Utilities for testing simics.
fail(msg)
Takes a string describing the failure as its single argument. If called in collect failures mode this will collect the failure for later checking with check_failures. If called outside collect failures mode it will immediately raise a TestFailure exception instead.
collect_failures()
If you use this you have to call check_failures at the end of your test script to check if it signaled any failures.
check_failures()
If any failures have occurred this function will report the failures and raise a TestFailure exception. If called outside collect failures mode this function will fail.
trap_log(logtype, obj = None)
By default the stest trap 'error' and 'spec-viol' log messages.
trap_log without an object sets the default handling for the given log type. Object specific settings always take precedence over the default handling.
Arguments:
untrap_log(logtype, obj = None)
untrap_log without an object sets the default behavior for the given log type. Object specific settings always take precedence over the default handling.
Arguments:
expect_true(cond, msg = 'expectation failed')
Arguments:
expect_false(cond, msg = 'expectation failed')
Arguments:
expect_equal(got, expected, msg = 'expectation failed')
Arguments:
expect_different(got, unexpected, msg = 'expectation failed')
Arguments:
expect_log(fun, args = [], obj = None, log_type = 'error', msg = None, regex = '', with_log_level = None)
expect_log_mgr(*args, **kwds)
re.search()
, which the emitted log must match
Example usage:
with stest.expect_log_mgr(log_type="spec-viol", msg="Check warning on read-only fields"): reg_compute_units.write(0xffff_ffff_ffff_ffff)
expect_exception(fun, args, exc)
expect_exception_mgr(*args, **kwds)
Arguments:
Example usage:
with stest.expect_exception_mgr(simics.SimExc_AttrNotWritable): dev.read_only_attribute = False
Use the fail function instead of raising this exception yourself.
A Python module for writing device model tests. Has three major parts: classes for accessing device registers, classes for writing device stubs, and classes for handling simulated memory and data structures in it. It also contains some auxiliary utilities.
It uses the Simics API and can only be used by Python code running in Simics.
bank_regs(bank, inquiry = False, prefix = '')
"g[2][3].r[1]"
, and the returned structure is o
,
then the corresponding register object can be obtained as
o.g[2][3].g[1]
. The set of registers is extracted using
the register_view
interface, and uses offsets and
bitfields as returned by that interface.
The inquiry
argument is deprecated and should not be used.
If prefix
is
given, then the returned structure will only contain registers whose
full name matches this prefix.
The returned register objects have methods read()
and
write()
that work like their AbstractRegister
counterparts, reading and writing the register with side-effects.
The register value can be read and written without side-effects
objects by getting and setting a property .val
, or by
calling a method set()
. The latter accepts keyword
arguments for fields just like the write()
method; bits not
covered by fields are retrieved by reading .val
. The
positional argument of the write()
method is required and
may be either an integer, or READ
to denote that previous
values are retrieved using read()
, or VAL
to denote that
they are retrieved using .val
.
Objects that represent the fields of a register can be retrieved as
reg.field.FIELDNAME
; e.g., if a register reg
has a
field named "a.b[2]"
then the field object is accessed as
reg.field.a.b[2]
. The field object has one method
read()
for performing a full-register read with
side-effects and returning the bits corresponding to the field, and
a property .val
that allows side-effect free access to the
field's bits. Field objects do not have a write
method;
writes must be done from the register object; this is to ensure that
remaining bits are explicitly specified.
iface(name)
value_to_tuple_be(val, bytes)
tuple(val.to_bytes(bytes, 'big'))
instead.
value_to_tuple_le(val, bytes)
tuple(val.to_bytes(bytes, 'little'))
instead.
tuple_to_value_be(t)
int.from_bytes(t, 'big')
instead.
tuple_to_value_le(t)
int.from_bytes(t, 'little')
instead.
RangeError(msg, re = None)
Bitfield(fields = None, ones = 0, little_endian = True, bits = None, **kwargs)
{'field-name' : bit-number, 'field-name' : (start-bit, stop-bit), 'field-name' : (start-bit, sub-field) }
obj.fields(value)
obj.mask(**dict)
obj.mk_bitfield_map(m, prefix = '', oset = 0)
obj.value(*args, **kwargs)
foo=5
to
return the value when field "foo"
is 5. If the value is
a list or dict rather than an integer, then a field array is
assumed; e.g. foo=[1,2]
is a shorthand for setting
field "foo[0]"
to 1 and field "foo[1]"
to 2,
and foo={1:4}
is a shorthand for setting field
"foo[1]"
to 4.
An optional positional argument can be supplied, to provide the values of bits not covered by the given fields.
Bitfield_LE(fields = None, ones = 0, **kwargs)
{'field-name' : bit-number, 'field-name' : (start-bit, stop-bit), 'field-name' : (start-bit, sub-field) }
Bitfield_BE(fields = None, ones = 0, bits = None, **kwargs)
{'field-name' : bit-number, 'field-name' : (start-bit, stop-bit), 'field-name' : (start-bit, sub-field) }
AbstractRegister(size = 4, bitfield = None, little_endian = True)
This class handles generic register stuff, like bitfield mapping and value construction/deconstruction. It depends on a subclass to implement the backend for data storage.
Subclasses are expected to implement two functions:
Optionally, a bitfield can be applied to a register. For such a register,
a specific field can be read through reg.field.FIELDNAME.read()
. The
write() method also has support for bitfields. Please see the
documentation for write() for more information.
There is an alternative deprecated shorthand for accessing fields:
reg.FIELDNAME
triggers a read that filters out the given
field, and similarly, reg.FIELDNAME = value
reads the
field, adjusts the given field, and writes back the value. This
syntax is deprecated, because it is not consistent with the API
exposed by register objects that both support accesses with and
without side-effects.
Constructor arguments:
obj.fields()
obj.read()
obj.write(*args, **fields)
You can either pass a single integer, or pass the fields as
arguments, i.e., write(field0=1, field1=23)
. For field
arrays, the syntax write(field=[1,23])
or
write(field={0: 1, 1: 23})
can be used to set the fields named
field[0]
and field[1]
.
If only a subset of fields is given, a positional arg should
also be passed for the base value, which defines what to write to
remaining bits. The value READ denotes that the read()
method is
called to retrieve the base value.
Register(*args, **kwargs)
The tuple syntax was useful in old Simics versions where banks were not separate objects. It should be avoided in new versions.
The initiator argument denotes the initiator of transactions accessing the register. See the AbstractRegister documentation for information about the rest of the parameters.
obj.raw_read()
obj.raw_write(val)
Register_LE(*args, **kwargs)
Register_BE(*args, **kwargs)
GRegister(size = 4, bitfield = None, init = 0)
obj.raw_read()
obj.raw_write(value)
IRegister(data, size = None, bitfield = None)
int_register
interface. If the object obj does
not implement the processor_info
you have to specify the
size in size.
obj.raw_read()
obj.raw_write(value)
Dev(iface_list = [], create_sim_obj = True, name = None)
The obj attribute contains the instance of the Simics class, and the cls_name attribute contains the name of the Simics class. Constructor arguments:
Each interface will be instantiated and can be accessed through dev.iface-name, or dev.port.iface-name.
Example:
dev = Dev([SimpleInterrupt, ('sreset', Signal), ('hreset', Signal)]) dev.simple_interrupt dev.sreset.signal dev.hreset.signal
obj.configure_pre_object(pre_obj)
obj.finalize()
obj.register_simics_class()
obj.fail(msg)
Called by the default method stubs.
Memory()
sparse-memory
class.
Provides an interface compatible with the deprecated Memory class.
The obj attribute contains an instance of memory-space
,
mapping to the memory. The real_obj attribute contains
an instance of the 'sparse-memory' class. The mem
attribute is an alias to the mem attribute of
real_obj.
obj.clear(*args)
obj.is_range_touched(start, length)
obj.read(addr, n)
Arguments:
Throws an exception if any byte in the read range is empty.
obj.write(addr, data)
Arguments:
Fills in empty slots in the memory and overwrites already existing data.
Layout(mem, ofs, regs, little_endian)
Testing devices that does DMA transfers usually requires setting up DMA descriptors. These can often be seen as register sets located in memory. This class allows you to define the layout of those registers, including bitfields within the registers.
Registers without bitfields can be accessed through:
layout.reg-name
while registers with bitfields can be accessed through:
layout.reg-name.field-name
or
layout.reg-name.read(), layout.reg-name.write()
Layouts are mapped ontop of Memory, i.e. NOT ontop of normal Simics RAM. Constructor arguments:
{'reg-name' : (offset, size), 'reg-name' : (offset, size, bitfield)}
obj.clear()
obj.read(ofs, size)
obj.write(ofs, value, size)
Layout_LE(mem, ofs, regs)
Layout_BE(mem, ofs, regs)
Internal and/or legacy classes removed from dev_util.py
iface(name)
All the interface methods in the class will raise an exception when called. Convenient when creating a fake device that is required to implement an interface, but you know that the interface should be unused in the given test.
Dev(iface_list = [], create_sim_obj = True, name = None)
The obj attribute contains the instance of the Simics class, and the cls_name attribute contains the name of the Simics class. Constructor arguments:
Each interface will be instantiated and can be accessed through dev.iface-name, or dev.port.iface-name.
Example:
dev = Dev([SimpleInterrupt, ('sreset', Signal), ('hreset', Signal)]) dev.simple_interrupt dev.sreset.signal dev.hreset.signal
obj.configure_pre_object(pre_obj)
obj.finalize()
obj.register_simics_class()
obj.fail(msg)
Called by the default method stubs.
Memory(test = False)
Each byte sized slot in this memory can either contain a byte of data or be empty. Empty slots cannot be read.
The obj attribute contains the object implementing the Simics
interface to the memory. It implements the memory_space
interface.
Constructor arguments:
obj.clear()
obj.is_range_touched(start, length)
obj.read(addr, n)
Arguments:
This method throws an exception if any byte in the read range is empty.
obj.write(addr, bytes)
Arguments:
Fills in empty slots in the memory and overwrites already existing data.