Sequence that writes to either one of two different registers, but with the same fields - verification

I'm working on an old environment, that is not UVM compatible, but uses the vr_ad_reg.
One of the issues with this old environment is that instead of instantiating a regfile twice for one of the modules (which in RTL is indeed instantiated twice), there is a double definition for the entire regfile and the registers in it.
For instance, I have two regfiles: "GAD" and "GAD_RX", and they both have a register defined like this:
reg_def GAD_SEQ GAD 20'h00010 {
reg_fld s_event : uint (bits : 7) : RW : 0x0;
reg_fld smpl_en : bit : RW : 0x0;
reg_fld int_en : bit : RW : 0x0;
reg_fld dma_req : bit : RW : 0x0;
reg_fld smpl_tag : uint (bits : 2) : RW : 0x0;
reg_fld ch_tag : uint (bits : 4) : RW : 0x0;
reg_fld smpl_point : uint (bits : 16) : RW : 0x0;
};
reg_def GAD_RX_SEQ GAD_RX 20'h00010 {
reg_fld s_event : uint (bits : 7) : RW : 0x0;
reg_fld smpl_en : bit : RW : 0x0;
reg_fld int_en : bit : RW : 0x0;
reg_fld dma_req : bit : RW : 0x0;
reg_fld smpl_tag : uint (bits : 2) : RW : 0x0;
reg_fld ch_tag : uint (bits : 4) : RW : 0x0;
reg_fld smpl_point : uint (bits : 16) : RW : 0x0;
};
As you can see, the regs are identical. I don't wish to replace the entire definition, because it is based on scripts that also generate RTL, and it's too much hassle and risk to try and rewrite them. But, I do want to be able to write a sequence that can write to both of them by constraining them to either one of the GADs.
I defined a struct member for all sequences that write to these registers:
type gad_type_t : [GAD,RX_GAD];
extend ocp_master_sequence_kind_t : [CONFIG_ADC_SEQ];
//This sequence writes a single line to GAD sequencer
extend CONFIG_ADC_SEQ ocp_master_sequence_q {
smpl_point : int(bits:16);
dma_req : bit;
int_en : bit;
smpl_en : bit;
ch_tag : uint(bits:4);
smpl_tag : uint(bits:2);
samp_sig : uint(bits:4);
keep soft samp_sig==0;
//which GAD to config
gad_type : gad_type_t;
keep soft gad_type==GAD;
I tried declaring register variable with macro but failed completely:
//Macro for declaring either GAD or RX_GAD register variable
define <get_gad_reg'action> "gad_reg <var_name'name> : <gad_type'exp> <reg_suffix'exp>" as computed {
var gad_regname : string;
var gad_type : gad_type_t = <gad_type'exp>;
var reg_suffix_s : string = <reg_suffix'exp>;
gad_regname = gad_type == RX_GAD ? append("GAD_RX_",reg_suffix_s) : append("GAD_",reg_suffix_s);
return append("var ",<var_name'name>," : ",gad_regname," vr_ad_reg = driver.get_reg_by_kind(",gad_regname,").as_a(",gad_regname," vr_ad_reg)");
};
Macro is supposed to be used in this way inside the body of the sequence:
gad_reg gad_seq_r : gad_type SEQ;
Which I hoped would translate to:
var gad_seq_r : GAD_SEQ vr_ad_reg = driver.get_reg_by_kind(GAD_SEQ).as_a(GAD_SEQ vr_ad_reg);
or:
var gad_seq_r : GAD_RX_SEQ vr_ad_reg = driver.get_reg_by_kind(GAD_RX_SEQ).as_a(GAD_RX_SEQ vr_ad_reg);
It worked for GAD, but not for RX_GAD, after much debugging I deduced that the gad_type isn't being matched right and the macro just takes the else clause on the conditional assignment.
I decided to try a different approach and not use macro, I tried doing this with the 'when' clause in the sequence itself:
when GAD {
body()#driver.clock is {
var gad_seq_r : GAD_SEQ vr_ad_reg = driver.get_reg_by_kind(GAD_SEQ).as_a(GAD_SEQ vr_ad_reg);
};
};
when RX_GAD {
body()#driver.clock is {
var gad_seq_r : GAD_RX_SEQ vr_ad_reg = driver.get_reg_by_kind(GAD_RX_SEQ).as_a(GAD_RX_SEQ vr_ad_reg);
};
};
body()#driver.clock is also {
gad_seq_r.smpl_point = last_line ? 0x8000 : smpl_point;
gad_seq_r.ch_tag = ch_tag;
gad_seq_r.smpl_tag = smpl_tag;
gad_seq_r.dma_req = dma_req;
gad_seq_r.int_en = int_en;
gad_seq_r.smpl_en = smpl_en;
gad_seq_r.s_event = s_event[6:0];
do WR_REG seq keeping {.reg==gad_seq_r;};
};
That doesn't compile, because the compiler doesn't recognize gad_seq_r outside of 'when' clause.
I don't know if there is a solution for this outside of duplicating code for GAD and RX_GAD, but I thought I might give it a shot here.
Either way, next project we will build a more reusable register database.
If you survived this far, thanks for your attention.

