_CTX_BUF_AT_ADDR = '&{}'.format(_CTX_BUF_AT)
_CTX_CALL_CLOCK_CB = 'ctx->clock_cb(ctx->clock_cb_data)'
- _bo_suffixes_map = {
+ _BO_SUFFIXES_MAP = {
pytsdl.tsdl.ByteOrder.BE: 'be',
pytsdl.tsdl.ByteOrder.LE: 'le',
}
- _tsdl_type_names_map = {
+ _TSDL_TYPE_NAMES_MAP = {
pytsdl.tsdl.Integer: 'integer',
pytsdl.tsdl.FloatingPoint: 'floating point',
pytsdl.tsdl.Enum: 'enumeration',
def __init__(self):
self._parser = pytsdl.parser.Parser()
+
self._obj_size_cb = {
pytsdl.tsdl.Struct: self._get_struct_size,
pytsdl.tsdl.Integer: self._get_integer_size,
pytsdl.tsdl.FloatingPoint: self._get_floating_point_size,
pytsdl.tsdl.Array: self._get_array_size,
}
+
self._obj_alignment_cb = {
pytsdl.tsdl.Struct: self._get_struct_alignment,
pytsdl.tsdl.Integer: self._get_integer_alignment,
pytsdl.tsdl.Sequence: self._get_sequence_alignment,
pytsdl.tsdl.String: self._get_string_alignment,
}
+
self._obj_param_ctype_cb = {
pytsdl.tsdl.Struct: lambda obj: 'const void*',
pytsdl.tsdl.Integer: self._get_integer_param_ctype,
pytsdl.tsdl.Sequence: lambda obj: 'const void*',
pytsdl.tsdl.String: lambda obj: 'const char*',
}
+
self._write_field_obj_cb = {
pytsdl.tsdl.Struct: self._write_field_struct,
pytsdl.tsdl.Integer: self._write_field_integer,
pytsdl.tsdl.Sequence: self._write_field_sequence,
pytsdl.tsdl.String: self._write_field_string,
}
+
self._get_src_name_funcs = {
'trace.packet.header.': self._get_tph_src_name,
'env.': self._get_env_src_name,
'event.fields.': self._get_ef_src_name,
}
- # TODO: prettify this function
- def _validate_struct(self, struct):
+ # Validates an inner TSDL structure's field (constrained structure).
+ #
+ # fname: field name
+ # ftype: TSDL object
+ def _validate_inner_struct_field(self, fname, ftype):
+ if type(ftype) is pytsdl.tsdl.Sequence:
+ raise RuntimeError('field "{}" is a dynamic array (not allowed here)'.format(fname))
+ elif type(ftype) is pytsdl.tsdl.Array:
+ # we need to check every element until we find a terminal one
+ element = ftype.element
+ self._validate_inner_struct_field(fname, element)
+ elif type(ftype) is pytsdl.tsdl.Variant:
+ raise RuntimeError('field "{}" is a variant (unsupported)'.format(fname))
+ elif type(ftype) is pytsdl.tsdl.String:
+ raise RuntimeError('field "{}" is a string (not allowed here)'.format(fname))
+ elif type(ftype) is pytsdl.tsdl.Struct:
+ self._validate_inner_struct(ftype)
+ elif type(ftype) is pytsdl.tsdl.Integer:
+ if self._get_obj_size(ftype) > 64:
+ raise RuntimeError('integer field "{}" larger than 64-bit'.format(fname))
+ elif type(ftype) is pytsdl.tsdl.FloatingPoint:
+ if self._get_obj_size(ftype) > 64:
+ raise RuntimeError('floating point field "{}" larger than 64-bit'.format(fname))
+ elif type(ftype) is pytsdl.tsdl.Enum:
+ if self._get_obj_size(ftype) > 64:
+ raise RuntimeError('enum field "{}" larger than 64-bit'.format(fname))
+
+ # Validates an inner TSDL structure (constrained).
+ #
+ # struct: TSDL structure to validate
+ def _validate_inner_struct(self, struct):
# just in case we call this with the wrong type
if type(struct) is not pytsdl.tsdl.Struct:
raise RuntimeError('expecting a struct')
# check each field
for fname, ftype in struct.fields.items():
- if type(ftype) is pytsdl.tsdl.Sequence:
- raise RuntimeError('field "{}" is a dynamic array (not allowed here)'.format(fname))
- elif type(ftype) is pytsdl.tsdl.Array:
- # we need to check every element until we find a terminal one
- element = ftype.element
-
- while True:
- if type(element) is pytsdl.tsdl.Sequence:
- raise RuntimeError('field "{}" contains a dynamic array (not allowed here)'.format(fname))
- elif type(element) is pytsdl.tsdl.Variant:
- raise RuntimeError('field "{}" contains a variant (unsupported)'.format(fname))
- elif type(element) is pytsdl.tsdl.String:
- raise RuntimeError('field "{}" contains a string (not allowed here)'.format(fname))
- elif type(element) is pytsdl.tsdl.Struct:
- _validate_struct(element)
- elif type(element) is pytsdl.tsdl.Integer:
- if self._get_obj_size(element) > 64:
- raise RuntimeError('integer field "{}" larger than 64-bit'.format(fname))
- elif type(element) is pytsdl.tsdl.FloatingPoint:
- if self._get_obj_size(element) > 64:
- raise RuntimeError('floating point field "{}" larger than 64-bit'.format(fname))
- elif type(element) is pytsdl.tsdl.Enum:
- if self._get_obj_size(element) > 64:
- raise RuntimeError('enum field "{}" larger than 64-bit'.format(fname))
-
- if type(element) is pytsdl.tsdl.Array:
- # still an array, continue
- element = element.element
- else:
- # found the terminal element
- break
- elif type(ftype) is pytsdl.tsdl.Variant:
- raise RuntimeError('field "{}" is a variant (unsupported)'.format(fname))
- elif type(ftype) is pytsdl.tsdl.String:
- raise RuntimeError('field "{}" is a string (not allowed here)'.format(fname))
- elif type(ftype) is pytsdl.tsdl.Struct:
- self._validate_struct(ftype)
- elif type(ftype) is pytsdl.tsdl.Integer:
- if self._get_obj_size(ftype) > 64:
- raise RuntimeError('integer field "{}" larger than 64-bit'.format(fname))
- elif type(ftype) is pytsdl.tsdl.FloatingPoint:
- if self._get_obj_size(ftype) > 64:
- raise RuntimeError('floating point field "{}" larger than 64-bit'.format(fname))
- elif type(ftype) is pytsdl.tsdl.Enum:
- if self._get_obj_size(ftype) > 64:
- raise RuntimeError('enum field "{}" larger than 64-bit'.format(fname))
+ self._validate_inner_struct_field(fname, ftype)
+ # Validates a context or fields structure.
+ #
+ # struct: context/fields TSDL structure
def _validate_context_fields(self, struct):
if type(struct) is not pytsdl.tsdl.Struct:
raise RuntimeError('expecting a struct')
raise RuntimeError('field "{}" is a variant (unsupported)'.format(fname))
elif type(ftype) is pytsdl.tsdl.Struct:
# validate inner structure against barectf constraints
- self._validate_struct(ftype)
+ self._validate_inner_struct(ftype)
+ # Validates a TSDL integer with optional constraints.
+ #
+ # integer: TSDL integer to validate
+ # size: expected size (None for any size)
+ # align: expected alignment (None for any alignment)
+ # signed: expected signedness (None for any signedness)
def _validate_integer(self, integer, size=None, align=None,
- signed=None):
+ signed=None):
if type(integer) is not pytsdl.tsdl.Integer:
raise RuntimeError('expected integer')
if integer.signed != signed:
raise RuntimeError('expected {} integer'.format('signed' if signed else 'unsigned'))
- def _validate_packet_header(self, packet_header):
+ # Validates a packet header.
+ #
+ # packet_header: packet header TSDL structure to validate
+ def _validate_tph(self, packet_header):
try:
- self._validate_struct(packet_header)
+ self._validate_inner_struct(packet_header)
except RuntimeError as e:
_perror('packet header: {}'.format(e))
if len(packet_header.fields) != 2:
_perror('packet header: only "magic" and "stream_id" fields are allowed')
+ # Converts a list of strings to a dotted representation. For
+ # example, ['trace', 'packet', 'header', 'magic'] is converted to
+ # 'trace.packet.header.magic'.
+ #
+ # name: list of strings to convert
def _dot_name_to_str(self, name):
return '.'.join(name)
+ # Compares two TSDL integers. Returns True if they are the same.
+ #
+ # int1: first TSDL integer
+ # int2: second TSDL integer
def _compare_integers(self, int1, int2):
if type(int1) is not pytsdl.tsdl.Integer:
return False
# True means 1 for sum()
return sum(comps) == len(comps)
- def _validate_packet_context(self, stream):
+ # Validates a packet context.
+ #
+ # stream: TSDL stream containing the packet context to validate
+ def _validate_spc(self, stream):
packet_context = stream.packet_context
sid = stream.id
try:
- self._validate_struct(packet_context)
+ self._validate_inner_struct(packet_context)
except RuntimeError as e:
_perror('stream {}: packet context: {}'.format(sid, e))
except RuntimeError as e:
_perror('stream {}: packet context: "cpu_id": {}'.format(sid, e))
- def _validate_event_header(self, stream):
+ # Validates an event header.
+ #
+ # stream: TSDL stream containing the event header to validate
+ def _validate_seh(self, stream):
event_header = stream.event_header
sid = stream.id
try:
- self._validate_struct(event_header)
+ self._validate_inner_struct(event_header)
except RuntimeError as e:
_perror('stream {}: event header: {}'.format(sid, e))
if len(fields) != 2:
_perror('stream {}: event header: only "id" and "timestamp" fields are allowed'.format(sid))
- def _validate_stream_event_context(self, stream):
+ # Validates a strean event context.
+ #
+ # stream: TSDL stream containing the stream event context
+ def _validate_sec(self, stream):
stream_event_context = stream.event_context
sid = stream.id
except RuntimeError as e:
_perror('stream {}: event context: {}'.format(sid, e))
- def _validate_event_context(self, stream, event):
+ # Validates an event context.
+ #
+ # stream: TSDL stream containing the TSDL event
+ # event: TSDL event containing the context to validate
+ def _validate_ec(self, stream, event):
event_context = event.context
sid = stream.id
eid = event.id
except RuntimeError as e:
_perror('stream {}: event {}: context: {}'.format(sid, eid, e))
- def _validate_event_fields(self, stream, event):
+ # Validates an event fields.
+ #
+ # stream: TSDL stream containing the TSDL event
+ # event: TSDL event containing the fields to validate
+ def _validate_ef(self, stream, event):
event_fields = event.fields
sid = stream.id
eid = event.id
except RuntimeError as e:
_perror('stream {}: event {}: fields: {}'.format(sid, eid, e))
+ # Validates a TSDL event.
+ #
+ # stream: TSDL stream containing the TSDL event
+ # event: TSDL event to validate
def _validate_event(self, stream, event):
# name must be a compatible C identifier
if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', event.name):
_perror('stream {}: event {}: malformed name'.format(stream.id,
event.id))
- self._validate_event_context(stream, event)
- self._validate_event_fields(stream, event)
+ self._validate_ec(stream, event)
+ self._validate_ef(stream, event)
+ # Validates a TSDL stream.
+ #
+ # stream: TSDL stream to validate
def _validate_stream(self, stream):
- self._validate_event_header(stream)
- self._validate_packet_context(stream)
- self._validate_stream_event_context(stream)
+ self._validate_seh(stream)
+ self._validate_spc(stream)
+ self._validate_sec(stream)
# event stuff
for event in stream.events:
self._validate_event(stream, event)
+ # Validates all TSDL scopes of the current TSDL document.
def _validate_all_scopes(self):
# packet header
- self._validate_packet_header(self._doc.trace.packet_header)
+ self._validate_tph(self._doc.trace.packet_header)
# stream stuff
for stream in self._doc.streams.values():
self._validate_stream(stream)
+ # Validates the trace block.
+ def _validate_trace(self):
+ # make sure a native byte order is specified
+ if self._doc.trace.byte_order is None:
+ _perror('native byte order (trace.byte_order) is not specified')
+ # Validates the current TSDL document.
def _validate_metadata(self):
+ self._validate_trace()
self._validate_all_scopes()
+ # Returns an aligned number.
+ #
# 3, 4 -> 4
# 4, 4 -> 4
# 5, 4 -> 8
# 7, 4 -> 8
# 8, 4 -> 8
# 9, 4 -> 12
+ #
+ # at: number to align
+ # align: alignment (power of two)
def _get_alignment(self, at, align):
return (at + align - 1) & -align
- # this converts a tree of offset variables:
+ # Converts a tree of offset variables:
#
# field
# a -> 0
# field_other_struct_yeah -> 20
# field_c -> 32
# len -> 36
+ #
+ # offvars_tree: tree of offset variables
+ # prefix: offset variable name prefix
+ # offvars: flattened offset variables
def _flatten_offvars_tree(self, offvars_tree, prefix=None,
offvars=None):
if offvars is None:
return offvars
- # returns the size of a struct with _static size_
+ # Returns the size of a TSDL structure with _static size_ (must be
+ # validated first).
+ #
+ # struct: TSDL structure of which to get the size
+ # offvars_tree: optional offset variables tree (output)
+ # base_offset: base offsets for offset variables
def _get_struct_size(self, struct,
offvars_tree=None,
base_offset=0):
return offset
+ # Returns the size of a TSDL array.
+ #
+ # array: TSDL array of which to get the size
def _get_array_size(self, array):
element = array.element
return self._get_alignment(size, align) * array.length
+ # Returns the size of a TSDL enumeration.
+ #
+ # enum: TSDL enumeration of which to get the size
def _get_enum_size(self, enum):
return self._get_obj_size(enum.integer)
+ # Returns the size of a TSDL floating point number.
+ #
+ # floating_point: TSDL floating point number of which to get the size
def _get_floating_point_size(self, floating_point):
return floating_point.exp_dig + floating_point.mant_dig
+ # Returns the size of a TSDL integer.
+ #
+ # integer: TSDL integer of which to get the size
def _get_integer_size(self, integer):
return integer.size
+ # Returns the size of a TSDL type.
+ #
+ # obj: TSDL type of which to get the size
def _get_obj_size(self, obj):
return self._obj_size_cb[type(obj)](obj)
+ # Returns the alignment of a TSDL structure.
+ #
+ # struct: TSDL structure of which to get the alignment
def _get_struct_alignment(self, struct):
if struct.align is not None:
return struct.align
return cur_align
+ # Returns the alignment of a TSDL integer.
+ #
+ # integer: TSDL integer of which to get the alignment
def _get_integer_alignment(self, integer):
return integer.align
+ # Returns the alignment of a TSDL floating point number.
+ #
+ # floating_point: TSDL floating point number of which to get the
+ # alignment
def _get_floating_point_alignment(self, floating_point):
return floating_point.align
+ # Returns the alignment of a TSDL enumeration.
+ #
+ # enum: TSDL enumeration of which to get the alignment
def _get_enum_alignment(self, enum):
return self._get_obj_alignment(enum.integer)
+ # Returns the alignment of a TSDL string.
+ #
+ # string: TSDL string of which to get the alignment
def _get_string_alignment(self, string):
return 8
+ # Returns the alignment of a TSDL array.
+ #
+ # array: TSDL array of which to get the alignment
def _get_array_alignment(self, array):
return self._get_obj_alignment(array.element)
+ # Returns the alignment of a TSDL sequence.
+ #
+ # sequence: TSDL sequence of which to get the alignment
def _get_sequence_alignment(self, sequence):
return self._get_obj_alignment(sequence.element)
+ # Returns the alignment of a TSDL type.
+ #
+ # obj: TSDL type of which to get the alignment
def _get_obj_alignment(self, obj):
return self._obj_alignment_cb[type(obj)](obj)
- def _fname_to_pname(self, prefix, name):
- return 'param_{}_{}'.format(prefix, name)
+ # Converts a field name to a C parameter name.
+ #
+ # You should not use this function directly, but rather use one
+ # of the _*_fname_to_pname() variants depending on your scope.
+ #
+ # prefix: parameter name prefix
+ # fname: field name
+ def _fname_to_pname(self, prefix, fname):
+ return 'param_{}_{}'.format(prefix, fname)
- def _ef_fname_to_pname(self, name):
- return self._fname_to_pname('ef', name)
+ # Converts an event fields field name to a C parameter name.
+ #
+ # fname: field name
+ def _ef_fname_to_pname(self, fname):
+ return self._fname_to_pname('ef', fname)
- def _ec_fname_to_pname(self, name):
- return self._fname_to_pname('ec', name)
+ # Converts an event context field name to a C parameter name.
+ #
+ # fname: field name
+ def _ec_fname_to_pname(self, fname):
+ return self._fname_to_pname('ec', fname)
- def _sec_fname_to_pname(self, name):
- return self._fname_to_pname('sec', name)
+ # Converts a stream event context field name to a C parameter name.
+ #
+ # fname: field name
+ def _sec_fname_to_pname(self, fname):
+ return self._fname_to_pname('sec', fname)
- def _eh_fname_to_pname(self, name):
- return self._fname_to_pname('eh', name)
+ # Converts an event header field name to a C parameter name.
+ #
+ # fname: field name
+ def _eh_fname_to_pname(self, fname):
+ return self._fname_to_pname('eh', fname)
- def _spc_fname_to_pname(self, name):
- return self._fname_to_pname('spc', name)
+ # Converts a stream packet context field name to a C parameter name.
+ #
+ # fname: field name
+ def _spc_fname_to_pname(self, fname):
+ return self._fname_to_pname('spc', fname)
- def _tph_fname_to_pname(self, name):
- return self._fname_to_pname('tph', name)
+ # Converts a trace packet header field name to a C parameter name.
+ #
+ # fname: field name
+ def _tph_fname_to_pname(self, fname):
+ return self._fname_to_pname('tph', fname)
+ # Returns the equivalent C type of a TSDL integer.
+ #
+ # integer: TSDL integer of which to get the equivalent C type
def _get_integer_param_ctype(self, integer):
signed = 'u' if not integer.signed else ''
return '{}int{}_t'.format(signed, sz)
+ # Returns the equivalent C type of a TSDL enumeration.
+ #
+ # enum: TSDL enumeration of which to get the equivalent C type
def _get_enum_param_ctype(self, enum):
return self._get_obj_param_ctype(enum.integer)
+ # Returns the equivalent C type of a TSDL floating point number.
+ #
+ # fp: TSDL floating point number of which to get the equivalent C type
def _get_floating_point_param_ctype(self, fp):
if fp.exp_dig == 8 and fp.mant_dig == 24 and fp.align == 32:
return 'float'
else:
return 'uint64_t'
+ # Returns the equivalent C type of a TSDL type.
+ #
+ # obj: TSDL type of which to get the equivalent C type
def _get_obj_param_ctype(self, obj):
return self._obj_param_ctype_cb[type(obj)](obj)
+ # Returns the check offset overflow macro call string for a given size.
+ #
+ # size: size to check
def _get_chk_offset_v(self, size):
fmt = '{}_CHK_OFFSET_V({}, {}, {});'
ret = fmt.format(self._prefix.upper(), self._CTX_AT,
return ret
+ # Returns the check offset overflow macro call C line for a given size.
+ #
+ # size: size to check
def _get_chk_offset_v_cline(self, size):
return _CLine(self._get_chk_offset_v(size))
+ # Returns the offset alignment macro call string for a given alignment.
+ #
+ # size: new alignment
def _get_align_offset(self, align):
fmt = '{}_ALIGN_OFFSET({}, {});'
ret = fmt.format(self._prefix.upper(), self._CTX_AT, align)
return ret
+ # Returns the offset alignment macro call C line for a given alignment.
+ #
+ # size: new alignment
def _get_align_offset_cline(self, size):
return _CLine(self._get_align_offset(size))
+ # Converts a C source string with newlines to an array of C lines and
+ # returns it.
+ #
+ # s: C source string
def _str_to_clines(self, s):
lines = s.split('\n')
return [_CLine(line) for line in lines]
+ # Fills a given template with values and returns its C lines. The `prefix`
+ # and `ucprefix` template variable are automatically provided using the
+ # generator's context.
+ #
+ # tmpl: template
+ # kwargs: additional template variable values
def _template_to_clines(self, tmpl, **kwargs):
s = tmpl.format(prefix=self._prefix, ucprefix=self._prefix.upper(),
**kwargs)
return self._str_to_clines(s)
- def _write_field_struct(self, fname, src_name, struct, scope_prefix):
+ # Returns the C lines for writing a TSDL structure field.
+ #
+ # fname: field name
+ # src_name: C source pointer
+ # struct: TSDL structure
+ def _write_field_struct(self, fname, src_name, struct, scope_prefix=None):
size = self._get_struct_size(struct)
size_bytes = self._get_alignment(size, 8) // 8
dst = self._CTX_BUF_AT_ADDR
_CLine('{} += {};'.format(self._CTX_AT, size)),
]
+ # Returns the C lines for writing a TSDL integer field.
+ #
+ # fname: field name
+ # src_name: C source integer
+ # integer: TSDL integer
def _write_field_integer(self, fname, src_name, integer, scope_prefix=None):
- bo = self._bo_suffixes_map[integer.byte_order]
+ bo = self._BO_SUFFIXES_MAP[integer.byte_order]
t = self._get_obj_param_ctype(integer)
length = self._get_obj_size(integer)
sz=length, bo=bo, type=t,
src_name=src_name)
+ # Returns the C lines for writing a TSDL enumeration field.
+ #
+ # fname: field name
+ # src_name: C source integer
+ # enum: TSDL enumeration
def _write_field_enum(self, fname, src_name, enum, scope_prefix=None):
return self._write_field_obj(fname, src_name, enum.integer)
+ # Returns the C lines for writing a TSDL floating point number field.
+ #
+ # fname: field name
+ # src_name: C source pointer
+ # floating_point: TSDL floating point number
def _write_field_floating_point(self, fname, src_name, floating_point,
scope_prefix=None):
- bo = self._bo_suffixes_map[floating_point.byte_order]
+ bo = self._BO_SUFFIXES_MAP[floating_point.byte_order]
t = self._get_obj_param_ctype(floating_point)
length = self._get_obj_size(floating_point)
sz=length, bo=bo, type=t,
src_name=src_name)
+ # Returns the C lines for writing a TSDL array field.
+ #
+ # fname: field name
+ # src_name: C source pointer
+ # struct: TSDL array
def _write_field_array(self, fname, src_name, array, scope_prefix=None):
clines = []
return clines
+ # Returns a trace packet header C source name out of a sequence length
+ # expression.
+ #
+ # length: sequence length expression
def _get_tph_src_name(self, length):
offvar = self._get_offvar_name_from_expr(length[3:], 'tph')
return 'ctx->{}'.format(offvar)
+ # Returns an environment C source name out of a sequence length
+ # expression.
+ #
+ # length: sequence length expression
def _get_env_src_name(self, length):
if len(length) != 2:
_perror('invalid sequence length: "{}"'.format(self._dot_name_to_str(length)))
return str(self._doc.env[fname])
+ # Returns a stream packet context C source name out of a sequence length
+ # expression.
+ #
+ # length: sequence length expression
def _get_spc_src_name(self, length):
offvar = self._get_offvar_name_from_expr(length[3:], 'spc')
return 'ctx->{}'.format(offvar)
+ # Returns a stream event header C source name out of a sequence length
+ # expression.
+ #
+ # length: sequence length expression
def _get_seh_src_name(self, length):
return self._get_offvar_name_from_expr(length[3:], 'seh')
+ # Returns a stream event context C source name out of a sequence length
+ # expression.
+ #
+ # length: sequence length expression
def _get_sec_src_name(self, length):
return self._get_offvar_name_from_expr(length[3:], 'sec')
+ # Returns an event context C source name out of a sequence length
+ # expression.
+ #
+ # length: sequence length expression
def _get_ec_src_name(self, length):
return self._get_offvar_name_from_expr(length[2:], 'ec')
+ # Returns an event fields C source name out of a sequence length
+ # expression.
+ #
+ # length: sequence length expression
def _get_ef_src_name(self, length):
return self._get_offvar_name_from_expr(length[2:], 'ef')
- def _seq_length_to_src_name(self, length, scope_prefix=None):
+ # Returns a C source name out of a sequence length expression.
+ #
+ # length: sequence length expression
+ # scope_prefix: preferred scope prefix
+ def _get_seq_length_src_name(self, length, scope_prefix=None):
length_dot = self._dot_name_to_str(length)
for prefix, get_src_name in self._get_src_name_funcs.items():
return self._get_offvar_name_from_expr(length, scope_prefix)
+ # Returns the C lines for writing a TSDL sequence field.
+ #
+ # fname: field name
+ # src_name: C source pointer
+ # sequence: TSDL sequence
+ # scope_prefix: preferred scope prefix
def _write_field_sequence(self, fname, src_name, sequence, scope_prefix):
clines = []
clines.append(_CLine('uint32_t {};'.format(iv)))
# sequence length offset variable
- length_offvar = self._seq_length_to_src_name(sequence.length,
+ length_offvar = self._get_seq_length_src_name(sequence.length,
scope_prefix)
# for loop using sequence's static length
return clines
+ # Returns the C lines for writing a TSDL string field.
+ #
+ # fname: field name
+ # src_name: C source pointer
+ # string: TSDL string
def _write_field_string(self, fname, src_name, string, scope_prefix=None):
clines = []
return clines
+ # Returns the C lines for writing a TSDL type field.
+ #
+ # fname: field name
+ # src_name: C source pointer
+ # ftype: TSDL type
+ # scope_prefix: preferred scope prefix
def _write_field_obj(self, fname, src_name, ftype, scope_prefix):
return self._write_field_obj_cb[type(ftype)](fname, src_name, ftype,
scope_prefix)
+ # Returns an offset variable name out of an offset name.
+ #
+ # name: offset name
+ # prefix: offset variable name prefix
def _get_offvar_name(self, name, prefix=None):
parts = ['off']
return '_'.join(parts)
+ # Returns an offset variable name out of an expression (array of
+ # strings).
+ #
+ # expr: array of strings
+ # prefix: offset variable name prefix
def _get_offvar_name_from_expr(self, expr, prefix=None):
return self._get_offvar_name('_'.join(expr), prefix)
+ # Returns the C lines for writing a TSDL field.
+ #
+ # fname: field name
+ # ftype: TSDL field type
+ # scope_name: scope name
+ # scope_prefix: preferred scope prefix
+ # param_name_cb: callback to get the C parameter name out of the
+ # field name
def _field_to_clines(self, fname, ftype, scope_name, scope_prefix,
param_name_cb):
clines = []
# group comment
fmt = '/* write {}.{} ({}) */'
line = fmt.format(scope_name, fname,
- self._tsdl_type_names_map[type(ftype)])
+ self._TSDL_TYPE_NAMES_MAP[type(ftype)])
clines.append(_CLine(line))
# align bit index before writing to the buffer
return clines
+ # Joins C line groups and returns C lines.
+ #
+ # cline_groups: C line groups to join
def _join_cline_groups(self, cline_groups):
if not cline_groups:
return cline_groups
return output_clines
+ # Returns the C lines for writing a complete TSDL structure (top level
+ # scope).
+ #
+ # struct: TSDL structure
+ # scope_name: scope name
+ # scope_prefix: preferred scope prefix
+ # param_name_cb: callback to get the C parameter name out of the
+ # field name
def _struct_to_clines(self, struct, scope_name, scope_prefix,
param_name_cb):
cline_groups = []
return self._join_cline_groups(cline_groups)
+ # Returns the offset variables of a TSDL structure.
+ #
+ # struct: TSDL structure
def _get_struct_size_offvars(self, struct):
offvars_tree = collections.OrderedDict()
size = self._get_struct_size(struct, offvars_tree)
return size, offvars
- def _get_ph_size_offvars(self):
+ # Returns the size and offset variables of the current trace packet header.
+ def _get_tph_size_offvars(self):
return self._get_struct_size_offvars(self._doc.trace.packet_header)
- def _get_pc_size_offvars(self, stream):
+ # Returns the size and offset variables of the a stream packet context.
+ #
+ # stream: TSDL stream
+ def _get_spc_size_offvars(self, stream):
return self._get_struct_size_offvars(stream.packet_context)
+ # Returns the C lines for the barectf context C structure entries for
+ # offsets.
+ #
+ # prefix: offset variable names prefix
+ # offvars: offset variables
def _offvars_to_ctx_clines(self, prefix, offvars):
clines = []
return clines
+ # Generates a barectf context C structure.
+ #
+ # stream: TSDL stream
+ # hide_sid: True to hide the stream ID
def _gen_barectf_ctx_struct(self, stream, hide_sid=False):
# get offset variables for both the packet header and packet context
- ph_size, ph_offvars = self._get_ph_size_offvars()
- pc_size, pc_offvars = self._get_pc_size_offvars(stream)
- clines = self._offvars_to_ctx_clines('tph', ph_offvars)
- clines += self._offvars_to_ctx_clines('spc', pc_offvars)
+ tph_size, tph_offvars = self._get_tph_size_offvars()
+ spc_size, spc_offvars = self._get_spc_size_offvars(stream)
+ clines = self._offvars_to_ctx_clines('tph', tph_offvars)
+ clines += self._offvars_to_ctx_clines('spc', spc_offvars)
# indent C
clines_indented = []
clock_cb = '\t/* (no clock callback) */'
if not self._manual_clock:
- ctype = self._get_clock_type(stream)
+ ctype = self._get_clock_ctype(stream)
fmt = '\t{} (*clock_cb)(void*),\n\tvoid* clock_cb_data;'
clock_cb = fmt.format(ctype)
return struct
+ # Generates all barectf context C structures.
def _gen_barectf_contexts_struct(self):
hide_sid = False
return '\n\n'.join(structs)
- _packet_context_known_fields = [
- 'content_size',
- 'packet_size',
- 'timestamp_begin',
- 'timestamp_end',
- ]
-
- def _get_clock_type(self, stream):
+ # Returns the C type of the clock used by the event header of a
+ # TSDL stream.
+ #
+ # stream: TSDL stream containing the event header to inspect
+ def _get_clock_ctype(self, stream):
return self._get_obj_param_ctype(stream.event_header['timestamp'])
+ # Generates the manual clock value C parameter for a given stream.
+ #
+ # stream: TSDL stream
def _gen_manual_clock_param(self, stream):
- return '{} param_clock'.format(self._get_clock_type(stream))
+ return '{} param_clock'.format(self._get_clock_ctype(stream))
+ # Generates the body of a barectf_open() function.
+ #
+ # stream: TSDL stream
def _gen_barectf_func_open_body(self, stream):
clines = []
# keep clock value (for timestamp_begin)
if self._stream_has_timestamp_begin_end(stream):
# get clock value ASAP
- clk_type = self._get_clock_type(stream)
+ clk_type = self._get_clock_ctype(stream)
clk = self._gen_get_clock_value()
line = '{} clk_value = {};'.format(clk_type, clk)
clines.append(_CLine(line))
return src
+ _SPC_KNOWN_FIELDS = [
+ 'content_size',
+ 'packet_size',
+ 'timestamp_begin',
+ 'timestamp_end',
+ ]
+
+ # Generates a barectf_open() function.
+ #
+ # stream: TSDL stream
+ # gen_body: also generate function body
+ # hide_sid: True to hide the stream ID
def _gen_barectf_func_open(self, stream, gen_body, hide_sid=False):
params = []
# packet context
for fname, ftype in stream.packet_context.fields.items():
- if fname in self._packet_context_known_fields:
+ if fname in self._SPC_KNOWN_FIELDS:
continue
ptype = self._get_obj_param_ctype(ftype)
return func
+ # Generates the body of a barectf_init() function.
+ #
+ # stream: TSDL stream
def _gen_barectf_func_init_body(self, stream):
clines = []
# set context offsets
clines.append(_CLine(''))
clines.append(_CLine("/* barectf context offsets */"))
- ph_size, ph_offvars = self._get_ph_size_offvars()
- pc_size, pc_offvars = self._get_pc_size_offvars(stream)
+ ph_size, ph_offvars = self._get_tph_size_offvars()
+ pc_size, pc_offvars = self._get_spc_size_offvars(stream)
pc_alignment = self._get_obj_alignment(stream.packet_context)
pc_offset = self._get_alignment(ph_size, pc_alignment)
return src
+ # Generates a barectf_init() function.
+ #
+ # stream: TSDL stream
+ # gen_body: also generate function body
+ # hide_sid: True to hide the stream ID
def _gen_barectf_func_init(self, stream, gen_body, hide_sid=False):
# fill template
sid = ''
return func
+ # Generates the C expression to get the clock value depending on
+ # whether we're in manual clock mode or not.
def _gen_get_clock_value(self):
if self._manual_clock:
return 'param_clock'
else:
return self._CTX_CALL_CLOCK_CB
+ # Returns True if the given TSDL stream has timestamp_begin and
+ # timestamp_end fields.
+ #
+ # stream: TSDL stream to check
def _stream_has_timestamp_begin_end(self, stream):
return self._has_timestamp_begin_end[stream.id]
- def _gen_write_ctx_field_integer(self, src_name, prefix, name, obj):
+ # Generates the C lines to write a barectf context field, saving
+ # and restoring the current bit position accordingly.
+ #
+ # src_name: C source name
+ # prefix: offset variable prefix
+ # name: offset variable name
+ # integer: TSDL integer to write
+ def _gen_write_ctx_field_integer(self, src_name, prefix, name, integer):
clines = []
# save buffer position
clines.append(_CLine(line))
# write value
- clines += self._write_field_integer(None, src_name, obj)
+ clines += self._write_field_integer(None, src_name, integer)
# restore buffer position
line = '{} = ctx_at_bkup;'.format(self._CTX_AT)
return clines
+ # Generates the body of a barectf_close() function.
+ #
+ # stream: TSDL stream
def _gen_barectf_func_close_body(self, stream):
clines = []
clines.append(_CLine("/* update packet context's timestamp_end */"))
# get clock value ASAP
- clk_type = self._get_clock_type(stream)
+ clk_type = self._get_clock_ctype(stream)
clk = self._gen_get_clock_value()
line = '{} clk_value = {};'.format(clk_type, clk)
clines.append(_CLine(line))
return src
+ # Generates a barectf_close() function.
+ #
+ # stream: TSDL stream
+ # gen_body: also generate function body
+ # hide_sid: True to hide the stream ID
def _gen_barectf_func_close(self, stream, gen_body, hide_sid=False):
# fill template
sid = ''
return func
+ # Generates all barectf_init() function.
+ #
+ # gen_body: also generate function bodies
def _gen_barectf_funcs_init(self, gen_body):
hide_sid = False
return funcs
+ # Generates all barectf_open() function.
+ #
+ # gen_body: also generate function bodies
def _gen_barectf_funcs_open(self, gen_body):
hide_sid = False
return funcs
+ # Generates the body of a barectf_trace() function.
+ #
+ # stream: TSDL stream of TSDL event to trace
+ # event: TSDL event to trace
def _gen_barectf_func_trace_event_body(self, stream, event):
clines = []
# get clock value ASAP
- clk_type = self._get_clock_type(stream)
+ clk_type = self._get_clock_ctype(stream)
clk = self._gen_get_clock_value()
line = '{} clk_value = {};'.format(clk_type, clk)
clines.append(_CLine(line))
return src
+ # Generates a barectf_trace() function.
+ #
+ # stream: TSDL stream containing the TSDL event to trace
+ # event: TSDL event to trace
+ # gen_body: also generate function body
+ # hide_sid: True to hide the stream ID
def _gen_barectf_func_trace_event(self, stream, event, gen_body, hide_sid):
params = []
return func
+ # Generates all barectf_trace() functions of a given TSDL stream.
+ #
+ # stream: TSDL stream containing the TSDL events to trace
+ # gen_body: also generate function body
+ # hide_sid: True to hide the stream ID
def _gen_barectf_funcs_trace_stream(self, stream, gen_body, hide_sid):
funcs = []
return funcs
+ # Generates all barectf_trace() function.
+ #
+ # gen_body: also generate function bodies
def _gen_barectf_funcs_trace(self, gen_body):
hide_sid = False
return funcs
+ # Generates all barectf_close() function.
+ #
+ # gen_body: also generate function bodies
def _gen_barectf_funcs_close(self, gen_body):
hide_sid = False
return funcs
+ # Generates the barectf header C source
def _gen_barectf_header(self):
ctx_structs = self._gen_barectf_contexts_struct()
init_funcs = self._gen_barectf_funcs_init(self._static_inline)
return header
+ _BO_DEF_MAP = {
+ pytsdl.tsdl.ByteOrder.BE: 'BIG_ENDIAN',
+ pytsdl.tsdl.ByteOrder.LE: 'LITTLE_ENDIAN',
+ }
+
+ # Generates the barectf bitfield.h header.
+ def _gen_barectf_bitfield_header(self):
+ header = barectf.templates.BITFIELD
+ header = header.replace('$prefix$', self._prefix)
+ header = header.replace('$PREFIX$', self._prefix.upper())
+ endian_def = self._BO_DEF_MAP[self._doc.trace.byte_order]
+ header = header.replace('$ENDIAN_DEF$', endian_def)
+
+ return header
+
+ # Writes a file to the generator's output.
+ #
+ # name: file name
+ # contents: file contents
+ def _write_file(self, name, contents):
+ with open(os.path.join(self._output, name), 'w') as f:
+ f.write(contents)
+
+ # Converts a C block to actual C source lines.
+ #
+ # cblock: C block
+ # indent: initial indentation
def _cblock_to_source_lines(self, cblock, indent=1):
src = []
indentstr = '\t' * indent
return src
+ # Converts a C block to an actual C source string.
+ #
+ # cblock: C block
+ # indent: initial indentation
def _cblock_to_source(self, cblock, indent=1):
lines = self._cblock_to_source_lines(cblock, indent)
return '\n'.join(lines)
+ # Sets the generator parameters.
def _set_params(self):
+ # streams have timestamp_begin/timestamp_end fields
self._has_timestamp_begin_end = {}
for stream in self._doc.streams.values():
has = 'timestamp_begin' in stream.packet_context.fields
self._has_timestamp_begin_end[stream.id] = has
+ # Generates barectf C files.
+ #
+ # metadata: metadata path
+ # output: output directory
+ # prefix: prefix
+ # static_inline: generate static inline functions
+ # manual_clock: do not use a clock callback: pass clock value to
+ # tracing functions
def gen_barectf(self, metadata, output, prefix, static_inline,
manual_clock):
self._metadata = metadata
# generate header
_pinfo('generating barectf header files')
- self._gen_barectf_header()
+ header = self._gen_barectf_header()
+ self._write_file('{}.h'.format(self._prefix), header)
+ header = self._gen_barectf_bitfield_header()
+ self._write_file('{}_bitfield.h'.format(self._prefix), header)
# generate C source file
if not self._static_inline:
_pinfo('generating barectf translation unit')
+
pass
_psuccess('done')
)"""
WRITE_INTEGER = """{ucprefix}_CHK_OFFSET_V(ctx->at, ctx->buf_size, {sz});
-{prefix}_bitfield_write_{bo}(ctx->buf, {type}, ctx->at, {sz}, {src_name});
+{prefix}_bt_bitfield_write_{bo}(ctx->buf, {type}, ctx->at, {sz}, {src_name});
ctx->at += {sz};"""
HEADER = """#ifndef _{ucprefix}_H
#include <stdint.h>
-#include "{prefix}_bitfields.h"
+#include "{prefix}_bitfield.h"
/* barectf contexts */
{barectf_ctx}
{functions}
"""
+
+BITFIELD = """#ifndef _$PREFIX$_BITFIELD_H
+#define _$PREFIX$_BITFIELD_H
+
+/*
+ * BabelTrace
+ *
+ * Bitfields read/write functions.
+ *
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h> /* C99 5.2.4.2 Numerical limits */
+
+#define $PREFIX$_BYTE_ORDER $ENDIAN_DEF$
+
+/* We can't shift a int from 32 bit, >> 32 and << 32 on int is undefined */
+#define _$prefix$_bt_piecewise_rshift(_v, _shift) \\
+({ \\
+ typeof(_v) ___v = (_v); \\
+ typeof(_shift) ___shift = (_shift); \\
+ unsigned long sb = (___shift) / (sizeof(___v) * CHAR_BIT - 1); \\
+ unsigned long final = (___shift) % (sizeof(___v) * CHAR_BIT - 1); \\
+ \\
+ for (; sb; sb--) \\
+ ___v >>= sizeof(___v) * CHAR_BIT - 1; \\
+ ___v >>= final; \\
+})
+
+#define _$prefix$_bt_piecewise_lshift(_v, _shift) \\
+({ \\
+ typeof(_v) ___v = (_v); \\
+ typeof(_shift) ___shift = (_shift); \\
+ unsigned long sb = (___shift) / (sizeof(___v) * CHAR_BIT - 1); \\
+ unsigned long final = (___shift) % (sizeof(___v) * CHAR_BIT - 1); \\
+ \\
+ for (; sb; sb--) \\
+ ___v <<= sizeof(___v) * CHAR_BIT - 1; \\
+ ___v <<= final; \\
+})
+
+#define _$prefix$_bt_is_signed_type(type) ((type) -1 < (type) 0)
+
+#define _$prefix$_bt_unsigned_cast(type, v) \\
+({ \\
+ (sizeof(v) < sizeof(type)) ? \\
+ ((type) (v)) & (~(~(type) 0 << (sizeof(v) * CHAR_BIT))) : \\
+ (type) (v); \\
+})
+
+/*
+ * $prefix$_bt_bitfield_write - write integer to a bitfield in native endianness
+ *
+ * Save integer to the bitfield, which starts at the "start" bit, has "len"
+ * bits.
+ * The inside of a bitfield is from high bits to low bits.
+ * Uses native endianness.
+ * For unsigned "v", pad MSB with 0 if bitfield is larger than v.
+ * For signed "v", sign-extend v if bitfield is larger than v.
+ *
+ * On little endian, bytes are placed from the less significant to the most
+ * significant. Also, consecutive bitfields are placed from lower bits to higher
+ * bits.
+ *
+ * On big endian, bytes are places from most significant to less significant.
+ * Also, consecutive bitfields are placed from higher to lower bits.
+ */
+
+#define _$prefix$_bt_bitfield_write_le(_ptr, type, _start, _length, _v) \\
+do { \\
+ typeof(_v) __v = (_v); \\
+ type *__ptr = (void *) (_ptr); \\
+ unsigned long __start = (_start), __length = (_length); \\
+ type mask, cmask; \\
+ unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \\
+ unsigned long start_unit, end_unit, this_unit; \\
+ unsigned long end, cshift; /* cshift is "complement shift" */ \\
+ \\
+ if (!__length) \\
+ break; \\
+ \\
+ end = __start + __length; \\
+ start_unit = __start / ts; \\
+ end_unit = (end + (ts - 1)) / ts; \\
+ \\
+ /* Trim v high bits */ \\
+ if (__length < sizeof(__v) * CHAR_BIT) \\
+ __v &= ~((~(typeof(__v)) 0) << __length); \\
+ \\
+ /* We can now append v with a simple "or", shift it piece-wise */ \\
+ this_unit = start_unit; \\
+ if (start_unit == end_unit - 1) { \\
+ mask = ~((~(type) 0) << (__start % ts)); \\
+ if (end % ts) \\
+ mask |= (~(type) 0) << (end % ts); \\
+ cmask = (type) __v << (__start % ts); \\
+ cmask &= ~mask; \\
+ __ptr[this_unit] &= mask; \\
+ __ptr[this_unit] |= cmask; \\
+ break; \\
+ } \\
+ if (__start % ts) { \\
+ cshift = __start % ts; \\
+ mask = ~((~(type) 0) << cshift); \\
+ cmask = (type) __v << cshift; \\
+ cmask &= ~mask; \\
+ __ptr[this_unit] &= mask; \\
+ __ptr[this_unit] |= cmask; \\
+ __v = _$prefix$_bt_piecewise_rshift(__v, ts - cshift); \\
+ __start += ts - cshift; \\
+ this_unit++; \\
+ } \\
+ for (; this_unit < end_unit - 1; this_unit++) { \\
+ __ptr[this_unit] = (type) __v; \\
+ __v = _$prefix$_bt_piecewise_rshift(__v, ts); \\
+ __start += ts; \\
+ } \\
+ if (end % ts) { \\
+ mask = (~(type) 0) << (end % ts); \\
+ cmask = (type) __v; \\
+ cmask &= ~mask; \\
+ __ptr[this_unit] &= mask; \\
+ __ptr[this_unit] |= cmask; \\
+ } else \\
+ __ptr[this_unit] = (type) __v; \\
+} while (0)
+
+#define _$prefix$_bt_bitfield_write_be(_ptr, type, _start, _length, _v) \\
+do { \\
+ typeof(_v) __v = (_v); \\
+ type *__ptr = (void *) (_ptr); \\
+ unsigned long __start = (_start), __length = (_length); \\
+ type mask, cmask; \\
+ unsigned long ts = sizeof(type) * CHAR_BIT; /* type size */ \\
+ unsigned long start_unit, end_unit, this_unit; \\
+ unsigned long end, cshift; /* cshift is "complement shift" */ \\
+ \\
+ if (!__length) \\
+ break; \\
+ \\
+ end = __start + __length; \\
+ start_unit = __start / ts; \\
+ end_unit = (end + (ts - 1)) / ts; \\
+ \\
+ /* Trim v high bits */ \\
+ if (__length < sizeof(__v) * CHAR_BIT) \\
+ __v &= ~((~(typeof(__v)) 0) << __length); \\
+ \\
+ /* We can now append v with a simple "or", shift it piece-wise */ \\
+ this_unit = end_unit - 1; \\
+ if (start_unit == end_unit - 1) { \\
+ mask = ~((~(type) 0) << ((ts - (end % ts)) % ts)); \\
+ if (__start % ts) \\
+ mask |= (~((type) 0)) << (ts - (__start % ts)); \\
+ cmask = (type) __v << ((ts - (end % ts)) % ts); \\
+ cmask &= ~mask; \\
+ __ptr[this_unit] &= mask; \\
+ __ptr[this_unit] |= cmask; \\
+ break; \\
+ } \\
+ if (end % ts) { \\
+ cshift = end % ts; \\
+ mask = ~((~(type) 0) << (ts - cshift)); \\
+ cmask = (type) __v << (ts - cshift); \\
+ cmask &= ~mask; \\
+ __ptr[this_unit] &= mask; \\
+ __ptr[this_unit] |= cmask; \\
+ __v = _$prefix$_bt_piecewise_rshift(__v, cshift); \\
+ end -= cshift; \\
+ this_unit--; \\
+ } \\
+ for (; (long) this_unit >= (long) start_unit + 1; this_unit--) { \\
+ __ptr[this_unit] = (type) __v; \\
+ __v = _$prefix$_bt_piecewise_rshift(__v, ts); \\
+ end -= ts; \\
+ } \\
+ if (__start % ts) { \\
+ mask = (~(type) 0) << (ts - (__start % ts)); \\
+ cmask = (type) __v; \\
+ cmask &= ~mask; \\
+ __ptr[this_unit] &= mask; \\
+ __ptr[this_unit] |= cmask; \\
+ } else \\
+ __ptr[this_unit] = (type) __v; \\
+} while (0)
+
+/*
+ * $prefix$_bt_bitfield_write - write integer to a bitfield in native endianness
+ * $prefix$_bt_bitfield_write_le - write integer to a bitfield in little endian
+ * $prefix$_bt_bitfield_write_be - write integer to a bitfield in big endian
+ */
+
+#if ($PREFIX$_BYTE_ORDER == LITTLE_ENDIAN)
+
+#define $prefix$_bt_bitfield_write(ptr, type, _start, _length, _v) \\
+ _$prefix$_bt_bitfield_write_le(ptr, type, _start, _length, _v)
+
+#define $prefix$_bt_bitfield_write_le(ptr, type, _start, _length, _v) \\
+ _$prefix$_bt_bitfield_write_le(ptr, type, _start, _length, _v)
+
+#define $prefix$_bt_bitfield_write_be(ptr, type, _start, _length, _v) \\
+ _$prefix$_bt_bitfield_write_be(ptr, unsigned char, _start, _length, _v)
+
+#elif ($PREFIX$_BYTE_ORDER == BIG_ENDIAN)
+
+#define $prefix$_bt_bitfield_write(ptr, type, _start, _length, _v) \\
+ _$prefix$_bt_bitfield_write_be(ptr, type, _start, _length, _v)
+
+#define $prefix$_bt_bitfield_write_le(ptr, type, _start, _length, _v) \\
+ _$prefix$_bt_bitfield_write_le(ptr, unsigned char, _start, _length, _v)
+
+#define $prefix$_bt_bitfield_write_be(ptr, type, _start, _length, _v) \\
+ _$prefix$_bt_bitfield_write_be(ptr, type, _start, _length, _v)
+
+#else /* ($PREFIX$_BYTE_ORDER == PDP_ENDIAN) */
+
+#error "Byte order not supported"
+
+#endif
+
+#endif /* _$PREFIX$_BITFIELD_H */
+"""