1# Copyright © 2024 Imagination Technologies Ltd. 2# SPDX-License-Identifier: MIT 3 4from mako.template import Template, exceptions 5from pco_map import * 6 7template = """/* 8 * Copyright © 2024 Imagination Technologies Ltd. 9 * 10 * SPDX-License-Identifier: MIT 11 */ 12 13#ifndef PCO_MAP_H 14#define PCO_MAP_H 15 16/** 17 * \\file pco_map.h 18 * 19 * \\brief PCO mapping definitions. 20 */ 21 22#include "pco_builder.h" 23#include "pco_common.h" 24#include "pco_internal.h" 25#include "pco_isa.h" 26#include "pco_ops.h" 27#include "util/macros.h" 28 29#include <stdbool.h> 30 31/* Enum mappings. */ 32% for enum_map in enum_maps.values(): 33static inline 34${enum_map.type_to} ${enum_map.name}(${enum_map.type_from} val) 35{ 36 switch (val) { 37 % for elem_from, elem_to in enum_map.mappings: 38 case ${elem_from}: 39 return ${elem_to}; 40 41 % endfor 42 default: break; 43 } 44 45 unreachable(); 46} 47 48% endfor 49static inline 50enum pco_regbank pco_map_reg_bank(pco_ref ref) 51{ 52 enum pco_regbank regbank = pco_map_reg_class_to_regbank(pco_ref_get_reg_class(ref)); 53 return pco_ref_is_idx_reg(ref) ? regbank + ref.idx_reg.num : regbank; 54} 55 56static inline 57unsigned pco_map_reg_bank_bits(pco_ref ref) 58{ 59 return util_last_bit(pco_map_reg_bank(ref)); 60} 61 62static inline 63enum pco_idxbank pco_map_idx_bank(pco_ref ref) 64{ 65 assert(pco_ref_is_idx_reg(ref)); 66 return pco_map_reg_class_to_idxbank(ref.reg_class); 67} 68 69static inline unsigned pco_map_reg_index(pco_ref ref) 70{ 71 if (pco_ref_is_reg(ref)) { 72 switch (ref.reg_class) { 73 case PCO_REG_CLASS_TEMP: 74 case PCO_REG_CLASS_VTXIN: 75 case PCO_REG_CLASS_COEFF: 76 case PCO_REG_CLASS_SHARED: 77 case PCO_REG_CLASS_SPEC: 78 case PCO_REG_CLASS_CONST: 79 return ref.val; 80 81 case PCO_REG_CLASS_INTERN: 82 return ref.val + PCO_SR_INTL0; 83 84 case PCO_REG_CLASS_PIXOUT: 85 if (ref.val >= 4) 86 return ref.val + PCO_SR_PIXOUT4 - 4; 87 else 88 return ref.val + PCO_SR_PIXOUT0; 89 90 case PCO_REG_CLASS_GLOBAL: 91 return ref.val + PCO_SR_GLOBAL0; 92 93 case PCO_REG_CLASS_SLOT: 94 return (7 - ref.val) + PCO_SR_SLOT7; 95 96 default: 97 break; 98 } 99 } else if (pco_ref_is_idx_reg(ref)) { 100 return pco_map_idx_bank(ref) | (ref.idx_reg.offset << 3); 101 } 102 103 unreachable(); 104} 105 106static inline unsigned pco_map_reg_index_bits(pco_ref ref) 107{ 108 if (pco_ref_is_reg(ref)) 109 return util_last_bit(pco_map_reg_index(ref)); 110 else if (pco_ref_is_idx_reg(ref)) 111 return 11; 112 113 unreachable(); 114} 115 116static inline 117enum pco_igrp_hdr_variant pco_igrp_hdr_variant(pco_igrp *igrp) 118{ 119 if (igrp->hdr.alutype == PCO_ALUTYPE_BITWISE) 120 return PCO_IGRP_HDR_BITWISE; 121 else if (igrp->hdr.alutype == PCO_ALUTYPE_CONTROL) 122 return PCO_IGRP_HDR_CONTROL; 123 else 124 assert(igrp->hdr.alutype == PCO_ALUTYPE_MAIN); 125 126 if (!igrp->hdr.end && !igrp->hdr.atom && !igrp->hdr.rpt && !igrp->hdr.cc) 127 return PCO_IGRP_HDR_MAIN_BRIEF; 128 129 return PCO_IGRP_HDR_MAIN; 130} 131 132static inline 133enum pco_src_variant pco_igrp_src_variant(const pco_igrp *igrp, 134 bool is_upper) 135{ 136 unsigned offset = is_upper ? ROGUE_ALU_INPUT_GROUP_SIZE : 0; 137 138 pco_ref sA = igrp->srcs.s[0 + offset]; 139 pco_ref sB = igrp->srcs.s[1 + offset]; 140 pco_ref sC = igrp->srcs.s[2 + offset]; 141 pco_ref mux = is_upper ? pco_ref_null() : igrp->iss.is[0]; 142 143 bool sA_set = !pco_ref_is_null(sA); 144 bool sB_set = !pco_ref_is_null(sB); 145 bool sC_set = !pco_ref_is_null(sC); 146 bool mux_set = !pco_ref_is_null(mux); 147 148 int sbA_bits = sA_set ? pco_map_reg_bank_bits(sA) : -1; 149 int sA_bits = sA_set ? pco_map_reg_index_bits(sA) : -1; 150 151 int sbB_bits = sB_set ? pco_map_reg_bank_bits(sB) : -1; 152 int sB_bits = sB_set ? pco_map_reg_index_bits(sB) : -1; 153 154 int sbC_bits = sC_set ? pco_map_reg_bank_bits(sC) : -1; 155 int sC_bits = sC_set ? pco_map_reg_index_bits(sC) : -1; 156 157 int mux_bits = mux_set ? util_last_bit(pco_map_io_to_is0_sel(pco_ref_get_io(mux))) : -1; 158 159 bool is_ctrl = igrp->hdr.alutype == PCO_ALUTYPE_CONTROL; 160 bool no_srcs_set = !sA_set && !sB_set && !sC_set && !mux_set; 161 if (is_ctrl && no_srcs_set) 162 return PCO_SRC_NONE; 163 164% for variant, spec in [(bs.name.upper(), bs.data) for bs in I_SRC.bit_structs.values()]: 165 ${'else ' if not loop.first else ''}if (${'!' if not spec.is_upper else ''}is_upper && 166 sbA_bits ${'==' if spec.sbA_bits == -1 else '<='} ${spec.sbA_bits} && sA_bits ${'==' if spec.sA_bits == -1 else '<='} ${spec.sA_bits} && 167 sbB_bits ${'==' if spec.sbB_bits == -1 else '<='} ${spec.sbB_bits} && sB_bits ${'==' if spec.sB_bits == -1 else '<='} ${spec.sB_bits} && 168 sbC_bits ${'==' if spec.sbC_bits == -1 else '<='} ${spec.sbC_bits} && sC_bits ${'==' if spec.sC_bits == -1 else '<='} ${spec.sC_bits} && 169 mux_bits ${'==' if spec.mux_bits == -1 else '<='} ${spec.mux_bits}) { 170 return ${variant}; 171 } 172% endfor 173 174 unreachable(); 175} 176 177static inline 178enum pco_iss_variant pco_igrp_iss_variant(const pco_igrp *igrp) 179{ 180 if (igrp->hdr.alutype == PCO_ALUTYPE_MAIN) 181 return PCO_ISS_ISS; 182 183 return PCO_ISS_NONE; 184} 185 186static inline 187enum pco_dst_variant pco_igrp_dest_variant(pco_igrp *igrp) 188{ 189 pco_ref w0 = igrp->dests.w[0]; 190 pco_ref w1 = igrp->dests.w[1]; 191 192 bool w0_set = !pco_ref_is_null(w0); 193 bool w1_set = !pco_ref_is_null(w1); 194 195 bool no_dsts = !w0_set && !w1_set; 196 bool one_dest = w0_set != w1_set; 197 bool dual_dsts = w0_set && w1_set; 198 199 if (no_dsts) 200 return PCO_DST_NONE; 201 202 int db0_bits = w0_set ? pco_map_reg_bank_bits(w0) : -1; 203 int d0_bits = w0_set ? pco_map_reg_index_bits(w0) : -1; 204 205 int db1_bits = w1_set ? pco_map_reg_bank_bits(w1) : -1; 206 int d1_bits = w1_set ? pco_map_reg_index_bits(w1) : -1; 207 208 int dbN_bits = w0_set ? db0_bits : db1_bits; 209 int dN_bits = w0_set ? d0_bits : d1_bits; 210 211 if (one_dest) { 212 db0_bits = dbN_bits; 213 d0_bits = dN_bits; 214 215 db1_bits = -1; 216 d1_bits = -1; 217 } 218 219% for variant, spec in [(bs.name.upper(), bs.data) for bs in I_DST.bit_structs.values()]: 220 ${'else ' if not loop.first else ''}if (${'!' if not spec.dual_dsts else ''}dual_dsts && 221 db0_bits ${'==' if spec.db0_bits == -1 else '<='} ${spec.db0_bits} && d0_bits ${'==' if spec.d0_bits == -1 else '<='} ${spec.d0_bits} && 222 db1_bits ${'==' if spec.db1_bits == -1 else '<='} ${spec.db1_bits} && d1_bits ${'==' if spec.d1_bits == -1 else '<='} ${spec.d1_bits}) { 223 return ${variant}; 224 } 225% endfor 226 227 unreachable(); 228} 229 230/* Instruction group mappings. */ 231% for op_map in op_maps.values(): 232static inline 233void ${op_map.name}_map_igrp(pco_igrp *igrp, pco_instr *instr) 234{ 235 % for mapping_group in op_map.igrp_mappings: 236 % for mapping in mapping_group: 237 ${mapping.format('igrp', 'instr')} 238 % endfor 239 240 % endfor 241 igrp->variant.hdr = pco_igrp_hdr_variant(igrp); 242 igrp->variant.lower_src = pco_igrp_src_variant(igrp, false); 243 igrp->variant.upper_src = pco_igrp_src_variant(igrp, true); 244 igrp->variant.iss = pco_igrp_iss_variant(igrp); 245 igrp->variant.dest = pco_igrp_dest_variant(igrp); 246} 247 248% endfor 249static inline 250void pco_map_igrp(pco_igrp *igrp, pco_instr *instr) 251{ 252 switch (instr->op) { 253% for op_map in op_maps.values(): 254 case ${op_map.cop_name}: 255 return ${op_map.name}_map_igrp(igrp, instr); 256 257% endfor 258 default: 259 break; 260 } 261 262 const struct pco_op_info *info = &pco_op_info[instr->op]; 263 printf("Instruction group mapping not defined for %s op '%s'.\\n", 264 info->type == PCO_OP_TYPE_PSEUDO ? "pseudo" : "hardware", 265 info->str); 266 267 unreachable(); 268} 269 270static inline unsigned pco_igrp_hdr_map_encode(uint8_t *bin, pco_igrp *igrp) 271{ 272 switch (igrp->variant.hdr) { 273 case PCO_IGRP_HDR_MAIN_BRIEF: 274 return pco_igrp_hdr_main_brief_encode(bin, 275 .da = igrp->hdr.da, 276 .length = igrp->hdr.length, 277 .oporg = igrp->hdr.oporg, 278 .olchk = igrp->hdr.olchk, 279 .w1p = igrp->hdr.w1p, 280 .w0p = igrp->hdr.w0p, 281 .cc = igrp->hdr.cc); 282 283 case PCO_IGRP_HDR_MAIN: 284 return pco_igrp_hdr_main_encode(bin, 285 .da = igrp->hdr.da, 286 .length = igrp->hdr.length, 287 .oporg = igrp->hdr.oporg, 288 .olchk = igrp->hdr.olchk, 289 .w1p = igrp->hdr.w1p, 290 .w0p = igrp->hdr.w0p, 291 .cc = igrp->hdr.cc, 292 .end = igrp->hdr.end, 293 .atom = igrp->hdr.atom, 294 .rpt = igrp->hdr.rpt); 295 296 case PCO_IGRP_HDR_BITWISE: 297 return pco_igrp_hdr_bitwise_encode(bin, 298 .da = igrp->hdr.da, 299 .length = igrp->hdr.length, 300 .opcnt = igrp->hdr.opcnt, 301 .olchk = igrp->hdr.olchk, 302 .w1p = igrp->hdr.w1p, 303 .w0p = igrp->hdr.w0p, 304 .cc = igrp->hdr.cc, 305 .end = igrp->hdr.end, 306 .atom = igrp->hdr.atom, 307 .rpt = igrp->hdr.rpt); 308 309 case PCO_IGRP_HDR_CONTROL: 310 return pco_igrp_hdr_control_encode(bin, 311 .da = igrp->hdr.da, 312 .length = igrp->hdr.length, 313 .olchk = igrp->hdr.olchk, 314 .w1p = igrp->hdr.w1p, 315 .w0p = igrp->hdr.w0p, 316 .cc = igrp->hdr.cc, 317 .miscctl = igrp->hdr.miscctl, 318 .ctrlop = igrp->hdr.ctrlop); 319 320 default: 321 break; 322 } 323 324 unreachable(); 325} 326 327 328% for op_map in encode_maps.values(): 329static inline 330 % if len(op_map.encode_variants) > 1: 331unsigned ${op_map.name}_map_encode(uint8_t *bin, pco_instr *instr, unsigned variant) 332{ 333 switch (variant) { 334 % for variant, mapping in op_map.encode_variants: 335 case ${variant}: 336 return ${mapping.format('bin', 'instr', 'variant')}; 337 338 % endfor 339 default: 340 break; 341 } 342 343 unreachable(); 344} 345 % else: 346unsigned ${op_map.name}_map_encode(uint8_t *bin, pco_instr *instr) 347{ 348 return ${op_map.encode_variants[0][1].format('bin', 'instr', 'variant')}; 349} 350 % endif 351 352% endfor 353static inline 354unsigned pco_instr_map_encode(uint8_t *bin, pco_igrp *igrp, enum pco_op_phase phase) 355{ 356 pco_instr *instr = igrp->instrs[phase]; 357 switch (instr->op) { 358% for op_map in encode_maps.values(): 359 case ${op_map.cop_name}: 360 % if len(op_map.encode_variants) > 1: 361 return ${op_map.name}_map_encode(bin, instr, pco_igrp_variant(igrp, phase)); 362 % else: 363 return ${op_map.name}_map_encode(bin, instr); 364 % endif 365 366% endfor 367 default: 368 break; 369 } 370 371 unreachable(); 372} 373 374static inline 375unsigned pco_srcs_map_encode(uint8_t *bin, pco_igrp *igrp, bool is_upper) 376{ 377 unsigned offset = is_upper ? ROGUE_ALU_INPUT_GROUP_SIZE : 0; 378 379 pco_ref _sA = igrp->srcs.s[0 + offset]; 380 pco_ref _sB = igrp->srcs.s[1 + offset]; 381 pco_ref _sC = igrp->srcs.s[2 + offset]; 382 pco_ref _mux = is_upper ? pco_ref_null() : igrp->iss.is[0]; 383 384 bool sA_set = !pco_ref_is_null(_sA); 385 bool sB_set = !pco_ref_is_null(_sB); 386 bool sC_set = !pco_ref_is_null(_sC); 387 bool mux_set = !pco_ref_is_null(_mux); 388 389 unsigned sbA = sA_set ? pco_map_reg_bank(_sA) : 0; 390 unsigned sA = sA_set ? pco_map_reg_index(_sA) : 0; 391 392 unsigned sbB = sB_set ? pco_map_reg_bank(_sB) : 0; 393 unsigned sB = sB_set ? pco_map_reg_index(_sB) : 0; 394 395 unsigned sbC = sC_set ? pco_map_reg_bank(_sC) : 0; 396 unsigned sC = sC_set ? pco_map_reg_index(_sC) : 0; 397 398 unsigned mux = mux_set ? pco_map_io_to_is0_sel(pco_ref_get_io(_mux)) : 0; 399 400 enum pco_src_variant variant = is_upper ? igrp->variant.upper_src : igrp->variant.lower_src; 401 switch (variant) { 402% 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()]: 403 case ${variant}: 404 return ${encode_func}(bin, 405 % if spec.sbA_bits != -1: 406 .s${offset + 0} = sA, 407 .sb${offset + 0} = sbA, 408 % endif 409 % if spec.sbB_bits != -1: 410 .s${offset + 1} = sB, 411 .sb${offset + 1} = sbB, 412 % endif 413 % if spec.sbC_bits != -1: 414 .s${offset + 2} = sC, 415 .sb${offset + 2} = sbC, 416 % endif 417 % if spec.mux_bits != -1: 418 .is0 = mux, 419 % endif 420 ); 421 422% endfor 423 default: 424 break; 425 } 426 427 unreachable(); 428} 429 430static inline 431unsigned pco_iss_map_encode(uint8_t *bin, pco_igrp *igrp) 432{ 433 bool is5_set = !pco_ref_is_null(igrp->iss.is[5]); 434 bool is4_set = !pco_ref_is_null(igrp->iss.is[4]); 435 bool is3_set = !pco_ref_is_null(igrp->iss.is[3]); 436 bool is2_set = !pco_ref_is_null(igrp->iss.is[2]); 437 bool is1_set = !pco_ref_is_null(igrp->iss.is[1]); 438 439 unsigned is5 = is5_set ? pco_map_io_to_is5_sel(pco_ref_get_io(igrp->iss.is[5])) : 0; 440 unsigned is4 = is4_set ? pco_map_io_to_is4_sel(pco_ref_get_io(igrp->iss.is[4])) : 0; 441 unsigned is3 = is3_set ? pco_map_io_to_is3_sel(pco_ref_get_io(igrp->iss.is[3])) : 0; 442 unsigned is2 = is2_set ? pco_map_io_to_is2_sel(pco_ref_get_io(igrp->iss.is[2])) : 0; 443 unsigned is1 = is1_set ? pco_map_io_to_is1_sel(pco_ref_get_io(igrp->iss.is[1])) : 0; 444 445 assert(igrp->variant.iss == PCO_ISS_ISS); 446 return pco_iss_iss_encode(bin, .is5 = is5, .is4 = is4, .is3 = is3, .is2 = is2, .is1 = is1); 447} 448 449static inline 450unsigned pco_dests_map_encode(uint8_t *bin, pco_igrp *igrp) 451{ 452 pco_ref w0 = igrp->dests.w[0]; 453 pco_ref w1 = igrp->dests.w[1]; 454 455 bool w0_set = !pco_ref_is_null(w0); 456 bool w1_set = !pco_ref_is_null(w1); 457 458 bool one_dest = w0_set != w1_set; 459 460 int db0 = w0_set ? pco_map_reg_bank(w0) : 0; 461 int d0 = w0_set ? pco_map_reg_index(w0) : 0; 462 463 int db1 = w1_set ? pco_map_reg_bank(w1) : 0; 464 int d1 = w1_set ? pco_map_reg_index(w1) : 0; 465 466 int dbN = w0_set ? db0 : db1; 467 int dN = w0_set ? d0 : d1; 468 469 if (one_dest) { 470 db0 = dbN; 471 d0 = dN; 472 473 db1 = 0; 474 d1 = 0; 475 } 476 477 switch (igrp->variant.dest) { 478% for variant, encode_func, spec in [(bs.name.upper(), f'{bs.name}_encode', bs.data) for bs in I_DST.bit_structs.values()]: 479 case ${variant}: 480 return ${encode_func}(bin, 481 % if spec.db0_bits != -1: 482 % if spec.dual_dsts: 483 .d0 = d0, 484 .db0 = db0, 485 % else: 486 .dN = d0, 487 .dbN = db0, 488 % endif 489 % endif 490 % if spec.db1_bits != -1: 491 .d1 = d1, 492 .db1 = db1, 493 % endif 494 ); 495 496% endfor 497 default: 498 break; 499 } 500 501 unreachable(); 502} 503#endif /* PCO_MAP_H */""" 504 505def main(): 506 try: 507 print(Template(template).render(enum_maps=enum_maps, op_maps=op_maps, encode_maps=encode_maps, I_SRC=I_SRC, I_DST=I_DST)) 508 except: 509 raise Exception(exceptions.text_error_template().render()) 510 511if __name__ == '__main__': 512 main() 513