pco, pygen: define and emit isa instruction group header variant fields

Signed-off-by: Simon Perretta <simon.perretta@imgtec.com>
Acked-by: Frank Binns <frank.binns@imgtec.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/32258>
This commit is contained in:
Simon Perretta 2024-05-10 05:25:35 +01:00 committed by Marge Bot
parent ee312ebd6f
commit 4ca21e7038
4 changed files with 353 additions and 19 deletions

View file

@ -35,15 +35,17 @@ enum ${enum.name} {
};
% endfor
/** Sub-enums. */
% for enum in [enum for enum in enums.values() if enum.parent is not None]:
#define ${enum.name} ${enum.parent.name}
% for bit_set in bit_sets.values():
enum ${bit_set.name}_variant {
% for variant in bit_set.variants:
${variant},
% endfor
};
% endfor
#endif /* PCO_COMMON_H */"""
def main():
print(Template(template).render(enums=enums))
print(Template(template).render(enums=enums, bit_sets=bit_sets))
if __name__ == '__main__':
main()

View file

@ -19,14 +19,26 @@ template = """/*
* \\brief PCO ISA definitions.
*/
#include "pco_common.h"
#include "util/macros.h"
#include <stdbool.h>
% for _bit_set_name, bit_set in bit_sets.items():
/** ${_bit_set_name} */
% for bit_struct in bit_set.bit_structs.values():
struct ${bit_struct.name} {
% for type, field, bits in bit_struct.struct_fields.values():
${type} ${field} : ${bits};
% endfor
};
% endfor
% endfor
#endif /* PCO_ISA_H */"""
def main():
print(Template(template).render())
print(Template(template).render(bit_sets=bit_sets))
if __name__ == '__main__':
main()

View file

