Passing parameters between Verilog modules - parameter-passing

I fairly new to Verilog and learning the ropes. I have some code which generates an 8 bit up-counter (module counter.v), which is then called by a top module (top_module.v). There is a simulation test fixture (test_fixture.v) which calls the top module for testing.
I was trying to define the width of the counter using a parameter (parameter COUNTER_WIDTH) and was having difficulty doing so. A colleague fixed the code for me and it does now indeed work, but I want to understand a few things so I can understand what is actually going on.
Here is the code for the counter module:
module counter
#(parameter COUNTER_WIDTH = 8)
(
input wire CLK,
input wire RST,
input wire CE,
output reg[COUNTER_WIDTH-1:0] out = {COUNTER_WIDTH{1'b0}}
);
always #(posedge CLK) begin
if (RST == 1) begin
out <= {COUNTER_WIDTH{1'b0}};
end else begin
if (CE == 1) begin
out <= out + 1'b1;
end
end
end
endmodule
The top module:
module top_module
#(parameter COUNTER_WIDTH = 8)
(
input wire CLK,
input wire CE,
input wire RST,
output wire[COUNTER_WIDTH-1:0] out
);
counter #(
.COUNTER_WIDTH(COUNTER_WIDTH)
)
counter_inst(
.CLK(CLK),
.RST(RST),
.CE(CE),
.out(out)
);
endmodule
And the test fixture:
module test_fixture();
parameter COUNTER_WIDTH = 8;
// inputs
reg CLK = 0;
reg RST = 0;
reg CE = 0;
// outputs
wire [COUNTER_WIDTH-1:0] Q;
// instance of top module to be tested
top_module #(
.COUNTER_WIDTH(COUNTER_WIDTH)
)
test_inst(
.CLK(CLK),
.RST(RST),
.CE(CE),
.out(Q)
);
endmodule
I think I'm fine with the counter module, but have a question about what is going on in top module/test fixture:
It looks like the parameter COUNTER_WIDTH is declared in each module (#(parameter COUNTER_WIDTH = 8)), and then "connected to" (if that is the correct expression) the parameter declaration in the other module (e.g. #(.COUNTER_WIDTH(COUNTER_WIDTH) )
Is that understanding correct? If so, why do we have to declare the parameter within a module and connect it to a parameter within another module?
Thanks in advance for your help!

Think of a parameter as a special kind of constant input whose value is fixed at compile time. Originally, in Verilog, parameters were constants that could be overridden from outside a module (using the now deprecated defparam statement). So, a Verilog parameter had two roles:
a local constant
a way of customising a module from outside
Then, in the 2001 version of the standard (IEEE 1364-2001), the syntax you're using below was introduced (the so-called "ANSI style"). Also IEEE 1364-2001 introduced localparams (which fulfill the first of these two roles because they cannot be overridden from outside), so leaving parameters to handle the second of these two roles (the customisation). With the ANSI-style syntax, you override a parameter when you instantiate a module. You can associate the parameter with any static value, for example a parameter of the parent module, a localparam, a genvar or a literal (a hard-coded value in your code).
Because of this historical dual-role, in Verilog you must give a parameter a default value, even if it makes no sense. (And this restriction is lifted in SystemVerilog.)
Does giving the parameters different names and default values help your understanding?
// the default value
// |
module counter // V
#(parameter COUNTER_WIDTH = 1)
(
input wire CLK,
input wire RST,
input wire CE,
output reg[COUNTER_WIDTH-1:0] out = {COUNTER_WIDTH{1'b0}}
);
always #(posedge CLK) begin
if (RST == 1) begin
out <= {COUNTER_WIDTH{1'b0}};
end else begin
if (CE == 1) begin
out <= out + 1'b1;
end
end
end
endmodule
Then, in top module, let's give the parameter a different name:
// the default value
// |
module top_module // V
#(parameter COUNTER_NUM_BITS = 2)
(
input wire CLK,
input wire CE,
input wire RST,
output wire[COUNTER_NUM_BITS-1:0] out
);
counter #(
.COUNTER_WIDTH(COUNTER_NUM_BITS)
)
counter_inst(
.CLK(CLK),
.RST(RST),
.CE(CE),
.out(out)
);
endmodule
And again in the test fixture:
module test_fixture();
localparam COUNTER_SIZE = 8; // This is not overridden from outside, so using
// a localparam would be better here.
// (A localparam being a kind of parameter that
// cannot be overridden from outside. Normal
// languages would call it a constant.)
// inputs
reg CLK = 0;
reg RST = 0;
reg CE = 0;
// outputs
wire [COUNTER_SIZE-1:0] Q;
// instance of top module to be tested
top_module #(
.COUNTER_NUM_BITS(COUNTER_SIZE)
)
test_inst(
.CLK(CLK),
.RST(RST),
.CE(CE),
.out(Q)
);
endmodule

why do we have to declare the parameter within a module and connect it to a parameter within another module?
Because, you don't HAVE to give a parameter a value when you instance the module.
In which case the tools need to have at least some value to work with.
So where you do:
counter #(
.COUNTER_WIDTH(COUNTER_WIDTH)
)
counter_inst(
.CLK(CLK),
.RST(RST),
.CE(CE),
.out(out)
);
You may also use:
counter
counter_inst(
.CLK(CLK),
.RST(RST),
.CE(CE),
.out(out)
);
In which case the default value is used.

Related

Verilog, How to pass different parameters when I use generate to instantiation module?

I have a question about parameters passing. I used generate for to do module instantiation. But how to pass different parameters to each module?
For example:
generate
for (i=0;i<N;i=i+1) begin:ModIns
Mod #(.p1(?),.p2(?)) M (
// Signal connection
);
end
endgenerate
For N modules, each with different p1 and p2. How to do that? By the way, the number of parameters is very large, can I pass parameters as a file?
Thanks!
Here are my 2 cents.
Declare a 2-D register and store all the parameters there.
reg [31:0] param_mem1 [N-1:0]; //Assuming parameter size to be 32 bit wide
reg [31:0] param_mem2 [N-1:0];
always#(posedge clk)
begin
for(i=0;i<N;i=i+1)
begin
param_mem1[i] <= i; //Here replace 'i' with your actual parameter value
param_mem2[i] <= i+1; //Dummy assignment, please use intended values
end
end
generate
for (i=0;i<N;i=i+1) begin:ModIns
Mod #(.p1(param_mem1[i]),.p2(param_mem2[i])) M (
// Signal connection
);
end
endgenerate
First: No you can't read it from a file. Parameters have to be known at compile time and a file is only readable in run time.
You can derive them from a genvar or pass them through a hierarchy, but then it more or less stops. Maybe what you are trying to do can be solved in a different way but the scope of the problem you have outlined for us here is rater limited.
As always: Tell us your problem, not your solution.
It would be easier to do this in SystemVerilog because a parameter can be an array, and your generate loop could select an element for each iteration of the loop.
In Verilog, you can pack your elements into a bit-vector, and your generate loop could select a slice for each iteration of the loop.
parameter A1={8'd1, 8'd2, 8'd3, 8'd4, ...};
parameter A2={8'd9, 8'd8, 8'd7, 8'd6, ...};
generate
for (i=0;i<N;i=i+1) begin:ModIns
Mod #(.p1(A1[i*8+:8),.p2(A2[i*8+:8])) M (
// Signal connection
);
end
endgenerate
If you want to define the parameters from a file, you can put the parameter declarations in a separate file and `include the file.
This compiles with VCS:
genvar port_idx;
generate
for (port_idx = 0; port_idx < 5; port_idx++) begin : intf
xactor_t xactor (core_clk, core_rst);
defparam xactor.intf_id = 18 + port_idx;
end

Initializing ROM from array using functions, Synthesis ERROR (VHDL)

Ok, so I have a problem with a ROM initialization function.
Before I get into the problem let me explain a bit the nature of my problem and my code.
What I want to do is generate N number of ROMs which I have to use as an input for a module that runs a matching algorithm.
My problem is that I have a file with my signatures (let's say 64 in total) which I want to load in my different ROMs depending on how many I've generated (powers of 2 in my case, e.g. 8 roms of 8 signatures each).
I figured the best way to do it is load the whole text file into an array (using a function outside of the architecture body) which I will then use (again in a function) to load the data into a smaller array which will then be my ROM.
It seemed to me that the synthesizer would then just ignore the big array since I don't actually use it in my architecture.
Problem now is that since the second array input arguments are signal dependent, the synthesizer just ignores them and ties my array to zero (line 57).
Does anyone know how else if there's a way to make this architecture synthesize-able?
library ieee;
use ieee.std_logic_1164.all;
use IEEE.std_logic_signed.all;
use std.textio.all;
entity signatures_rom_partial is
generic(
data_width : integer := 160;
cycle_int : integer :=32;
rom_size : integer := 4
);
port ( clk : in std_logic;
reset : in std_logic;
readlne: in integer range 0 to cycle_int-1; -- user input for array data initialization
address: in integer range 0 to rom_size-1; -- address for data read
data: out std_logic_vector(data_width-1 downto 0) -- data output
);
end signatures_rom_partial;
architecture rom_arch of signatures_rom_partial is
type rom_type is array (0 to cycle_int-1) of bit_vector (data_width-1 downto 0); -- big array for all signatures, not used in arch
type test_type is array (0 to rom_size-1) of std_logic_vector (data_width-1 downto 0); -- smaller ROMs used in arch
--Read from file function--
----------------------------------------------------------------------------------------------------------
impure function InitRomFromFile (RomFileName : in string) return rom_type is --
file RomFile : text is in RomFileName; --
variable RomFileLine : line; --
variable rom : rom_type; --
--
begin --
for i in rom_type'range loop --
readline (RomFile, RomFileLine); --
read (RomFileLine, rom(i)); --
end loop; --
return rom; --
end function; --
----------------------------------------------------------------------------------------------------------
--Function for smaller ROM initialization--
----------------------------------------------------------------------------------------------------------
impure function initPartRom (rom : rom_type; readlne : integer) return test_type is --
variable test_array : test_type; --
--
begin --
for j in test_type'range loop --
test_array(j) := to_stdlogicvector(rom(j+readlne)); --
end loop; --
return test_array; --
end function; --
----------------------------------------------------------------------------------------------------------
constant rom : rom_type := InitRomFromFile("signatures_input.txt");
signal test_array : test_type := initPartRom(rom , readlne); --(LINE 57) SYNTHESIZER IGNORES THESE INPUT ARGUMENTS
begin
process(clk,reset)
begin
if reset='1' then
data<=(others=>'0');
elsif (clk'event and clk='1') then
data <= (test_array(address));
end if;
end process;
end rom_arch;
Synthesis is done using Xilinx ISE, simulation is done with Modelsim in which, my creation works fine :)
Thanks for any help!
With Xilinx ISE (14.7) it is possible to synthesize ROMs and RAMs even if the initial data is read from an external file by function.
The only requirement is, that the reading function must be computable at synthesis time. This is not true for your code because readlne is not static at the point the function is called. You should change it to a generic instead of an input and assign a different value to this generic for every other ROM instance. Then it should work as intended.
A sample implementation of how to read initialization data from a text file in (Xilinx) .mem format can be found in VHDL Library PoC in the namespace PoC.mem.ocrom or PoC.mem.ocram

Why isn't parameter being passed properly in Verilog?

I have two verlog modules as seen below. The parameter statement is supposed too allow me to pass the bus width i'd like to instantiate another module at.
I keep getting an error when trying to compile saying "Port expression 64 does not match expected width 1 or 2."
module LabL3;
parameter SIZE = 64;
reg [SIZE-1:0]a;
reg [SIZE-1:0]b;
reg c;
wire [SIZE-1:0]z;
integer i,j,k;
yMux #(SIZE) mux(z,a,b,c);
initial
begin
for(i=0;i<4;i=i+1)begin
for(j=0;j<4;j=j+1)begin
for(k=0;k<2;k=k+1)begin
a=i;b=j;c=k;
#1$display("a=%d b=%d c=%d z=%d",a,b,c,z);
end
end
end
end
endmodule
and the other file is:
module yMux(z,a,b,c);
parameter SIZE= 0;
output [SIZE-1:0]z;
input [SIZE-1:0]a,b;
input c;
yMux1 mux[SIZE-1:0](z,a,b,c);
endmodule
and lastly
module yMux1(z,a,b,c);
output z;
input a,b,c;
wire not_C, upper, lower;
not my_not(notC,c);
and upperAnd(upper,a,notC);
and lowerAnd(lower,c,b);
or my_or(z,upper,lower);
endmodule
and the command I am using is: iverilog LabL3.v yMux1.v yMux.v
I have tried the different syntax's for parameter passing. All give the same result.
Any hints would greatly be appreciated.
- Chris
You are using vectored instances:
yMux1 mux[SIZE-1:0](z,a,b,c);
Where you end up with SIZE number of yMux1 instances. This should connect z,a,b bitwise correctly and connect the single bit c to all yMux1 c ports via replication.
If you really want to drive all c ports to the same value I would try manually replicating the port with:
yMux1 mux[SIZE-1:0](z,a,b,{SIZE{c}});
Example on EDAPlayground looks fine to me. Could be an issue with the specific tool not supporting vectored instances correctly.
When possible I would recommend using named port connections (ANSI header style) from section 23.2.1 of the SystemVerilog IEEE 1800-2012 Standard.
This style is very clear as to your design intent, I find it much easier to read which relates to less bugs. It also allows easier refactoring of the code due to the named connections and not being order dependent.
module LabL3;
parameter SIZE = 64;
reg [SIZE-1:0] a;
reg [SIZE-1:0] b;
reg c;
wire [SIZE-1:0] z;
yMux #(
.SIZE(SIZE)
) mux (
.z(z),
.a(a),
.b(b),
.c(c)
);
yMux definiton:
module yMux #(
parameter SIZE= 0
) (
output [SIZE-1:0] z,
input [SIZE-1:0] a,
input [SIZE-1:0] b,
input c
);
// ...
endmodule
An example of the above code on EDAPlayground.

VHDL, using functions in for generate statement

VHDL, using functions in for generate statement
I have a component that should be instantiated about 8000 times, I used for-generate statement with the help of some constant values for reducing amount of code, but I had to declare a function for parametrization of component connections.
My function looks like this:
function dim1_calc (
cmp_index : integer;
prt_index : integer
) return integer is
variable updw : integer := 0;
variable shft_v : integer := 0;
variable result : integer := 0;
begin
if (cmp_index < max_up) then
updw := 1;
else
updw := 2;
end if;
case prt_index is
when 1 =>
shft_v := cnst_rom(updw)(1) + (i-1);
when 2 =>
shft_v := cnst_rom(updw)(2) + (i);
--
--
--
when 32 =>
shft_v := cnst_rom(updw)(32) + (i);
when others =>
shft_v := 0;
end case;
if (updw = 1) then
if (shft_v = min_up & ((prt_index mod 2) = 0)) then
result <= max_up;
elsif (shft_v = max_up & ((prt_index mod 2) = 1)) then
result <= min_up;
elsif (shft_v < max_up) then
result <= shft_v;
else
result <= shft_v - max_up;
end if;
else
--something like first condition statements...
--
--
end if;
return result;
end function;
and part of my code that uses this function plus some related part looks like this:
--these type definitions are in my package
type nx_bits_at is array (natural range <>) of std_logic_vector (bits-1 downto 0);
type mxn_bits_at is array (natural range <>) of nx_bits_at;
--
--
--
component pn_cmpn is
port(
clk : in std_logic;
bn_to_pn : in nx_bits_at(1 to row_wght);
pn_to_bn : out nx_bits_at(1 to row_wght)
);
end component;
--
--
--
signal v2c : mxn_bits_at(1 to bn_num)(1 to col_wght);
signal c2v : mxn_bits_at(1 to pn_num)(1 to row_wght);
--
--
--
gen_pn : for i in (1 to pn_num) generate
ins_pn : pn_cmpn port map (
clk => clk,
bn_to_pn(1) => b2p (dim1_calc(i, 1)) (dim2_calc(i, 1)),
bn_to_pn(2) => b2p (dim1_calc(i, 2)) (dim2_calc(i, 2)),
.
.
.
bn_to_pn(32) => b2p (dim1_calc(i, 32)) (dim2_calc(i, 32)),
pn_to_bn => p2b (i)
);
end generate;
I know that using too many sequential statements together is not appropriate in general, and I'm avoiding them as much as possible, but in this case I assumed that this function won't synthesize into some real hardware, and synthesizer just calculates the output value and will put it in corresponding instantiations of that component. Am I right? or this way of coding leads to extra hardware compared to just 8000 instantiations.
PS1: Initially I used "0 to..." for defining ranges of the 2nd and 3rd dimension of my arrays, but because of confusion that were made in dimension calculation function based on for-generate statement parameter, I replaced them with "1 to...". Is that an OK! coding style or should I avoid it?
PS2: Is there a way that port mapping part in above code combines into something like this:
(I know this is strongly wrong, it's just a clarification of what I want)
gen_pn : for i in (1 to pn_num) generate
ins_pn : pn_cmpn port map (
clk => clk,
gen_bn_to_pn : for j in (1 to 32) generate
bn_to_pn(j) => b2p (dim1_calc(i, j)) (dim2_calc(i, j)),
end generate;
pn_to_bn => p2b (i)
);
end generate;
Let me give another example
Assume that I have a component instantiation like this:
ins_test : test_comp port map (
clk => clk,
test_port(1) => test_sig(2)
test_port(2) => test_sig(3)
test_port(3) => test_sig(4)
);
Is there a way that I can use for generate here? something like:
ins_test : test_comp port map (
clk => clk,
gen_pn : for i in (1 to 3) generate
test_port(i) => test_sig(i+1)
end generate;
);
PS3: Is it possible to call a function inside another function in VHDL?
Functions are usable this way. If you encounter problems, I am sure they will regard details in the design or design tools, rather than the basic approach.
One potential issue is that the function refers to some external "things" such as max_up, i, cnst_rom whose declarations are not part of the function nor parameters to it. This makes it an "impure function" which - because it refers to external state or even modifies it - has restrictions on calling it (because the external state may change, results may depend on order of evaluation etc).
If you can make it pure, do so. I have a feeling that max_up, cnst_rom are constants : if they aren't used elsewhere, declare them local to the function. And i probably ought to be a parameter.
If this is not possible, make the external declarations constants, and preferably wrap them and the function together in a package.
This will just generate the values you need in a small, comprehensible, maintainable form, and not an infinite volume of hardware. I have used a complex nest of functions performing floating point arithmetic then fiddly range reduction and integer rounding to initialise a lookup table, so fundamentally the approach does work.
Potential pitfall:
Some design tools have trouble with perfectly valid VHDL, if its use is slightly unorthodox. Synplicity cannot synthesise some forms of function (which DO generate hardware) though has no trouble with the equivalent procedure returning the result through an OUT parameter!. XST is considerably better.
XST parsing my lookup table init has an absurd slowdown, quadratic in the number of function calls. But only if you are using the old VHDL parser (the default for Spartan-3). Spartan-6 uses the new parser and works fine ( under a second instead of half an hour!) as do Modelsim and Isim. (haven't tried Synplicity on that project)
Some tools object to unorthodox things in port maps : you may get away with function calls there; or you may have to workaround tool bugs by initialising constants with the calls, and using those constants in the port maps.
And your supplementary questions:
PS1) The correct coding style for an array range is ... whatever makes your intent clear.
If you find yourself mentally offsetting by 1 and getting confused or even making errors, STOP! and improve the design.
Some good array indexing styles:
type colour is (red, green, blue);
subtype brightness is natural range 0 to 255;
hue : array (colour) of brightness;
gamma : array (brightness) of brightness;
-- here 0 is a legitimate value
channel : array (1 to 99) of frequency;
PS2) I think you're asking if you can nest generate statements. Yes.
Details may be awkward and difficult, but yes.
PS3) Yes of course! You can even declare functions local to others; eliminating the possibility they will be accidentally called somewhere they make no sense. They (impure functions) can access the execution scope of the outer function (or process), simplifying parameter lists.
Q1 - in this case I assumed that this function won't synthesize into some ...
It depends on which synthesizer you're using. See this relevant question and comments below.
Q2 - PS1: Initially I used "0 to..." for defining ranges of the ...
Surely it's OK. And please allow we to post a suggestion on coding style here. (from this book)
When defining the loop parameter specification, either use a type (or subtype) definition, or use predefined object attributes (e.g., PredefinedObject'range, PredefinedObject'length - 1 downto 0). Avoid using discrete range (e.g., 1 to 4).
This rule makes the code more reusable and flexible for maintenance.
Q3 - PS2: Is there a way that port mapping part in above code combines into ...
I think this is why you asked the 4th question. So refer to the next answer:).
Q4 - Is it possible to call a function inside another function in VHDL?
Though I can't find some official reference to this, the answer is yes.
PS: Coding rules are defined by the synthesizer tools. So the best way to find an answer is to try it yourself.

How to deal with name/value pairs of function arguments in MATLAB

I have a function that takes optional arguments as name/value pairs.
function example(varargin)
% Lots of set up stuff
vargs = varargin;
nargs = length(vargs);
names = vargs(1:2:nargs);
values = vargs(2:2:nargs);
validnames = {'foo', 'bar', 'baz'};
for name = names
validatestring(name{:}, validnames);
end
% Do something ...
foo = strmatch('foo', names);
disp(values(foo))
end
example('foo', 1:10, 'bar', 'qwerty')
It seems that there is a lot of effort involved in extracting the appropriate values (and it still isn't particularly robust again badly specified inputs). Is there a better way of handling these name/value pairs? Are there any helper functions that come with MATLAB to assist?
I prefer using structures for my options. This gives you an easy way to store the options and an easy way to define them. Also, the whole thing becomes rather compact.
function example(varargin)
%# define defaults at the beginning of the code so that you do not need to
%# scroll way down in case you want to change something or if the help is
%# incomplete
options = struct('firstparameter',1,'secondparameter',magic(3));
%# read the acceptable names
optionNames = fieldnames(options);
%# count arguments
nArgs = length(varargin);
if round(nArgs/2)~=nArgs/2
error('EXAMPLE needs propertyName/propertyValue pairs')
end
for pair = reshape(varargin,2,[]) %# pair is {propName;propValue}
inpName = lower(pair{1}); %# make case insensitive
if any(strcmp(inpName,optionNames))
%# overwrite options. If you want you can test for the right class here
%# Also, if you find out that there is an option you keep getting wrong,
%# you can use "if strcmp(inpName,'problemOption'),testMore,end"-statements
options.(inpName) = pair{2};
else
error('%s is not a recognized parameter name',inpName)
end
end
InputParser helps with this. See Parse Function Inputs for more information.
I could yack for hours about this, but still don't have a good gestalt view of general Matlab signature handling. But here's a couple pieces of advice.
First, take a laissez faire approach to validating input types. Trust the caller. If you really want strong type testing, you want a static language like Java. Try to enforce type safety every where in Matlab, and you'll end up with a good part of your LOC and execution time devoted to run time type tests and coercion in userland, which trades in a lot of the power and development speed of Matlab. I learned this the hard way.
For API signatures (functions intended to be called from other functions, instead of from the command lines), consider using a single Args argument instead of varargin. Then it can be passed around between multiple arguments without having to convert it to and from a comma-separated list for varargin signatures. Structs, like Jonas says, are very convenient. There's also a nice isomorphism between structs and n-by-2 {name,value;...} cells, and you could set up a couple functions to convert between them inside your functions to whichever it wants to use internally.
function example(args)
%EXAMPLE
%
% Where args is a struct or {name,val;...} cell array
Whether you use inputParser or roll your own name/val parser like these other fine examples, package it up in a separate standard function that you'll call from the top of your functions that have name/val signatures. Have it accept the default value list in a data structure that's convenient to write out, and your arg-parsing calls will look sort of like function signature declarations, which helps readability, and avoid copy-and-paste boilerplate code.
Here's what the parsing calls could look like.
function out = my_example_function(varargin)
%MY_EXAMPLE_FUNCTION Example function
% No type handling
args = parsemyargs(varargin, {
'Stations' {'ORD','SFO','LGA'}
'Reading' 'Min Temp'
'FromDate' '1/1/2000'
'ToDate' today
'Units' 'deg. C'
});
fprintf('\nArgs:\n');
disp(args);
% With type handling
typed_args = parsemyargs(varargin, {
'Stations' {'ORD','SFO','LGA'} 'cellstr'
'Reading' 'Min Temp' []
'FromDate' '1/1/2000' 'datenum'
'ToDate' today 'datenum'
'Units' 'deg. C' []
});
fprintf('\nWith type handling:\n');
disp(typed_args);
% And now in your function body, you just reference stuff like
% args.Stations
% args.FromDate
And here's a function to implement the name/val parsing that way. You could hollow it out and replace it with inputParser, your own type conventions, etc. I think the n-by-2 cell convention makes for nicely readable source code; consider keeping that. Structs are typically more convenient to deal with in the receiving code, but the n-by-2 cells are more convenient to construct using expressions and literals. (Structs require the ",..." continuation at each line, and guarding cell values from expanding to nonscalar structs.)
function out = parsemyargs(args, defaults)
%PARSEMYARGS Arg parser helper
%
% out = parsemyargs(Args, Defaults)
%
% Parses name/value argument pairs.
%
% Args is what you pass your varargin in to. It may be
%
% ArgTypes is a list of argument names, default values, and optionally
% argument types for the inputs. It is an n-by-1, n-by-2 or n-by-3 cell in one
% of these forms forms:
% { Name; ... }
% { Name, DefaultValue; ... }
% { Name, DefaultValue, Type; ... }
% You may also pass a struct, which is converted to the first form, or a
% cell row vector containing name/value pairs as
% { Name,DefaultValue, Name,DefaultValue,... }
% Row vectors are only supported because it's unambiguous when the 2-d form
% has at most 3 columns. If there were more columns possible, I think you'd
% have to require the 2-d form because 4-element long vectors would be
% ambiguous as to whether they were on record, or two records with two
% columns omitted.
%
% Returns struct.
%
% This is slow - don't use name/value signatures functions that will called
% in tight loops.
args = structify(args);
defaults = parse_defaults(defaults);
% You could normalize case if you want to. I recommend you don't; it's a runtime cost
% and just one more potential source of inconsistency.
%[args,defaults] = normalize_case_somehow(args, defaults);
out = merge_args(args, defaults);
%%
function out = parse_defaults(x)
%PARSE_DEFAULTS Parse the default arg spec structure
%
% Returns n-by-3 cellrec in form {Name,DefaultValue,Type;...}.
if isstruct(x)
if ~isscalar(x)
error('struct defaults must be scalar');
end
x = [fieldnames(s) struct2cell(s)];
end
if ~iscell(x)
error('invalid defaults');
end
% Allow {name,val, name,val,...} row vectors
% Does not work for the general case of >3 columns in the 2-d form!
if size(x,1) == 1 && size(x,2) > 3
x = reshape(x, [numel(x)/2 2]);
end
% Fill in omitted columns
if size(x,2) < 2
x(:,2) = {[]}; % Make everything default to value []
end
if size(x,2) < 3
x(:,3) = {[]}; % No default type conversion
end
out = x;
%%
function out = structify(x)
%STRUCTIFY Convert a struct or name/value list or record list to struct
if isempty(x)
out = struct;
elseif iscell(x)
% Cells can be {name,val;...} or {name,val,...}
if (size(x,1) == 1) && size(x,2) > 2
% Reshape {name,val, name,val, ... } list to {name,val; ... }
x = reshape(x, [2 numel(x)/2]);
end
if size(x,2) ~= 2
error('Invalid args: cells must be n-by-2 {name,val;...} or vector {name,val,...} list');
end
% Convert {name,val, name,val, ...} list to struct
if ~iscellstr(x(:,1))
error('Invalid names in name/val argument list');
end
% Little trick for building structs from name/vals
% This protects cellstr arguments from expanding into nonscalar structs
x(:,2) = num2cell(x(:,2));
x = x';
x = x(:);
out = struct(x{:});
elseif isstruct(x)
if ~isscalar(x)
error('struct args must be scalar');
end
out = x;
end
%%
function out = merge_args(args, defaults)
out = structify(defaults(:,[1 2]));
% Apply user arguments
% You could normalize case if you wanted, but I avoid it because it's a
% runtime cost and one more chance for inconsistency.
names = fieldnames(args);
for i = 1:numel(names)
out.(names{i}) = args.(names{i});
end
% Check and convert types
for i = 1:size(defaults,1)
[name,defaultVal,type] = defaults{i,:};
if ~isempty(type)
out.(name) = needa(type, out.(name), type);
end
end
%%
function out = needa(type, value, name)
%NEEDA Check that a value is of a given type, and convert if needed
%
% out = needa(type, value)
% HACK to support common 'pseudotypes' that aren't real Matlab types
switch type
case 'cellstr'
isThatType = iscellstr(value);
case 'datenum'
isThatType = isnumeric(value);
otherwise
isThatType = isa(value, type);
end
if isThatType
out = value;
else
% Here you can auto-convert if you're feeling brave. Assumes that the
% conversion constructor form of all type names works.
% Unfortunately this ends up with bad results if you try converting
% between string and number (you get Unicode encoding/decoding). Use
% at your discretion.
% If you don't want to try autoconverting, just throw an error instead,
% with:
% error('Argument %s must be a %s; got a %s', name, type, class(value));
try
out = feval(type, value);
catch err
error('Failed converting argument %s from %s to %s: %s',...
name, class(value), type, err.message);
end
end
It is so unfortunate that strings and datenums are not first-class types in Matlab.
MathWorks has revived this beaten horse, but with very useful functionality that answers this need, directly. It's called Function Argument Validation (a phrase one can and should search for in the documentation) and comes with release R2019b+. MathWorks created a video about it, also. Validation works much like the "tricks" people have come up with over the years. Here is an example:
function ret = example( inputDir, proj, options )
%EXAMPLE An example.
% Do it like this.
% See THEOTHEREXAMPLE.
arguments
inputDir (1, :) char
proj (1, 1) projector
options.foo char {mustBeMember(options.foo, {'bar' 'baz'})} = 'bar'
options.Angle (1, 1) {double, integer} = 45
options.Plot (1, 1) logical = false
end
% Code always follows 'arguments' block.
ret = [];
switch options.foo
case 'bar'
ret = sind(options.Angle);
case 'baz'
ret = cosd(options.Angle);
end
if options.Plot
plot(proj.x, proj.y)
end
end
Here's the unpacking:
The arguments block must come before any code (OK after help block) and must follow the positional order defined in the function definition, and I believe every argument requires a mention. Required arguments go first, followed by optional arguments, followed by name-value pairs. MathWorks also recommends to no longer use the varargin keyword, but nargin and nargout are still useful.
Class requirements can be custom classes, such as projector, in this case.
Required arguments may not have a default value (i.e. they are known because they don't have a default value).
Optional arguments must have a default value (i.e. they are known because they have a default value).
Default values must be able to pass the same argument validation. In other words, a default value of zeros(3) won't work as a default value for an argument that's supposed to be a character vector.
Name-value pairs are stored in an argument that are internally converted to a struct, which I'm calling options, here (hinting to us that we can use structs to pass keyword arguments, like kwargs in Python).
Very nicely, name-value arguments will now show up as argument hints when you hit tab in a function call. (If completion hints interest you, I encourage you to also look up MATLAB's functionSignatures.json functionality).
So in the example, inputDir is a required argument because it's given no default value. It also must be a 1xN character vector. As if to contradict that statement, note that MATLAB will try to convert the supplied argument to see if the converted argument passes. If you pass 97:122 as inputDir, for example, it will pass and inputDir == char(97:122) (i.e. inputDir == 'abcdefghijklmnopqrstuvwxyz'). Conversely, zeros(3) won't work on account of its not being a vector. And forget about making strings fail when you specify characters, making doubles fail when you demand uint8, etc. Those will be converted. You'd need to dig deeper to circumvent this "flexibility."
Moving on, 'foo' specifies a name-value pair whose value may be only 'bar' or 'baz'.
MATLAB has a number of mustBe... validation functions (start typing
mustBe and hit tab to see what's available), and it's easy enough to
create your own. If you create your own, the validation function must
give an error if the input doesn't match, unlike, say, uigetdir,
which returns 0 if the user cancels the dialog. Personally, I
follow MATLAB's convention and call my validation functions
mustBe..., so I have functions like mustBeNatural for natural
numbers, and mustBeFile to ensure I passed a file that actually
exists.
'Angle' specifies a name-value pair whose value must be a scalar double or integer, so, for example, example(pwd, 'foo', 'baz', 'Angle', [30 70]) won't work since you passed a vector for the Angle argument.
You get the idea. There is a lot of flexibility with the arguments block -- too much and too little, I think -- but for simple functions, it's fast and easy. You still might rely on one or more of inputParser, validateattributes, assert, and so on for addressing greater validation complexity, but I always try to stuff things into an arguments block, first. If it's becoming unsightly, maybe I'll do an arguments block and some assertions, etc.
Personally I use a custom function derived from a private method used by many Statistics Toolbox functions (like kmeans, pca, svmtrain, ttest2, ...)
Being an internal utility function, it changed and was renamed many times over the releases. Depending on your MATLAB version, try looking for one of the following files:
%# old versions
which -all statgetargs
which -all internal.stats.getargs
which -all internal.stats.parseArgs
%# current one, as of R2014a
which -all statslib.internal.parseArgs
As with any undocumented function, there are no guarantees and it could be removed from MATLAB in subsequent releases without any notice... Anyways, I believe someone posted an old version of it as getargs on the File Exchange..
The function processes parameters as name/value pairs, using a set of valid parameter names along with their default values. It returns the parsed parameters as separate output variables. By default, unrecognized name/value pairs raise an error, but we could also silently capture them in an extra output. Here is the function description:
$MATLABROOT\toolbox\stats\stats\+internal\+stats\parseArgs.m
function varargout = parseArgs(pnames, dflts, varargin)
%
% [A,B,...] = parseArgs(PNAMES, DFLTS, 'NAME1',VAL1, 'NAME2',VAL2, ...)
% PNAMES : cell array of N valid parameter names.
% DFLTS : cell array of N default values for these parameters.
% varargin : Remaining arguments as name/value pairs to be parsed.
% [A,B,...]: N outputs assigned in the same order as the names in PNAMES.
%
% [A,B,...,SETFLAG] = parseArgs(...)
% SETFLAG : structure of N fields for each parameter, indicates whether
% the value was parsed from input, or taken from the defaults.
%
% [A,B,...,SETFLAG,EXTRA] = parseArgs(...)
% EXTRA : cell array containing name/value parameters pairs not
% specified in PNAMES.
Example:
function my_plot(x, varargin)
%# valid parameters, and their default values
pnames = {'Color', 'LineWidth', 'LineStyle', 'Title'};
dflts = { 'r', 2, '--', []};
%# parse function arguments
[clr,lw,ls,txt] = internal.stats.parseArgs(pnames, dflts, varargin{:});
%# use the processed values: clr, lw, ls, txt
%# corresponding to the specified parameters
%# ...
end
Now this example function could be called as any of the following ways:
>> my_plot(data) %# use the defaults
>> my_plot(data, 'linestyle','-', 'Color','b') %# any order, case insensitive
>> my_plot(data, 'Col',[0.5 0.5 0.5]) %# partial name match
Here are some invalid calls and the errors thrown:
%# unrecognized parameter
>> my_plot(x, 'width',0)
Error using [...]
Invalid parameter name: width.
%# bad parameter
>> my_plot(x, 1,2)
Error using [...]
Parameter name must be text.
%# wrong number of arguments
>> my_plot(x, 'invalid')
Error using [...]
Wrong number of arguments.
%# ambiguous partial match
>> my_plot(x, 'line','-')
Error using [...]
Ambiguous parameter name: line.
inputParser:
As others have mentioned, the officially recommended approach to parsing functions inputs is to use inputParser class. It supports various schemes such as specifying required inputs, optional positional arguments, and name/value parameters. It also allows to perform validation on the inputs (such as checking the class/type and the size/shape of the arguments)
Read Loren's informative post on this issue. Don't forget to read the comments section... - You will see that there are quite a few different approaches to this topic. They all work, so selecting a prefered method is really a matter of personal taste and maintainability.
I'm a bigger fan of home-grown boiler plate code like this:
function TestExample(req1, req2, varargin)
for i = 1:2:length(varargin)
if strcmpi(varargin{i}, 'alphabet')
ALPHA = varargin{i+1};
elseif strcmpi(varargin{i}, 'cutoff')
CUTOFF = varargin{i+1};
%we need to remove these so seqlogo doesn't get confused
rm_inds = [rm_inds i, i+1]; %#ok<*AGROW>
elseif strcmpi(varargin{i}, 'colors')
colors = varargin{i+1};
rm_inds = [rm_inds i, i+1];
elseif strcmpi(varargin{i}, 'axes_handle')
handle = varargin{i+1};
rm_inds = [rm_inds i, i+1];
elseif strcmpi(varargin{i}, 'top-n')
TOPN = varargin{i+1};
rm_inds = [rm_inds i, i+1];
elseif strcmpi(varargin{i}, 'inds')
npos = varargin{i+1};
rm_inds = [rm_inds i, i+1];
elseif strcmpi(varargin{i}, 'letterfile')
LETTERFILE = varargin{i+1};
rm_inds = [rm_inds i, i+1];
elseif strcmpi(varargin{i}, 'letterstruct')
lo = varargin{i+1};
rm_inds = [rm_inds i, i+1];
end
end
This way I can simulate the 'option', value pair that's nearly identical to how most Matlab functions take their arguments.
Hope that helps,
Will
Here's the solution I'm trialling, based upon Jonas' idea.
function argStruct = NameValuePairToStruct(defaults, varargin)
%NAMEVALUEPAIRTOSTRUCT Converts name/value pairs to a struct.
%
% ARGSTRUCT = NAMEVALUEPAIRTOSTRUCT(DEFAULTS, VARARGIN) converts
% name/value pairs to a struct, with defaults. The function expects an
% even number of arguments to VARARGIN, alternating NAME then VALUE.
% (Each NAME should be a valid variable name.)
%
% Examples:
%
% No defaults
% NameValuePairToStruct(struct, ...
% 'foo', 123, ...
% 'bar', 'qwerty', ...
% 'baz', magic(3))
%
% With defaults
% NameValuePairToStruct( ...
% struct('bar', 'dvorak', 'quux', eye(3)), ...
% 'foo', 123, ...
% 'bar', 'qwerty', ...
% 'baz', magic(3))
%
% See also: inputParser
nArgs = length(varargin);
if rem(nArgs, 2) ~= 0
error('NameValuePairToStruct:NotNameValuePairs', ...
'Inputs were not name/value pairs');
end
argStruct = defaults;
for i = 1:2:nArgs
name = varargin{i};
if ~isvarname(name)
error('NameValuePairToStruct:InvalidName', ...
'A variable name was not valid');
end
argStruct = setfield(argStruct, name, varargin{i + 1}); %#ok<SFLD>
end
end
Inspired by Jonas' answer, but more compact:
function example(varargin)
defaults = struct('A',1, 'B',magic(3)); %define default values
params = struct(varargin{:});
for f = fieldnames(defaults)',
if ~isfield(params, f{1}),
params.(f{1}) = defaults.(f{1});
end
end
%now just access them as params.A, params.B
There is a nifty function called parsepvpairs that takes care of this nicely, provided you have access to MATLAB's finance toolbox. It takes three arguments, expected field names, default field values, and the actual arguments received.
For example, here's a function that creates an HTML figure in MATLAB and can take the optional field value pairs named 'url', 'html', and 'title'.
function htmldlg(varargin)
names = {'url','html','title'};
defaults = {[],[],'Padaco Help'};
[url, html,titleStr] = parsepvpairs(names,defaults,varargin{:});
%... code to create figure using the parsed input values
end
Since ages I am using process_options.m. It is stable, easy to use and has been included in various matlab frameworks. Don't know anything about performance though – might be that there are faster implementations.
Feature I like most with process_options is the unused_args return value, that can be used to split input args in groups of args for, e.g., subprocesses.
And you can easily define default values.
Most importantly: using process_options.m usually results in readable and maintainable option definitions.
Example code:
function y = func(x, y, varargin)
[u, v] = process_options(varargin,
'u', 0,
'v', 1);
If you are using MATLAB 2019b or later, the best way to deal with name-value pairs in your function is to use "Declare function argument validation".
function result = myFunction(NameValueArgs)
arguments
NameValueArgs.Name1
NameValueArgs.Name2
end
% Function code
result = NameValueArgs.Name1 * NameValueArgs.Name2;
end
see: https://www.mathworks.com/help/matlab/ref/arguments.html
function argtest(varargin)
a = 1;
for ii=1:length(varargin)/2
[~] = evalc([varargin{2*ii-1} '=''' num2str(varargin{2*ii}) '''']);
end;
disp(a);
who
This does of course not check for correct assignments, but it's simple and any useless variable will be ignored anyway. It also only works for numerics, strings and arrays, but not for matrices, cells or structures.
I ended up writing this today, and then found these mentions.
Mine uses struct's and struct 'overlays' for options. It essentially mirrors the functionality of setstructfields() except that new parameters can not be added. It also has an option for recursing, whereas setstructfields() does it automatically.
It can take in a cell array of paired values by calling struct(args{:}).
% Overlay default fields with input fields
% Good for option management
% Arguments
% $opts - Default options
% $optsIn - Input options
% Can be struct(), cell of {name, value, ...}, or empty []
% $recurseStructs - Applies optOverlay to any existing structs, given new
% value is a struct too and both are 1x1 structs
% Output
% $opts - Outputs with optsIn values overlayed
function [opts] = optOverlay(opts, optsIn, recurseStructs)
if nargin < 3
recurseStructs = false;
end
isValid = #(o) isstruct(o) && length(o) == 1;
assert(isValid(opts), 'Existing options cannot be cell array');
assert(isValid(optsIn), 'Input options cannot be cell array');
if ~isempty(optsIn)
if iscell(optsIn)
optsIn = struct(optsIn{:});
end
assert(isstruct(optsIn));
fields = fieldnames(optsIn);
for i = 1:length(fields)
field = fields{i};
assert(isfield(opts, field), 'Field does not exist: %s', field);
newValue = optsIn.(field);
% Apply recursion
if recurseStructs
curValue = opts.(field);
% Both values must be proper option structs
if isValid(curValue) && isValid(newValue)
newValue = optOverlay(curValue, newValue, true);
end
end
opts.(field) = newValue;
end
end
end
I'd say that using the naming convention 'defaults' and 'new' would probably be better :P
I have made a function based on Jonas and Richie Cotton. It implements both functionalities (flexible arguments or restricted, meaning that only variables existing in the defaults are allowed), and a few other things like syntactic sugar and sanity checks.
function argStruct = getnargs(varargin, defaults, restrict_flag)
%GETNARGS Converts name/value pairs to a struct (this allows to process named optional arguments).
%
% ARGSTRUCT = GETNARGS(VARARGIN, DEFAULTS, restrict_flag) converts
% name/value pairs to a struct, with defaults. The function expects an
% even number of arguments in VARARGIN, alternating NAME then VALUE.
% (Each NAME should be a valid variable name and is case sensitive.)
% Also VARARGIN should be a cell, and defaults should be a struct().
% Optionally: you can set restrict_flag to true if you want that only arguments names specified in defaults be allowed. Also, if restrict_flag = 2, arguments that aren't in the defaults will just be ignored.
% After calling this function, you can access your arguments using: argstruct.your_argument_name
%
% Examples:
%
% No defaults
% getnargs( {'foo', 123, 'bar', 'qwerty'} )
%
% With defaults
% getnargs( {'foo', 123, 'bar', 'qwerty'} , ...
% struct('foo', 987, 'bar', magic(3)) )
%
% See also: inputParser
%
% Authors: Jonas, Richie Cotton and LRQ3000
%
% Extract the arguments if it's inside a sub-struct (happens on Octave), because anyway it's impossible that the number of argument be 1 (you need at least a couple, thus two)
if (numel(varargin) == 1)
varargin = varargin{:};
end
% Sanity check: we need a multiple of couples, if we get an odd number of arguments then that's wrong (probably missing a value somewhere)
nArgs = length(varargin);
if rem(nArgs, 2) ~= 0
error('NameValuePairToStruct:NotNameValuePairs', ...
'Inputs were not name/value pairs');
end
% Sanity check: if defaults is not supplied, it's by default an empty struct
if ~exist('defaults', 'var')
defaults = struct;
end
if ~exist('restrict_flag', 'var')
restrict_flag = false;
end
% Syntactic sugar: if defaults is also a cell instead of a struct, we convert it on-the-fly
if iscell(defaults)
defaults = struct(defaults{:});
end
optionNames = fieldnames(defaults); % extract all default arguments names (useful for restrict_flag)
argStruct = defaults; % copy over the defaults: by default, all arguments will have the default value.After we will simply overwrite the defaults with the user specified values.
for i = 1:2:nArgs % iterate over couples of argument/value
varname = varargin{i}; % make case insensitive
% check that the supplied name is a valid variable identifier (it does not check if the variable is allowed/declared in defaults, just that it's a possible variable name!)
if ~isvarname(varname)
error('NameValuePairToStruct:InvalidName', ...
'A variable name was not valid: %s position %i', varname, i);
% if options are restricted, check that the argument's name exists in the supplied defaults, else we throw an error. With this we can allow only a restricted range of arguments by specifying in the defaults.
elseif restrict_flag && ~isempty(defaults) && ~any(strmatch(varname, optionNames))
if restrict_flag ~= 2 % restrict_flag = 2 means that we just ignore this argument, else we show an error
error('%s is not a recognized argument name', varname);
end
% else alright, we replace the default value for this argument with the user supplied one (or we create the variable if it wasn't in the defaults and there's no restrict_flag)
else
argStruct = setfield(argStruct, varname, varargin{i + 1}); %#ok<SFLD>
end
end
end
Also available as a Gist.
And for those interested in having real named arguments (with a syntax similar to Python, eg: myfunction(a=1, b='qwerty'), use InputParser (only for Matlab, Octave users will have to wait until v4.2 at least or you can try a wrapper called InputParser2).
Also as a bonus, if you don't want to always have to type argstruct.yourvar but directly use yourvar, you can use the following snippet by Jason S:
function varspull(s)
% Import variables in a structures into the local namespace/workspace
% eg: s = struct('foo', 1, 'bar', 'qwerty'); varspull(s); disp(foo); disp(bar);
% Will print: 1 and qwerty
%
%
% Author: Jason S
%
for n = fieldnames(s)'
name = n{1};
value = s.(name);
assignin('caller',name,value);
end
end