Since both of your registers have the exact same layout, you can just reference any one of the types inside your sequence, build up the desired value based on your sequence fields and then use write_reg <reg> value <val>:
extend CONFIG_ADC_SEQ ocp_master_sequence_q {
gad_type : gad_type_t;
smpl_point: int(bits:16);
// ... all other sequence fields that model register settings
// Used by 'write_reg'
!gad_reg: vr_ad_reg;
body() #driver.clock is also {
// Dummy register variable. Could be of either GAD_SEQ or GAD_RX_SEQ type
var dummy_gad_reg: GAD_SEQ vr_ad_reg;
dummy_gad_reg.smpl_point = smpl_point;
// ... set all other fields of 'gad_seq_r' based on your sequence fields
// Get a pointer to the "real" GAD reg you're trying to access
var real_gad_reg: vr_ad_reg;
if gad_type == GAD {
real_gad_reg = driver.get_reg_by_kind(GAD_SEQ);
}
else {
real_gad_reg = driver.get_reg_by_kind(GAD_RX_SEQ);
};
// Instruct 'vr_ad' to write the value in your dummy reg to the real reg
write_reg gad_reg { .static_item == real_gad_reg }
val dummy_gad_reg.get_cur_value();
};
};
I noticed you're using some WR_REG sequence to write your registers, which takes the register to be written as an argument. If using write_reg isn't an option (for whatever reason) and you have to use your sequence, I think you could replace the call to write_reg from above with:
real_gad_reg.write_reg_val(dummy_gad_reg.get_cur_value());
do WR_REG seq keeping {
.reg == real_gad_reg;
};

Related

Adding user mode types for Perl 6 NativeCall structs

The Perl 6 docs list a bunch of types. Some of them, such as Str, have more complicated box/unbox behaviors.
Is it possible to define my own type, specifying my own routines for the box/unboxing? For a particular project, I have a bunch of types I'm reusing, and basically cut/pasting my accessor functions over and over.
For example, the C Struct uses a time_t, and I plug in accessor methods to go to/from a DateTime. Another example is a comma-separated list, I'd like to go to/from an Array and take care of the split/join automagically.
Is there a better way to do this?
Edit: Add Example:
constant time_t = uint64;
constant FooType_t = uint16;
enum FooType <A B C>;
class Foo is repr('CStruct') is rw
{
has uint32 $.id;
has Str $.name;
has FooType_t $.type;
has time_t $.time;
method name(Str $n?) {
$!name := $n with $n;
$!name;
}
method type(FooType $t?) {
$!type = $t with $t;
FooType($!type);
}
method time(DateTime $d?) {
$!time = .Instant.to-posix[0].Int with $d;
DateTime.new($!time)
}
}
my $f = Foo.new;
$f.id = 12;
$f.name('myname');
$f.type(B);
$f.time(DateTime.new('2000-01-01T12:34:56Z'));
say "$f.id() $f.name() $f.type() $f.time()";
# 12 myname B 2000-01-01T12:34:56Z
This works, I can set the various fields of the CStruct in Perl-ish ways (no lvalue, but I can pass them in as parameters).
Now I want to use time_t, FooType_t, etc. for many fields in a lot of structs and have them act the same way. Is there a better way other than to just copy those methods over and over?
Maybe macros could help here? I haven't mastered them yet.
You could write a trait that handles automatic attribute conversion on fetching or storing the attribute. The following should get you started:
multi sub trait_mod:<is>(Attribute:D $attr, :$autoconv!) {
use nqp;
my $name := $attr.name;
$attr.package.^add_method: $name.substr(2), do given $attr.type {
when .REPR eq 'P6int' {
method () is rw {
my $self := self;
Proxy.new:
FETCH => method () {
$autoconv.out(nqp::getattr_i($self, $self.WHAT, $name));
},
STORE => method ($_) {
nqp::bindattr_i($self, $self.WHAT, $name,
nqp::decont($autoconv.in($_)));
}
}
}
default {
die "FIXME: no idea how to handle {.^name}";
}
}
}
For example, take your use case of time_t:
constant time_t = uint64;
class CTimeConversion {
multi method in(Int $_ --> time_t) { $_ }
multi method in(DateTime $_ --> time_t) { .posix }
method out(time_t $_ --> DateTime) { DateTime.new($_) }
}
class CTimeSpan is repr<CStruct> {
has time_t $.start is autoconv(CTimeConversion);
has time_t $.end is autoconv(CTimeConversion);
}
Finally, some example code to show it works:
my $span = CTimeSpan.new;
say $span;
say $span.end;
$span.end = DateTime.now;
say $span;
say $span.end;