@ -38,3 +38,173 @@ F_UINT4_POS_WRAP = field_type('uint4_pos_wrap', BaseType.uint, 4, dec_bits=5, ch
F_OFFSET31 = field_type('offset31', BaseType.uint, 31, dec_bits=32, check='!(val & 0b1)', encode='val >> 1')
## 8-bit value; lowest 2 bits == 0b00.
F_UINT6MUL4 = field_type('uint6mul4', BaseType.uint, 6, dec_bits=8, check='!(val & 0b11)', encode='val >> 2')
# Instruction group header definitions.
F_OPORG = field_enum_type(
name='oporg', num_bits=3,
elems=[
('p0', 0b000),
('p2', 0b001),
('be', 0b010),
('p0_p1', 0b011),
('p0_p2', 0b100),
('p0_p1_p2', 0b101),
('p0_p2_be', 0b110),
('p0_p1_p2_be', 0b111),
])
F_OPCNT = field_enum_type(
name='opcnt', num_bits=3,
elems=[
('p0', 0b001),
('p1', 0b010),
('p2', 0b100),
], is_bitset=True)
F_CC = field_enum_type(
name='cc', num_bits=2,
elems=[
('e1_zx', 0b00),
('e1_z1', 0b01),
('ex_zx', 0b10),
('e1_z0', 0b11),
])
F_CC1 = field_enum_subtype(name='cc1', parent=F_CC, num_bits=1)
F_ALUTYPE = field_enum_type(
name='alutype', num_bits=2,
elems=[
('main', 0b00),
('bitwise', 0b10),
('control', 0b11),
])
F_CTRLOP = field_enum_type(
name='ctrlop', num_bits=4,
elems=[
('b', 0b0000),
('lapc', 0b0001),
('savl', 0b0010),
('cnd', 0b0011),
('wop', 0b0100),
('wdf', 0b0101),
('mutex', 0b0110),
('nop', 0b0111),
('itrsmp', 0b1000),
('sbo', 0b1011),
])
I_IGRP_HDR = bit_set(
name='igrp_hdr',
pieces=[
('da', (0, '7:4')),
('length', (0, '3:0')),
('ext', (1, '7')),
('oporg', (1, '6:4')),
('opcnt', (1, '6:4')),
('olchk', (1, '3')),
('w1p', (1, '2')),
('w0p', (1, '1')),
('cc', (1, '0')),
('end', (2, '7')),
('alutype', (2, '6:5')),
('rsvd', (2, '4')),
('atom', (2, '3')),
('rpt', (2, '2:1')),
('ccext', (2, '0')),
('miscctl', (2, '7')),
('ctrlop', (2, '4:1')),
],
fields=[
('da', (F_UINT4, ['da'])),
('length', (F_UINT4_POS_WRAP, ['length'])),
('ext', (F_BOOL, ['ext'])),
('oporg', (F_OPORG, ['oporg'])),
('opcnt', (F_OPCNT, ['opcnt'])),
('olchk', (F_BOOL, ['olchk'])),
('w1p', (F_BOOL, ['w1p'])),
('w0p', (F_BOOL, ['w0p'])),
('cc1', (F_CC1, ['cc'])),
('end', (F_BOOL, ['end'])),
('alutype', (F_ALUTYPE, ['alutype'])),
('rsvd', (F_UINT1, ['rsvd'], 0)),
('atom', (F_BOOL, ['atom'])),
('rpt', (F_UINT2_POS_INC, ['rpt'])),
('cc', (F_CC, ['ccext', 'cc'])),
('miscctl', (F_UINT1, ['miscctl'])),
('ctrlop', (F_CTRLOP, ['ctrlop'])),
])
I_IGRP_HDR_MAIN_BRIEF = bit_struct(
name='main_brief',
bit_set=I_IGRP_HDR,
field_mappings=[
'da',
'length',
('ext', 'ext', False),
'oporg',
'olchk',
'w1p',
'w0p',
('cc', 'cc1'),
])
I_IGRP_HDR_MAIN = bit_struct(
name='main',
bit_set=I_IGRP_HDR,
field_mappings=[
'da',
'length',
('ext', 'ext', True),
'oporg',
'olchk',
'w1p',
'w0p',
'cc',
'end',
('alutype', 'alutype', 'main'),
'rsvd',
'atom',
'rpt',
])
I_IGRP_HDR_BITWISE = bit_struct(
name='bitwise',
bit_set=I_IGRP_HDR,
field_mappings=[
'da',
'length',
('ext', 'ext', True),
'opcnt',
'olchk',
'w1p',
'w0p',
'cc',
'end',
('alutype', 'alutype', 'bitwise'),
'rsvd',
'atom',
'rpt',
])
I_IGRP_HDR_CONTROL = bit_struct(
name='control',
bit_set=I_IGRP_HDR,
field_mappings=[
'da',
'length',
('ext', 'ext', True),
('opcnt', 'opcnt', 0),
'olchk',
'w1p',
'w0p',
'cc',
'miscctl',
('alutype', 'alutype', 'control'),
'ctrlop',
])

View file

@ -7,13 +7,16 @@ _ = None
prefix = 'pco'
def val_fits_in_bits(val, num_bits):
return val < pow(2, num_bits)
class BaseType(Enum):
bool = auto()
uint = auto()
enum = auto()
class Type(object):
def __init__(self, name, base_type, num_bits, dec_bits, check, encode, nzdefault, print_early):
def __init__(self, name, base_type, num_bits, dec_bits, check, encode, nzdefault, print_early, enum):
self.name = name
self.base_type = base_type
self.num_bits = num_bits
@ -22,12 +25,23 @@ class Type(object):
self.encode = encode
self.nzdefault = nzdefault
self.print_early = print_early
self.enum = enum
types = {}
def type(name, base_type, num_bits=None, dec_bits=None, check=None, encode=None, nzdefault=None, print_early=False):
def type(name, base_type, num_bits=None, dec_bits=None, check=None, encode=None, nzdefault=None, print_early=False, enum=None):
assert name not in types.keys(), f'Duplicate type "{name}".'
t = Type(name, base_type, num_bits, dec_bits, check, encode, nzdefault, print_early)
if base_type == BaseType.bool:
_name = 'bool'
elif base_type == BaseType.uint:
_name = 'unsigned'
elif base_type == BaseType.enum:
_name = f'enum {prefix}_{name}'
else:
assert False, f'Invalid base type for type {name}.'
t = Type(_name, base_type, num_bits, dec_bits, check, encode, nzdefault, print_early, enum)
types[name] = t
return t
@ -42,9 +56,6 @@ class EnumType(object):
self.parent = parent
enums = {}
def val_fits_in_bits(val, num_bits):
return val < pow(2, num_bits)
def enum_type(name, elems, is_bitset=False, num_bits=None, *args, **kwargs):
assert name not in enums.keys(), f'Duplicate enum "{name}".'
@ -86,21 +97,22 @@ def enum_type(name, elems, is_bitset=False, num_bits=None, *args, **kwargs):
_name = f'{prefix}_{name}'
_valid = _valid_valmask if is_bitset else _valid_vals
_unique_count = bin(_valid_valmask).count('1') if is_bitset else len(_valid_vals)
enums[name] = EnumType(_name, _elems, _valid, _unique_count, is_bitset, parent=None)
enum = EnumType(_name, _elems, _valid, _unique_count, is_bitset, parent=None)
enums[name] = enum
return type(name, BaseType.enum, num_bits, *args, **kwargs)
return type(name, BaseType.enum, num_bits, *args, **kwargs, enum=enum)
def enum_subtype(name, parent, num_bits):
assert name not in enums.keys(), f'Duplicate enum "{name}".'
assert parent.name in enums.keys()
enum_parent = enums[parent.name]
assert not enum_parent.is_bitset
assert parent.enum is not None
assert not parent.enum.is_bitset
assert parent.num_bits is not None and parent.num_bits > num_bits
_name = f'{prefix}_{name}'
enums[name] = EnumType(_name, None, None, None, False, enum_parent)
return type(name, BaseType.enum, num_bits)
enum = EnumType(_name, None, None, None, False, parent)
enums[name] = enum
return type(name, BaseType.enum, num_bits, enum=enum)
# Type specializations.
@ -162,3 +174,141 @@ def ref_mod_enum(name, *args, **kwargs):
ref_mod_enums[name] = enums[name]
assert len(ref_mods) <= 64, 'Too many ref mods!'
return t
# Bit encoding definition helpers.
class BitPiece(object):
def __init__(self, name, byte, hi_bit, lo_bit, num_bits):
self.name = name
self.byte = byte
self.hi_bit = hi_bit
self.lo_bit = lo_bit
self.num_bits = num_bits
def bit_piece(name, byte, bit_range):
assert bit_range.count(':') <= 1, f'Invalid bit range specification in bit piece {name}.'
is_one_bit = not bit_range.count(':')
split_range = [bit_range, bit_range] if is_one_bit else bit_range.split(':', 1)
(hi_bit, lo_bit) = list(map(int, split_range))
assert hi_bit < 8 and hi_bit >= 0 and lo_bit < 8 and lo_bit >= 0 and hi_bit >= lo_bit
_num_bits = hi_bit - lo_bit + 1
return BitPiece(name, byte, hi_bit, lo_bit, _num_bits)
class BitField(object):
def __init__(self, name, field_type, pieces, reserved):
self.name = name
self.field_type = field_type
self.pieces = pieces
self.reserved = reserved
def bit_field(name, bit_set_pieces, field_type, pieces, reserved=None):
_pieces = [bit_set_pieces[p] for p in pieces]
total_bits = sum([p.num_bits for p in _pieces])
assert total_bits == field_type.num_bits, f'Expected {field_type.num_bits}, got {total_bits} in bit field {name}.'
if reserved is not None:
assert val_fits_in_bits(reserved, total_bits), f'Reserved value for bit field {name} is too large.'
return BitField(name, field_type, _pieces, reserved)
class BitSet(object):
def __init__(self, name, pieces, fields):
self.name = name
self.pieces = pieces
self.fields = fields
self.bit_structs = {}
self.variants = []
bit_sets = {}
def bit_set(name, pieces, fields):
assert name not in bit_sets.keys(), f'Duplicate bit set "{name}".'
_pieces = {}
for (piece, spec) in pieces:
assert piece not in _pieces.keys(), f'Duplicate bit piece "{n}" in bit set "{name}".'
_pieces[piece] = bit_piece(piece, *spec)
_fields = {}
for (field, spec) in fields:
assert field not in _fields.keys(), f'Duplicate bit field "{n}" in bit set "{name}".'
_fields[field] = bit_field(field, _pieces, *spec)
_name = f'{prefix}_{name}'
bs = BitSet(_name, _pieces, _fields)
bit_sets[name] = bs
return bs
class BitStruct(object):
def __init__(self, name, struct_fields, num_bytes):
self.name = name
self.struct_fields = struct_fields
self.num_bytes = num_bytes
def bit_struct(name, bit_set, field_mappings):
assert name not in bit_set.bit_structs.keys(), f'Duplicate bit struct "{name}" in bit set "{bit_set.name}".'
struct_fields = {}
all_pieces = []
total_bits = 0
for mapping in field_mappings:
if isinstance(mapping, str):
struct_field = mapping
_field = mapping
fixed_value = None
else:
assert isinstance(mapping, tuple)
struct_field, _field, *fixed_value = mapping
assert len(fixed_value) == 0 or len(fixed_value) == 1
fixed_value = None if len(fixed_value) == 0 else fixed_value[0]
assert struct_field not in struct_fields.keys(), f'Duplicate struct field "{struct_field}" in bit struct "{name}".'
assert _field in bit_set.fields.keys(), f'Field "{_field}" in mapping for struct field "{name}.{struct_field}" not defined in bit set "{bit_set.name}".'
field = bit_set.fields[_field]
field_type = field.field_type
is_enum = field_type.base_type == BaseType.enum
if fixed_value is not None:
assert field.reserved is None, f'Fixed value for field mapping "{struct_field}" using field "{_field}" cannot overwrite its reserved value.'
if is_enum and isinstance(fixed_value, str):
enum = field_type.enum
assert fixed_value in enum.elems.keys(), f'Fixed value for field mapping "{struct_field}" using field "{_field}" is not an element of enum {field_type.name}.'
fixed_value = f'{prefix}_{field_type.name}_{fixed_value}'.upper()
else:
if isinstance(fixed_value, bool):
fixed_value = int(fixed_value)
assert isinstance(fixed_value, int)
assert val_fits_in_bits(fixed_value, field_type.num_bits), f'Fixed value for field mapping "{struct_field}" using field "{_field}" is too large.'
all_pieces.extend([(piece.lo_bit + (8 * piece.byte), piece.hi_bit + (8 * piece.byte), piece.name) for piece in field.pieces])
total_bits += field_type.num_bits
if field.reserved is None and fixed_value is None:
# Use parent enum for struct fields.
if is_enum and field_type.enum.parent is not None:
field_type = field_type.enum.parent
struct_field_bits = field_type.dec_bits if field_type.dec_bits is not None else field_type.num_bits
struct_fields[struct_field] = (field_type.name, struct_field, struct_field_bits)
# Check for overlapping pieces.
for p0 in all_pieces:
for p1 in all_pieces:
if p0 == p1:
continue
assert p0[1] < p1[0] or p0[0] > p1[1], f'Pieces "{p0[2]}" and "{p1[2]}" overlap in bit struct "{name}".'
# Check for byte-alignment.
assert (total_bits % 8) == 0, f'Bit struct "{name}" has a non-byte-aligned number of bits ({total_bits}).'
_name = f'{bit_set.name}_{name}'
bs = BitStruct(_name, struct_fields, total_bits // 8)
bit_set.bit_structs[name] = bs
bit_set.variants.append(f'{bit_set.name}_{name}'.upper())
return bs