diff --git a/src/imagination/pco/pco_common.h.py b/src/imagination/pco/pco_common.h.py index d51eb511553..4147d404a96 100644 --- a/src/imagination/pco/pco_common.h.py +++ b/src/imagination/pco/pco_common.h.py @@ -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() diff --git a/src/imagination/pco/pco_isa.h.py b/src/imagination/pco/pco_isa.h.py index 083b0c8d382..8f8c300e2b0 100644 --- a/src/imagination/pco/pco_isa.h.py +++ b/src/imagination/pco/pco_isa.h.py @@ -19,14 +19,26 @@ template = """/* * \\brief PCO ISA definitions. */ +#include "pco_common.h" #include "util/macros.h" #include +% 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() diff --git a/src/imagination/pco/pco_isa.py b/src/imagination/pco/pco_isa.py index 73295cfcb96..01d9c922355 100644 --- a/src/imagination/pco/pco_isa.py +++ b/src/imagination/pco/pco_isa.py @@ -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', +]) diff --git a/src/imagination/pco/pco_pygen_common.py b/src/imagination/pco/pco_pygen_common.py index 88004d95b75..a330f8b1e1e 100644 --- a/src/imagination/pco/pco_pygen_common.py +++ b/src/imagination/pco/pco_pygen_common.py @@ -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