How do I get a list of unconnected cell ports using the Yosys RTLIL API?

For a larger project, I need to create a list of unconnected cell ports using the Yosys RTLIL API. What is the best strategy for doing so?
The plain RTLIL API does not provide any indexes. You can determine the net connected to a port, but not the ports connected to a net. There are powerful indexers available in Yosys that can help you here, for example ModIndex from kernel/modtools.h, but in most cases it is simplest to create a custom index for whatever you need.
In this case we just need a dict<> that counts the number of cells connected to a net bit. We make two passes over all cell ports. In the first pass we count the number of connections for each signal bit, and in a second pass we determine if a cell port is the only port connected to that bit:
void find_unconn_cellports(Module *module)
{
SigMap sigmap(module);
dict<SigBit, int> sigbit_conncounts;
for (auto wire : module->wires()) {
if (wire->port_input)
for (auto bit : sigmap(wire))
sigbit_conncounts[bit]++;
if (wire->port_output)
for (auto bit : sigmap(wire))
sigbit_conncounts[bit]++;
}
for (auto cell : module->cells())
for (auto conn : cell->connections())
for (auto bit : conn.second)
sigbit_conncounts[sigmap(bit)]++;
for (auto cell : module->cells())
for (auto conn : cell->connections())
for (int i = 0; i < GetSize(conn.second); i++)
if (sigbit_conncounts.at(sigmap(conn.second[i])) == 1)
log("Unconnected cell port bit: %s.%s.%s[%d]\n",
log_id(module), log_id(cell), log_id(conn.first), i);
}
Using a similar approach we can find all undriven cell ports:
void find_undriven_cellports(Module *module)
{
SigMap sigmap(module);
pool<SigBit> driven_sigbit;
for (auto wire : module->wires()) {
if (wire->port_input)
for (auto bit : sigmap(wire))
driven_sigbit.insert(bit);
}
for (auto cell : module->cells())
for (auto conn : cell->connections())
if (cell->output(conn.first))
for (auto bit : sigmap(conn.second))
driven_sigbit.insert(bit);
for (auto cell : module->cells())
for (auto conn : cell->connections())
if (cell->input(conn.first))
for (int i = 0; i < GetSize(conn.second); i++) {
auto bit = sigmap(conn.second[i]);
if (bit.wire && !driven_sigbit.count(bit))
log("Undriven cell port bit: %s.%s.%s[%d]\n",
log_id(module), log_id(cell), log_id(conn.first), i);
}
}
Or all unused cell ports:
void find_unused_cellports(Module *module)
{
SigMap sigmap(module);
pool<SigBit> used_sigbit;
for (auto wire : module->wires()) {
if (wire->port_output)
for (auto bit : sigmap(wire))
used_sigbit.insert(bit);
}
for (auto cell : module->cells())
for (auto conn : cell->connections())
if (cell->input(conn.first))
for (auto bit : sigmap(conn.second))
used_sigbit.insert(bit);
for (auto cell : module->cells())
for (auto conn : cell->connections())
if (cell->output(conn.first))
for (int i = 0; i < GetSize(conn.second); i++)
if (used_sigbit.count(sigmap(conn.second[i])) == 0)
log("Unused cell port bit: %s.%s.%s[%d]\n",
log_id(module), log_id(cell), log_id(conn.first), i);
}

What is the grammar of rule of this code in Objective-C or in C language?

I'm reading the code of Mach Ports, I want to know what's the paradigm of a piece of code. I mean I knew the grammar of struct of objective-c, but I don't know what grammar of message.header = (mach_msg_header_t) {......};
The complete code is below.
natural_t data;
mach_port_t port;
struct {
mach_msg_header_t header;
mach_msg_body_t body;
mach_msg_type_descriptor_t type;
} message;
message.header = (mach_msg_header_t) {
.msgh_remote_port = port,
.msgh_local_port = MACH_PORT_NULL,
.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0),
.msgh_size = sizeof(message)
};
The header is assigned to the type-casted mach_msg_header_t pseudo constructor that initializes some of the fields. A break down of the structure is available here : http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/ (partially pasted below)
typedef struct {
mach_msg_bits_t msgh_bits;
mach_msg_size_t msgh_size;
mach_port_t msgh_remote_port;
mach_port_t msgh_local_port;
mach_port_seqno_t msgh_seqno;
mach_msg_id_t msgh_id;
} mach_msg_header_t;
The bit you referenced, does the assignment of the low level fields in the structure and copy into the header.
message.header = (mach_msg_header_t) {
.msgh_remote_port = port,
.msgh_local_port = MACH_PORT_NULL,
.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0),
.msgh_size = sizeof(message)
};

