I have a list of structs, the struct has a field which defines it's type (assume it's name).
I would to have a macro as follows:
MYKEEP <name>.<field> <ANY KEEP>;
which would be translated to:
keep value(mylist.has(it.name == <name>)) => mylist.first(it.name == <name>).<field> <ANY KEEP>
Is it possible to do it without an "as computed" macro?
it looks like you want to get a list of structs as an input, check the value of some of the
struct's fields, and then assign a constant value to a different struct field
according to that value.
taking performance into account,this kind of 'Injective' relationship between the two fields should
be in proceedural code rather than generative. (most likely in post_generate()).
consider using a define as macro that looks like this:
define <name_induced_field'struct_member> "MYKEEP <name'exp> <field'exp> <ANY_KEEP'exp>" as{
post_generate() is also{
for each in l{
if (it.t==<name'exp>){
it.<field'exp> = <ANY_KEEP'exp>;
};
};
};
};
and then use it in the code like so:
type mytype: [AA,BB];
struct s {
t:mytype;
!i:int;
};
extend sys{
MYKEEP AA i 1;
MYKEEP BB i 2;
l:list of s;
keep l.size()==5;
};
note: if the struct field has the same relationship to it's name in other cases ,consider
maybe constraining the field from within the struct, for example:
define <name_induced_field'struct_member> "MYKEEP <name'exp> <field'exp> <ANY_KEEP'exp>" as{
keep value(t==<name'exp>) => (<field'exp>==<ANY_KEEP'exp>);
};
type mytype: [AA,BB];
struct s {
MYKEEP AA i 1;
MYKEEP BB i 2;
t:mytype;
i:int;
post_generate() is also{
print me;
};
};
proceedural code doesn't help me, because these fields may effect others in generation time.
I manged to find a macro that seems to work:
define <ana_packet_gen_con_keep1'exp> "KEEP_CON [(<WORD>soft) ]<type'exp>\.<field'any> <exp>" as {
keep for each (con) in it.containers {
<WORD> (con.con_type==<type'exp>) => con.as_a(<type'exp>'con_type ana_container).<field'any> <exp>;
};
};
Does having several "keep for each" effect the performance too much?
Related
To explain my problem I posted an example below. The code in this form is not tested so there might be some syntax mistake in it. As I have to work with a lot of registers in an integrated circuit with their addresses which can be remapped, it would be very useful to create structures like that below. Is there some trick to create these structures? As this example does not work the way I want it because foo requires a Country object and Country::Europe::Italy is invalid as parameter.
// I want to create a structure like this
class myClass {
public:
class Country {
enum class Europe {
England,
France,
Germany,
Italy
};
enum class Asia {
China,
Japan
};
};
// Here I want to make sure, that the method is only
// called with a Country element and e.g. Italy should
// behave like a Country object. Actually it should behave
// as if it is derived from Country.
int foo(Country c);
};
int main() {
myClass myC();
// Exemplary call of the method foo
myC.foo(myClass::Country::Europe::Italy);
}
You cannot use enum class to achieve your goal. However, you can use a namespace with a set of hardcoded constexpr objects:
struct Country
{
int _id;
};
namespace Countries
{
namespace Europe
{
constexpr Country Italy{0};
constexpr Country France{1};
};
};
Usage:
myC.foo(Countries::Europe::Italy);
A proper example using registers and a better explanation would have been better. I guess you want to remap from one register name to another. A suggestion:
class Register {
public:
enum class UserName {
REG_IO0,
REG_MEM1
};
enum class CPUName {
REG_INT0,
REG_INT1
};
void setMapping(UserName from, CPUName to); // store the mapping
CPUName getMapping(UserName name) const; // retrieve the mapping
private:
std::map<UserName, CPUName> m_registerMap;
};
If you want you could implement get/set methods for the registers in that class if you store the indexes/adresses of the registers. Either use templates or overload them for different data types.
You can explicitly use an enum type as a function or constructor argument, restricting the caller to using that enumeration.
The thing you can't trivially do is combine multiple enum definitions in the way that you have suggested.
You could write several constructors, one for each of the enums Europe, Asia, etc, but that would be work, especially if you have a number of functions that need to take these enums as arguments.
--OR--
You could define one big enum, and define fixed value separators for each subgroup, so you can compare the enum value against these guard values to identify the subgroup. You lose the sub-grouping if you do that. You could use c++11 constant enum initialisers to construct enum value members in subclasses for each continent - but note these are only available for enum class from c++17 (so I am using a nested class trick to provide the member namespace enforcement - in c++17 you could have enum class Location - you can write this in c++11 but you can't then do the const initialisers). The values follow the above rule of separators, but callers have to indirect through the subclasses to get the names.
class Country
{
class Location {
enum Value {
None =0,
Europe = 0x0100,
Asia = 0x0200,
//etc
};
};
struct Asia {
const Location::Value Japan { Location::Asia + 1 };
//etc
};
struct Europe {
const Location::Value UnitedKingdom { Location::Europe + 1 };
//etc
};
// etc
};
Then you could have
class myClass {
public:
myClass(Country::Location::Value v);
};
And call it with
myClass instance(Country::Asia::Japan);
-- OR --
You could define another structure who's only purpose is to take the various enumerations and convert them to a pair of values for the continent and country index. You could then use that structure as your function parameter, and allow auto-conversion from that structure. This means you only do the conversion once, and callers to your code are not impacted. You could use the guard ranges such that you don't need to explicitly store the continent code, just the raw country number would be unique across all your enums.
in my verification environment we work with vr_ad UVM package, where there is a general struct for a register vr_ad_reg which has been extended with different type for every register in the environment, etc:
reg_def TIMER_LOAD_0 TIMER 20'h00010 {
reg_fld timer_load : uint : RW : 0xffff;
}:
The vr_ad_reg has predefined function post_access(), which I would like to extend for every register type that starts with the word 'TIMER'. Is there a way to do it? For example:
extend TIMER_* vr_ad_reg { //The intention here to extend the vr_ad_reg for all types that starts with the word TIMER
post_access() is also {
var some_var : uint;
};
}
Thank you for your help
There's no built in construct to extend multiple sub-types. What you can do however is use a macro based solution. Team Specman had a blog post on this topic: http://www.cadence.com/Community/blogs/fv/archive/2009/10/20/extending-multiple-when-subtypes-simultaneously.aspx
They created a define as computed macro that takes multiple sub-types and extends those:
define <multi_when'statement> "extend \[<detr'name>,...\] <base'type> (<MEMBERS {<struct_member>;...})" as computed {
for each in <detr'names> do {
result = appendf("%s extend %s %s %s;",result,it,<base'type>,<MEMBERS>);
};
};
You can then use like so:
extend [ TIMER_LOAD_0, TIMER_LOAD_1, TIMER_LOAD_2 ] vr_ad_reg {
post_access() is also {
// ...
};
};
If you have a lot of registers that match your expression or you don't know the exact name beforehand, you might want to consider using a run-time solution:
extend vr_reg {
post_access() is also {
var some_var: uint;
if str_match(kind.as_a(string), "/^TIMER_*/") {
... // do stuff for the TIMER_* registers
};
};
};
I am trying to constrain my list items to be equal to certain values under certain conditions.
For that I have devised a define as computed macro that
define <num_prob_constraints'struct_member> "CHECK_and_SET_CONSTRAINTS <lst'exp>" as computed {
//var cur : list of uint = <lst'exp>.as_a(list of uint);
var t : uint = <lst'exp>.as_a(list of uint).size();
print t;
for i from 1 to 4 {
result = append(result,"keep ",<lst'exp>,"[",i,"]==",i,"=> ",<lst'exp>,"[",i,"]==389; \n");
};
};
and in my code I use this macro like this:
struct schedule{
n : uint;
sched_w : list of list of int;
CHECK_and_SET_CONSTRAINTS sched_w;
};
But this does not work. First, it prints some random size (From the macro) instead of the list’s real size.
Secondly, I get errors of this sort:
*** Error: '1' is of type 'int', while expecting type 'list of int'.
in code generated by macro defined at line 3 in
sports_sched_macro.e
keep sched_w[1]==1=> sched_w[1]==389;
expanded at line 8 in sports_sched.e
CHECK_and_SET_CONSTRAINTS sched_w;
Any ideas on what is wrong here?
Macros are simply code substituts. Their function is simply to replace some string with another (calculated or not) during the parsing phase.
This means that the macro will be deployed where you used it in the parsing phase which precedes the generation phase. So, in fact, the list does not exist yet, and you cannot access it’s size and items.
More specifically, your macro is deployed this way:
struct schedule {
n : uint;
sched_w : list of list of int;
keep sched_w[1]==2=> sched_w[1]==389;
keep sched_w[2]==2=> sched_w[2]==389;
...
...
};
The error message you received tell you that you cannot access specific list items explicitly (since the list size and item’s values are yet undetermined).
If you want to keep your list with size 4, and if the value is 2 you want to replace it with 389, you may need to use the post_generate() method, as you are trying to access values that are already assigned to the list items:
keep sched_w.size()==4;
post_generate() is also{
for each in sched_w {
if (it==2) {it=389};
};
};
Are you sure you want to constrain a 2-dimensional list? This looks a bit different. E.g. for an array schedule[4][1]:
schedule: list of list of int;
keep schedule.size() == 4;
keep for each (sublist) in schedule {
sublist.size() == 1;
for each (elem) in sublist {
...
};
};
I want program a struct in Matlab for saving some parameters.
The struct's name has to change every iteration in a loop, thus in each iteration I make a new struct. Therefore I want something like this:
index={'01','02','03'};
letter={'aa','bb','cc'};
names={'Peter','John','Michael'};
for(i=1:numel(index)){
......
strcat(str, index{i}, letter{i})(i).name = names{i};
}
Then, when the loop has finished I have 3 structs with the next names:
- str01aa{
name = 'Peter'
}
- str02bb{
name = 'John'
}
- str03cc{
name = 'Michael'
}
My problem is that the strcat function with the bracket (i) is not good defined, and the structs are not created.
I hope you can help me.
Thanks.
strcat(str, index{i}, letter{i})(i).name isn't a valid operation, because strcat returns a sting object, which can't possess fields. You need to make that string into a variable name using genvarname (documentation), like so:
index={'01','02','03'};
letter={'aa','bb','cc'};
names={'Peter','John','Michael'};
for(i = 1:numel(index))
{
......
genvarname(strcat('str', index{i}, letter{i}))(i).name = names{i};
}
Note that I changed str to 'str' for consistency with your example. As a general rule, dynamically constructed variable names are bad practice because they make debugging a nightmare.
Let me make a suggestion; instead of having a bunch of structs with different, seemingly arbitrary names, why not try something like this:
index={'01','02','03'};
letter={'aa','bb','cc'};
names={'Peter','John','Michael'};
for(i = 1:numel(index))
{
......
yourStruct(i).id = strcat('str', index{i}, letter{i});
yourStruct(i).name = names{i};
}
Either way, good luck!
Is there a way I could extend the given pseudo methods for lists in e, to add some specific implementation?
Thanks
"pseudo method" is not really a method, it just looks as if it was. So it cannot be extended with "is also/only/etc".
but you can define any "pseudo method" of your own, using macro.
for example - pseudo method that adds only even items -
(do note the \ before the () )
define <my_pseudo_method'action> "<input1'exp>.add_if_even\(<input2'num>\)"
as computed {
result = append("if ", <input2'num>, " %2 == 0 then { ", <input1'exp>, ".add(", <input2'num>, ")};");
}
then can be called from another file -
extend sys {
run() is also {
var my_list : list of int;
for i from 0 to 10 {
my_list.add_if_even(i);
};
print my_list;
};
};
Using a macro, you can even "override" an existing pseudo-method. For example, let's say you want to modify add() so that it will add an element to the list only if it is not already in the list. (In other words, you want to keep all elements in the list unique).
You can do something like this:
define <my_add'action> "<list'exp>.add\(<exp>\)" as {
if not <list'exp>.has(it == <exp>) then {
var new_size<?>: int = <list'exp>.size() + 1;
<list'exp>.resize(new_size<?>, TRUE, <exp>, TRUE);
};
};
Note that I use another pseudo-method here - resize() - to implement the actual addition of the new element to the list. If I tried to use the add() pseudo-method itself, it wouldn't work, and would lead to an infinite recursion. This is because add() used inside the macro would again call the macro itself, and not the pre-defined pseudo-method being overridden.
You can also use templates to add/modify list pseudo-methods. e.g.
<'
template struct MyList of (<T1'type>) {
items: list of <T1'type>;
keep soft items.size()==10;
pop_index(i:int):<T1'type> is {
result = items[i];
items.delete(i);
};
};
extend sys {
list1: MyList of (byte);
// somehwere
var foo:= list1.pop_index(3);
};
'>