mesa/src/imagination/pco/pco_map.h.py
Simon Perretta 58337957ac pco, pygen: restructure igrp alu components into arrays
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>
2024-11-29 15:14:12 +00:00

512 lines
15 KiB
Python

# Copyright © 2024 Imagination Technologies Ltd.
# SPDX-License-Identifier: MIT
from mako.template import Template, exceptions
from pco_map import *
template = """/*
* Copyright © 2024 Imagination Technologies Ltd.
*
* SPDX-License-Identifier: MIT
*/
#ifndef PCO_MAP_H
#define PCO_MAP_H
/**
* \\file pco_map.h
*
* \\brief PCO mapping definitions.
*/
#include "pco_builder.h"
#include "pco_common.h"
#include "pco_internal.h"
#include "pco_isa.h"
#include "pco_ops.h"
#include "util/macros.h"
#include <stdbool.h>
/* Enum mappings. */
% for enum_map in enum_maps.values():
static inline
${enum_map.type_to} ${enum_map.name}(${enum_map.type_from} val)
{
switch (val) {
% for elem_from, elem_to in enum_map.mappings:
case ${elem_from}:
return ${elem_to};
% endfor
default: break;
}
unreachable();
}
% endfor
static inline
enum pco_regbank pco_map_reg_bank(pco_ref ref)
{
enum pco_regbank regbank = pco_map_reg_class_to_regbank(pco_ref_get_reg_class(ref));
return pco_ref_is_idx_reg(ref) ? regbank + ref.idx_reg.num : regbank;
}
static inline
unsigned pco_map_reg_bank_bits(pco_ref ref)
{
return util_last_bit(pco_map_reg_bank(ref));
}
static inline
enum pco_idxbank pco_map_idx_bank(pco_ref ref)
{
assert(pco_ref_is_idx_reg(ref));
return pco_map_reg_class_to_idxbank(ref.reg_class);
}
static inline unsigned pco_map_reg_index(pco_ref ref)
{
if (pco_ref_is_reg(ref)) {
switch (ref.reg_class) {
case PCO_REG_CLASS_TEMP:
case PCO_REG_CLASS_VTXIN:
case PCO_REG_CLASS_COEFF:
case PCO_REG_CLASS_SHARED:
case PCO_REG_CLASS_SPEC:
case PCO_REG_CLASS_CONST:
return ref.val;
case PCO_REG_CLASS_INTERN:
return ref.val + PCO_SR_INTL0;
case PCO_REG_CLASS_PIXOUT:
if (ref.val >= 4)
return ref.val + PCO_SR_PIXOUT4 - 4;
else
return ref.val + PCO_SR_PIXOUT0;
case PCO_REG_CLASS_GLOBAL:
return ref.val + PCO_SR_GLOBAL0;
case PCO_REG_CLASS_SLOT:
return (7 - ref.val) + PCO_SR_SLOT7;
default:
break;
}
} else if (pco_ref_is_idx_reg(ref)) {
return pco_map_idx_bank(ref) | (ref.idx_reg.offset << 3);
}
unreachable();
}
static inline unsigned pco_map_reg_index_bits(pco_ref ref)
{
if (pco_ref_is_reg(ref))
return util_last_bit(pco_map_reg_index(ref));
else if (pco_ref_is_idx_reg(ref))
return 11;
unreachable();
}
static inline
enum pco_igrp_hdr_variant pco_igrp_hdr_variant(pco_igrp *igrp)
{
if (igrp->hdr.alutype == PCO_ALUTYPE_BITWISE)
return PCO_IGRP_HDR_BITWISE;
else if (igrp->hdr.alutype == PCO_ALUTYPE_CONTROL)
return PCO_IGRP_HDR_CONTROL;
else
assert(igrp->hdr.alutype == PCO_ALUTYPE_MAIN);
if (!igrp->hdr.end && !igrp->hdr.atom && !igrp->hdr.rpt && !igrp->hdr.cc)
return PCO_IGRP_HDR_MAIN_BRIEF;
return PCO_IGRP_HDR_MAIN;
}
static inline
enum pco_src_variant pco_igrp_src_variant(const pco_igrp *igrp,
bool is_upper)
{
unsigned offset = is_upper ? ROGUE_ALU_INPUT_GROUP_SIZE : 0;
pco_ref sA = igrp->srcs.s[0 + offset];
pco_ref sB = igrp->srcs.s[1 + offset];
pco_ref sC = igrp->srcs.s[2 + offset];
pco_ref mux = is_upper ? pco_ref_null() : igrp->iss.is[0];
bool sA_set = !pco_ref_is_null(sA);
bool sB_set = !pco_ref_is_null(sB);
bool sC_set = !pco_ref_is_null(sC);
bool mux_set = !pco_ref_is_null(mux);
int sbA_bits = sA_set ? pco_map_reg_bank_bits(sA) : -1;
int sA_bits = sA_set ? pco_map_reg_index_bits(sA) : -1;
int sbB_bits = sB_set ? pco_map_reg_bank_bits(sB) : -1;
int sB_bits = sB_set ? pco_map_reg_index_bits(sB) : -1;
int sbC_bits = sC_set ? pco_map_reg_bank_bits(sC) : -1;
int sC_bits = sC_set ? pco_map_reg_index_bits(sC) : -1;
int mux_bits = mux_set ? util_last_bit(pco_map_io_to_is0_sel(pco_ref_get_io(mux))) : -1;
bool is_ctrl = igrp->hdr.alutype == PCO_ALUTYPE_CONTROL;
bool no_srcs_set = !sA_set && !sB_set && !sC_set && !mux_set;
if (is_ctrl && no_srcs_set)
return PCO_SRC_NONE;
% for variant, spec in [(bs.name.upper(), bs.data) for bs in I_SRC.bit_structs.values()]:
${'else ' if not loop.first else ''}if (${'!' if not spec.is_upper else ''}is_upper &&
sbA_bits ${'==' if spec.sbA_bits == -1 else '<='} ${spec.sbA_bits} && sA_bits ${'==' if spec.sA_bits == -1 else '<='} ${spec.sA_bits} &&
sbB_bits ${'==' if spec.sbB_bits == -1 else '<='} ${spec.sbB_bits} && sB_bits ${'==' if spec.sB_bits == -1 else '<='} ${spec.sB_bits} &&
sbC_bits ${'==' if spec.sbC_bits == -1 else '<='} ${spec.sbC_bits} && sC_bits ${'==' if spec.sC_bits == -1 else '<='} ${spec.sC_bits} &&
mux_bits ${'==' if spec.mux_bits == -1 else '<='} ${spec.mux_bits}) {
return ${variant};
}
% endfor
unreachable();
}
static inline
enum pco_iss_variant pco_igrp_iss_variant(const pco_igrp *igrp)
{
if (igrp->hdr.alutype == PCO_ALUTYPE_MAIN)
return PCO_ISS_ISS;
return PCO_ISS_NONE;
}
static inline
enum pco_dst_variant pco_igrp_dest_variant(pco_igrp *igrp)
{
pco_ref w0 = igrp->dests.w[0];
pco_ref w1 = igrp->dests.w[1];
bool w0_set = !pco_ref_is_null(w0);
bool w1_set = !pco_ref_is_null(w1);
bool no_dsts = !w0_set && !w1_set;
bool one_dest = w0_set != w1_set;
bool dual_dsts = w0_set && w1_set;
if (no_dsts)
return PCO_DST_NONE;
int db0_bits = w0_set ? pco_map_reg_bank_bits(w0) : -1;
int d0_bits = w0_set ? pco_map_reg_index_bits(w0) : -1;
int db1_bits = w1_set ? pco_map_reg_bank_bits(w1) : -1;
int d1_bits = w1_set ? pco_map_reg_index_bits(w1) : -1;
int dbN_bits = w0_set ? db0_bits : db1_bits;
int dN_bits = w0_set ? d0_bits : d1_bits;
if (one_dest) {
db0_bits = dbN_bits;
d0_bits = dN_bits;
db1_bits = -1;
d1_bits = -1;
}
% for variant, spec in [(bs.name.upper(), bs.data) for bs in I_DST.bit_structs.values()]:
${'else ' if not loop.first else ''}if (${'!' if not spec.dual_dsts else ''}dual_dsts &&
db0_bits ${'==' if spec.db0_bits == -1 else '<='} ${spec.db0_bits} && d0_bits ${'==' if spec.d0_bits == -1 else '<='} ${spec.d0_bits} &&
db1_bits ${'==' if spec.db1_bits == -1 else '<='} ${spec.db1_bits} && d1_bits ${'==' if spec.d1_bits == -1 else '<='} ${spec.d1_bits}) {
return ${variant};
}
% endfor
unreachable();
}
/* Instruction group mappings. */
% for op_map in op_maps.values():
static inline
void ${op_map.name}_map_igrp(pco_igrp *igrp, pco_instr *instr)
{
% for mapping_group in op_map.igrp_mappings:
% for mapping in mapping_group:
${mapping.format('igrp', 'instr')}
% endfor
% endfor
igrp->variant.hdr = pco_igrp_hdr_variant(igrp);
igrp->variant.lower_src = pco_igrp_src_variant(igrp, false);
igrp->variant.upper_src = pco_igrp_src_variant(igrp, true);
igrp->variant.iss = pco_igrp_iss_variant(igrp);
igrp->variant.dest = pco_igrp_dest_variant(igrp);
}
% endfor
static inline
void pco_map_igrp(pco_igrp *igrp, pco_instr *instr)
{
switch (instr->op) {
% for op_map in op_maps.values():
case ${op_map.cop_name}:
return ${op_map.name}_map_igrp(igrp, instr);
% endfor
default:
break;
}
const struct pco_op_info *info = &pco_op_info[instr->op];
printf("Instruction group mapping not defined for %s op '%s'.\\n",
info->type == PCO_OP_TYPE_PSEUDO ? "pseudo" : "hardware",
info->str);
unreachable();
}
static inline unsigned pco_igrp_hdr_map_encode(uint8_t *bin, pco_igrp *igrp)
{
switch (igrp->variant.hdr) {
case PCO_IGRP_HDR_MAIN_BRIEF:
return pco_igrp_hdr_main_brief_encode(bin,
.da = igrp->hdr.da,
.length = igrp->hdr.length,
.oporg = igrp->hdr.oporg,
.olchk = igrp->hdr.olchk,
.w1p = igrp->hdr.w1p,
.w0p = igrp->hdr.w0p,
.cc = igrp->hdr.cc);
case PCO_IGRP_HDR_MAIN:
return pco_igrp_hdr_main_encode(bin,
.da = igrp->hdr.da,
.length = igrp->hdr.length,
.oporg = igrp->hdr.oporg,
.olchk = igrp->hdr.olchk,
.w1p = igrp->hdr.w1p,
.w0p = igrp->hdr.w0p,
.cc = igrp->hdr.cc,
.end = igrp->hdr.end,
.atom = igrp->hdr.atom,
.rpt = igrp->hdr.rpt);
case PCO_IGRP_HDR_BITWISE:
return pco_igrp_hdr_bitwise_encode(bin,
.da = igrp->hdr.da,
.length = igrp->hdr.length,
.opcnt = igrp->hdr.opcnt,
.olchk = igrp->hdr.olchk,
.w1p = igrp->hdr.w1p,
.w0p = igrp->hdr.w0p,
.cc = igrp->hdr.cc,
.end = igrp->hdr.end,
.atom = igrp->hdr.atom,
.rpt = igrp->hdr.rpt);
case PCO_IGRP_HDR_CONTROL:
return pco_igrp_hdr_control_encode(bin,
.da = igrp->hdr.da,
.length = igrp->hdr.length,
.olchk = igrp->hdr.olchk,
.w1p = igrp->hdr.w1p,
.w0p = igrp->hdr.w0p,
.cc = igrp->hdr.cc,
.miscctl = igrp->hdr.miscctl,
.ctrlop = igrp->hdr.ctrlop);
default:
break;
}
unreachable();
}
% for op_map in encode_maps.values():
static inline
% if len(op_map.encode_variants) > 1:
unsigned ${op_map.name}_map_encode(uint8_t *bin, pco_instr *instr, unsigned variant)
{
switch (variant) {
% for variant, mapping in op_map.encode_variants:
case ${variant}:
return ${mapping.format('bin', 'instr', 'variant')};
% endfor
default:
break;
}
unreachable();
}
% else:
unsigned ${op_map.name}_map_encode(uint8_t *bin, pco_instr *instr)
{
return ${op_map.encode_variants[0][1].format('bin', 'instr', 'variant')};
}
% endif
% endfor
static inline
unsigned pco_instr_map_encode(uint8_t *bin, pco_igrp *igrp, enum pco_op_phase phase)
{
pco_instr *instr = igrp->instrs[phase];
switch (instr->op) {
% for op_map in encode_maps.values():
case ${op_map.cop_name}:
% if len(op_map.encode_variants) > 1:
return ${op_map.name}_map_encode(bin, instr, pco_igrp_variant(igrp, phase));
% else:
return ${op_map.name}_map_encode(bin, instr);
% endif
% endfor
default:
break;
}
unreachable();
}
static inline
unsigned pco_srcs_map_encode(uint8_t *bin, pco_igrp *igrp, bool is_upper)
{
unsigned offset = is_upper ? ROGUE_ALU_INPUT_GROUP_SIZE : 0;
pco_ref _sA = igrp->srcs.s[0 + offset];
pco_ref _sB = igrp->srcs.s[1 + offset];
pco_ref _sC = igrp->srcs.s[2 + offset];
pco_ref _mux = is_upper ? pco_ref_null() : igrp->iss.is[0];
bool sA_set = !pco_ref_is_null(_sA);
bool sB_set = !pco_ref_is_null(_sB);
bool sC_set = !pco_ref_is_null(_sC);
bool mux_set = !pco_ref_is_null(_mux);
unsigned sbA = sA_set ? pco_map_reg_bank(_sA) : 0;
unsigned sA = sA_set ? pco_map_reg_index(_sA) : 0;
unsigned sbB = sB_set ? pco_map_reg_bank(_sB) : 0;
unsigned sB = sB_set ? pco_map_reg_index(_sB) : 0;
unsigned sbC = sC_set ? pco_map_reg_bank(_sC) : 0;
unsigned sC = sC_set ? pco_map_reg_index(_sC) : 0;
unsigned mux = mux_set ? pco_map_io_to_is0_sel(pco_ref_get_io(_mux)) : 0;
enum pco_src_variant variant = is_upper ? igrp->variant.upper_src : igrp->variant.lower_src;
switch (variant) {
% for variant, encode_func, spec, offset in [(bs.name.upper(), f'{bs.name}_encode', bs.data, 3 if bs.data.is_upper else 0) for bs in I_SRC.bit_structs.values()]:
case ${variant}:
return ${encode_func}(bin,
% if spec.sbA_bits != -1:
.s${offset + 0} = sA,
.sb${offset + 0} = sbA,
% endif
% if spec.sbB_bits != -1:
.s${offset + 1} = sB,
.sb${offset + 1} = sbB,
% endif
% if spec.sbC_bits != -1:
.s${offset + 2} = sC,
.sb${offset + 2} = sbC,
% endif
% if spec.mux_bits != -1:
.is0 = mux,
% endif
);
% endfor
default:
break;
}
unreachable();
}
static inline
unsigned pco_iss_map_encode(uint8_t *bin, pco_igrp *igrp)
{
bool is5_set = !pco_ref_is_null(igrp->iss.is[5]);
bool is4_set = !pco_ref_is_null(igrp->iss.is[4]);
bool is3_set = !pco_ref_is_null(igrp->iss.is[3]);
bool is2_set = !pco_ref_is_null(igrp->iss.is[2]);
bool is1_set = !pco_ref_is_null(igrp->iss.is[1]);
unsigned is5 = is5_set ? pco_map_io_to_is5_sel(pco_ref_get_io(igrp->iss.is[5])) : 0;
unsigned is4 = is4_set ? pco_map_io_to_is4_sel(pco_ref_get_io(igrp->iss.is[4])) : 0;
unsigned is3 = is3_set ? pco_map_io_to_is3_sel(pco_ref_get_io(igrp->iss.is[3])) : 0;
unsigned is2 = is2_set ? pco_map_io_to_is2_sel(pco_ref_get_io(igrp->iss.is[2])) : 0;
unsigned is1 = is1_set ? pco_map_io_to_is1_sel(pco_ref_get_io(igrp->iss.is[1])) : 0;
assert(igrp->variant.iss == PCO_ISS_ISS);
return pco_iss_iss_encode(bin, .is5 = is5, .is4 = is4, .is3 = is3, .is2 = is2, .is1 = is1);
}
static inline
unsigned pco_dests_map_encode(uint8_t *bin, pco_igrp *igrp)
{
pco_ref w0 = igrp->dests.w[0];
pco_ref w1 = igrp->dests.w[1];
bool w0_set = !pco_ref_is_null(w0);
bool w1_set = !pco_ref_is_null(w1);
bool one_dest = w0_set != w1_set;
int db0 = w0_set ? pco_map_reg_bank(w0) : 0;
int d0 = w0_set ? pco_map_reg_index(w0) : 0;
int db1 = w1_set ? pco_map_reg_bank(w1) : 0;
int d1 = w1_set ? pco_map_reg_index(w1) : 0;
int dbN = w0_set ? db0 : db1;
int dN = w0_set ? d0 : d1;
if (one_dest) {
db0 = dbN;
d0 = dN;
db1 = 0;
d1 = 0;
}
switch (igrp->variant.dest) {
% for variant, encode_func, spec in [(bs.name.upper(), f'{bs.name}_encode', bs.data) for bs in I_DST.bit_structs.values()]:
case ${variant}:
return ${encode_func}(bin,
% if spec.db0_bits != -1:
% if spec.dual_dsts:
.d0 = d0,
.db0 = db0,
% else:
.dN = d0,
.dbN = db0,
% endif
% endif
% if spec.db1_bits != -1:
.d1 = d1,
.db1 = db1,
% endif
);
% endfor
default:
break;
}
unreachable();
}
#endif /* PCO_MAP_H */"""
def main():
try:
print(Template(template).render(enum_maps=enum_maps, op_maps=op_maps, encode_maps=encode_maps, I_SRC=I_SRC, I_DST=I_DST))
except:
raise Exception(exceptions.text_error_template().render())
if __name__ == '__main__':
main()