NSMutableData to CConstPointer conversion in Swift needed

The following Swift code (writing bytes to a stream) is rewritten from Objective-C:
var outputStream : NSOutputStream = NSOutputStream()
var pData : NSMutableData = NSMutableData()
var pType : Int = 1
let pMessage : String = "Device_Description\0\0\x01" // 16BitChar with escapeSequence
var pLength : Int = 8+pMessage.lengthOfBytesUsingEncoding(NSUTF16LittleEndianStringEncoding)
pData.appendBytes(&pLength, length: 4)
pData.appendBytes(&pType, length: 4)
pData.appendData((pMessage as NSString).dataUsingEncoding(NSUTF16LittleEndianStringEncoding))
outputStream.write(pData.bytes, maxLength: pData.length)
pData.bytes is of type COpaquePointer, but CConstPointer<Uint8>is needed by the write operation. Any hints for the correct conversion? Thanks in advance.
As Jack wu has outlined, but somewhat incompletely, the following code works just the same as using the UnsafePointer option:
var byteData = [UInt8]()
pData.getBytes(&byteData)
self.outputStream!.write(byteData, maxLength: pData.length)
From the Swift & Objc interop book section here : https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/buildingcocoaapps/InteractingWithCAPIs.html
C Constant Pointers
When a function is declared as taking a CConstPointer argument,
it can accept any of the following:
nil, which is passed as a null pointer
A CMutablePointer, CMutableVoidPointer, CConstPointer, CConstVoidPointer, or AutoreleasingUnsafePointer value, which
is converted to CConstPointer if necessary
An in-out expression whose operand is an lvalue of type Type, which is passed as the address of the lvalue
A Type[] value, which is passed as a pointer to the start of the array, and lifetime-extended for the duration of the call
I believe then it can work like this:
var p: [Uint8] = []
pData.getBytes(&p)
outputStream.write(p, maxLength: pData.length)
I found a simple solution right now, by use of UnsafePointer<T>():
var outputStream : NSOutputStream = NSOutputStream()
var pData : NSMutableData = NSMutableData()
var pType : Int = 1
let pMessage : String = "Device_Description\0\0\x01" // 16BitChar with escapeSequence
var pLength : Int = 8+pMessage.lengthOfBytesUsingEncoding(NSUTF16LittleEndianStringEncoding)
pData.appendBytes(&pLength, length: 4)
pData.appendBytes(&pType, length: 4)
pData.appendData(ptpMessage.dataUsingEncoding(NSUTF16LittleEndianStringEncoding))
outputStream.write(UnsafePointer<UInt8>(pData.bytes), maxLength: pData.length)
#holex: Thanks for your input. I know this solution is not quite Swifty, but it´s working for now.

Objective C - How to receive two int in same parameter

I need to write a method like this:
-(void)doStuff:(int)options;
Based in the a typedef enum like this:
typedef enum
{
FirstOption,
SecondOption,
ThirdOption
} MyOptions
What I need to to do in order to be able to call the method in this way (i.e. calling the method with more than one option "enabled":
[self doStuff:(FirstOption | ThirdOption)];
Do I need to setup the typedef enum differently? And how I check the options received in the method, a simple if (options == ...)?
What you call for is a bit array. Define your options like this:
enum MyOptions
{
FirstOption = 0x01, // first bit
SecondOption = 0x02, // second bit
ThirdOption = 0x04, // third bit
... = 0x08 ...
};
Combine the options like you suggested, with |, and test for them with & (options & SecondOption).
- (void) doStuff: (MyOptions) options
{
if ( options & FirstOption )
{
// do something fancy
}
if ( options & SecondOption )
{
// do something awesome
}
if ( (options & SecondOption) && ( options & ThirdOption) )
{
// do something sublime
}
}
I'm no expert at Obj-C, but in other languages I would use flags. If each value is a power of two, then it will have only one bit set for that value. You can use that bit as a bool for a particular option.
FirstOption = 1
SecondOption = 2
ThirdOption = 4
FirstAndThird = FirstOption | ThirdOption; // Binary Or sets the bits
// Binary And checks the bits
IsFirst = FirstAndThird & FirstOption == FirstOption; // is true
IsSecond = FirstAndThird & SecondOption == SecondOption; // is false
IsThird = FirstAndThird & ThirdOption == ThirdOption; // is true
This question may also be of use.