1bf215546Sopenharmony_ci#encoding=utf-8 2bf215546Sopenharmony_ci 3bf215546Sopenharmony_ci# Copyright (C) 2021 Collabora, Ltd. 4bf215546Sopenharmony_ci# 5bf215546Sopenharmony_ci# Permission is hereby granted, free of charge, to any person obtaining a 6bf215546Sopenharmony_ci# copy of this software and associated documentation files (the "Software"), 7bf215546Sopenharmony_ci# to deal in the Software without restriction, including without limitation 8bf215546Sopenharmony_ci# the rights to use, copy, modify, merge, publish, distribute, sublicense, 9bf215546Sopenharmony_ci# and/or sell copies of the Software, and to permit persons to whom the 10bf215546Sopenharmony_ci# Software is furnished to do so, subject to the following conditions: 11bf215546Sopenharmony_ci# 12bf215546Sopenharmony_ci# The above copyright notice and this permission notice (including the next 13bf215546Sopenharmony_ci# paragraph) shall be included in all copies or substantial portions of the 14bf215546Sopenharmony_ci# Software. 15bf215546Sopenharmony_ci# 16bf215546Sopenharmony_ci# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17bf215546Sopenharmony_ci# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18bf215546Sopenharmony_ci# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19bf215546Sopenharmony_ci# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20bf215546Sopenharmony_ci# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21bf215546Sopenharmony_ci# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22bf215546Sopenharmony_ci# IN THE SOFTWARE. 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ciimport argparse 25bf215546Sopenharmony_ciimport sys 26bf215546Sopenharmony_ciimport struct 27bf215546Sopenharmony_cifrom valhall import instructions, enums, immediates, typesize 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ciLINE = '' 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ciclass ParseError(Exception): 32bf215546Sopenharmony_ci def __init__(self, error): 33bf215546Sopenharmony_ci self.error = error 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ciclass FAUState: 36bf215546Sopenharmony_ci def __init__(self, message = False): 37bf215546Sopenharmony_ci self.message = message 38bf215546Sopenharmony_ci self.page = None 39bf215546Sopenharmony_ci self.words = set() 40bf215546Sopenharmony_ci self.buffer = set() 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci def set_page(self, page): 43bf215546Sopenharmony_ci assert(page <= 3) 44bf215546Sopenharmony_ci die_if(self.page is not None and self.page != page, 'Mismatched pages') 45bf215546Sopenharmony_ci self.page = page 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci def push(self, source): 48bf215546Sopenharmony_ci if not (source & (1 << 7)): 49bf215546Sopenharmony_ci # Skip registers 50bf215546Sopenharmony_ci return 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci self.buffer.add(source) 53bf215546Sopenharmony_ci die_if(len(self.buffer) > 2, "Overflowed FAU buffer") 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci if (source >> 5) == 0b110: 56bf215546Sopenharmony_ci # Small constants need to check if the buffer overflows but no else 57bf215546Sopenharmony_ci return 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci slot = (source >> 1) 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_ci self.words.add(source) 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci # Check the encoded slots 64bf215546Sopenharmony_ci slots = set([(x >> 1) for x in self.words]) 65bf215546Sopenharmony_ci die_if(len(slots) > (2 if self.message else 1), 'Too many FAU slots') 66bf215546Sopenharmony_ci die_if(len(self.words) > (3 if self.message else 2), 'Too many FAU words') 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci# When running standalone, exit with the error since we're dealing with a 69bf215546Sopenharmony_ci# human. Otherwise raise a Python exception so the test harness can handle it. 70bf215546Sopenharmony_cidef die(s): 71bf215546Sopenharmony_ci if __name__ == "__main__": 72bf215546Sopenharmony_ci print(LINE) 73bf215546Sopenharmony_ci print(s) 74bf215546Sopenharmony_ci sys.exit(1) 75bf215546Sopenharmony_ci else: 76bf215546Sopenharmony_ci raise ParseError(s) 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_cidef die_if(cond, s): 79bf215546Sopenharmony_ci if cond: 80bf215546Sopenharmony_ci die(s) 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_cidef parse_int(s, minimum, maximum): 83bf215546Sopenharmony_ci try: 84bf215546Sopenharmony_ci number = int(s, base = 0) 85bf215546Sopenharmony_ci except ValueError: 86bf215546Sopenharmony_ci die(f"Expected number {s}") 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_ci if number > maximum or number < minimum: 89bf215546Sopenharmony_ci die(f"Range error on {s}") 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci return number 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_cidef encode_source(op, fau): 94bf215546Sopenharmony_ci if op[0] == '^': 95bf215546Sopenharmony_ci die_if(op[1] != 'r', f"Expected register after discard {op}") 96bf215546Sopenharmony_ci return parse_int(op[2:], 0, 63) | 0x40 97bf215546Sopenharmony_ci elif op[0] == 'r': 98bf215546Sopenharmony_ci return parse_int(op[1:], 0, 63) 99bf215546Sopenharmony_ci elif op[0] == 'u': 100bf215546Sopenharmony_ci val = parse_int(op[1:], 0, 127) 101bf215546Sopenharmony_ci fau.set_page(val >> 6) 102bf215546Sopenharmony_ci return (val & 0x3F) | 0x80 103bf215546Sopenharmony_ci elif op[0] == 'i': 104bf215546Sopenharmony_ci return int(op[3:]) | 0xC0 105bf215546Sopenharmony_ci elif op.startswith('0x'): 106bf215546Sopenharmony_ci try: 107bf215546Sopenharmony_ci val = int(op, base=0) 108bf215546Sopenharmony_ci except ValueError: 109bf215546Sopenharmony_ci die('Expected value') 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci die_if(val not in immediates, 'Unexpected immediate value') 112bf215546Sopenharmony_ci return immediates.index(val) | 0xC0 113bf215546Sopenharmony_ci else: 114bf215546Sopenharmony_ci for i in [0, 1, 3]: 115bf215546Sopenharmony_ci if op in enums[f'fau_special_page_{i}'].bare_values: 116bf215546Sopenharmony_ci idx = 32 + (enums[f'fau_special_page_{i}'].bare_values.index(op) << 1) 117bf215546Sopenharmony_ci fau.set_page(i) 118bf215546Sopenharmony_ci return idx | 0xC0 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci die('Invalid operand') 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_cidef encode_dest(op): 124bf215546Sopenharmony_ci die_if(op[0] != 'r', f"Expected register destination {op}") 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci parts = op.split(".") 127bf215546Sopenharmony_ci reg = parts[0] 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci # Default to writing in full 130bf215546Sopenharmony_ci wrmask = 0x3 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci if len(parts) > 1: 133bf215546Sopenharmony_ci WMASKS = ["h0", "h1"] 134bf215546Sopenharmony_ci die_if(len(parts) > 2, "Too many modifiers") 135bf215546Sopenharmony_ci mask = parts[1]; 136bf215546Sopenharmony_ci die_if(mask not in WMASKS, "Expected a write mask") 137bf215546Sopenharmony_ci wrmask = 1 << WMASKS.index(mask) 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci return parse_int(reg[1:], 0, 63) | (wrmask << 6) 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_cidef parse_asm(line): 142bf215546Sopenharmony_ci global LINE 143bf215546Sopenharmony_ci LINE = line # For better errors 144bf215546Sopenharmony_ci encoded = 0 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci # Figure out mnemonic 147bf215546Sopenharmony_ci head = line.split(" ")[0] 148bf215546Sopenharmony_ci opts = [ins for ins in instructions if head.startswith(ins.name)] 149bf215546Sopenharmony_ci opts = sorted(opts, key=lambda x: len(x.name), reverse=True) 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci if len(opts) == 0: 152bf215546Sopenharmony_ci die(f"No known mnemonic for {head}") 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci if len(opts) > 1 and len(opts[0].name) == len(opts[1].name): 155bf215546Sopenharmony_ci print(f"Ambiguous mnemonic for {head}") 156bf215546Sopenharmony_ci print(f"Options:") 157bf215546Sopenharmony_ci for ins in opts: 158bf215546Sopenharmony_ci print(f" {ins}") 159bf215546Sopenharmony_ci sys.exit(1) 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci ins = opts[0] 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci # Split off modifiers 164bf215546Sopenharmony_ci if len(head) > len(ins.name) and head[len(ins.name)] != '.': 165bf215546Sopenharmony_ci die(f"Expected . after instruction in {head}") 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci mods = head[len(ins.name) + 1:].split(".") 168bf215546Sopenharmony_ci modifier_map = {} 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci tail = line[(len(head) + 1):] 171bf215546Sopenharmony_ci operands = [x.strip() for x in tail.split(",") if len(x.strip()) > 0] 172bf215546Sopenharmony_ci expected_op_count = len(ins.srcs) + len(ins.dests) + len(ins.immediates) + len(ins.staging) 173bf215546Sopenharmony_ci if len(operands) != expected_op_count: 174bf215546Sopenharmony_ci die(f"Wrong number of operands in {line}, expected {expected_op_count}, got {len(operands)} {operands}") 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci # Encode each operand 177bf215546Sopenharmony_ci for i, (op, sr) in enumerate(zip(operands, ins.staging)): 178bf215546Sopenharmony_ci die_if(op[0] != '@', f'Expected staging register, got {op}') 179bf215546Sopenharmony_ci parts = op[1:].split(':') 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci if op == '@': 182bf215546Sopenharmony_ci parts = [] 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci die_if(any([x[0] != 'r' for x in parts]), f'Expected registers, got {op}') 185bf215546Sopenharmony_ci regs = [parse_int(x[1:], 0, 63) for x in parts] 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci extended_write = "staging_register_write_count" in [x.name for x in ins.modifiers] and sr.write 188bf215546Sopenharmony_ci max_sr_count = 8 if extended_write else 7 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_ci sr_count = len(regs) 191bf215546Sopenharmony_ci die_if(sr_count > max_sr_count, f'Too many staging registers {sr_count}') 192bf215546Sopenharmony_ci 193bf215546Sopenharmony_ci base = regs[0] if len(regs) > 0 else 0 194bf215546Sopenharmony_ci die_if(any([reg != (base + i) for i, reg in enumerate(regs)]), 195bf215546Sopenharmony_ci 'Expected consecutive staging registers, got {op}') 196bf215546Sopenharmony_ci die_if(sr_count > 1 and (base % 2) != 0, 197bf215546Sopenharmony_ci 'Consecutive staging registers must be aligned to a register pair') 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci if sr.count == 0: 200bf215546Sopenharmony_ci if "staging_register_write_count" in [x.name for x in ins.modifiers] and sr.write: 201bf215546Sopenharmony_ci modifier_map["staging_register_write_count"] = sr_count - 1 202bf215546Sopenharmony_ci else: 203bf215546Sopenharmony_ci assert "staging_register_count" in [x.name for x in ins.modifiers] 204bf215546Sopenharmony_ci modifier_map["staging_register_count"] = sr_count 205bf215546Sopenharmony_ci else: 206bf215546Sopenharmony_ci die_if(sr_count != sr.count, f"Expected {sr.count} staging registers, got {sr_count}") 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci encoded |= ((sr.encoded_flags | base) << sr.start) 209bf215546Sopenharmony_ci operands = operands[len(ins.staging):] 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci for op, dest in zip(operands, ins.dests): 212bf215546Sopenharmony_ci encoded |= encode_dest(op) << 40 213bf215546Sopenharmony_ci operands = operands[len(ins.dests):] 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_ci if len(ins.dests) == 0 and len(ins.staging) == 0: 216bf215546Sopenharmony_ci # Set a placeholder writemask to prevent encoding faults 217bf215546Sopenharmony_ci encoded |= (0xC0 << 40) 218bf215546Sopenharmony_ci 219bf215546Sopenharmony_ci fau = FAUState(message = ins.message) 220bf215546Sopenharmony_ci 221bf215546Sopenharmony_ci for i, (op, src) in enumerate(zip(operands, ins.srcs)): 222bf215546Sopenharmony_ci parts = op.split('.') 223bf215546Sopenharmony_ci encoded_src = encode_source(parts[0], fau) 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci # Require a word selection for special FAU values 226bf215546Sopenharmony_ci needs_word_select = ((encoded_src >> 5) == 0b111) 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci # Has a swizzle been applied yet? 229bf215546Sopenharmony_ci swizzled = False 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci for mod in parts[1:]: 232bf215546Sopenharmony_ci # Encode the modifier 233bf215546Sopenharmony_ci if mod in src.offset and src.bits[mod] == 1: 234bf215546Sopenharmony_ci encoded |= (1 << src.offset[mod]) 235bf215546Sopenharmony_ci elif src.halfswizzle and mod in enums[f'half_swizzles_{src.size}_bit'].bare_values: 236bf215546Sopenharmony_ci die_if(swizzled, "Multiple swizzles specified") 237bf215546Sopenharmony_ci swizzled = True 238bf215546Sopenharmony_ci val = enums[f'half_swizzles_{src.size}_bit'].bare_values.index(mod) 239bf215546Sopenharmony_ci encoded |= (val << src.offset['widen']) 240bf215546Sopenharmony_ci elif mod in enums[f'swizzles_{src.size}_bit'].bare_values and (src.widen or src.lanes): 241bf215546Sopenharmony_ci die_if(swizzled, "Multiple swizzles specified") 242bf215546Sopenharmony_ci swizzled = True 243bf215546Sopenharmony_ci val = enums[f'swizzles_{src.size}_bit'].bare_values.index(mod) 244bf215546Sopenharmony_ci encoded |= (val << src.offset['widen']) 245bf215546Sopenharmony_ci elif src.lane and mod in enums[f'lane_{src.size}_bit'].bare_values: 246bf215546Sopenharmony_ci die_if(swizzled, "Multiple swizzles specified") 247bf215546Sopenharmony_ci swizzled = True 248bf215546Sopenharmony_ci val = enums[f'lane_{src.size}_bit'].bare_values.index(mod) 249bf215546Sopenharmony_ci encoded |= (val << src.offset['lane']) 250bf215546Sopenharmony_ci elif src.combine and mod in enums['combine'].bare_values: 251bf215546Sopenharmony_ci die_if(swizzled, "Multiple swizzles specified") 252bf215546Sopenharmony_ci swizzled = True 253bf215546Sopenharmony_ci val = enums['combine'].bare_values.index(mod) 254bf215546Sopenharmony_ci encoded |= (val << src.offset['combine']) 255bf215546Sopenharmony_ci elif src.size == 32 and mod in enums['widen'].bare_values: 256bf215546Sopenharmony_ci die_if(not src.swizzle, "Instruction doesn't take widens") 257bf215546Sopenharmony_ci die_if(swizzled, "Multiple swizzles specified") 258bf215546Sopenharmony_ci swizzled = True 259bf215546Sopenharmony_ci val = enums['widen'].bare_values.index(mod) 260bf215546Sopenharmony_ci encoded |= (val << src.offset['swizzle']) 261bf215546Sopenharmony_ci elif src.size == 16 and mod in enums['swizzles_16_bit'].bare_values: 262bf215546Sopenharmony_ci die_if(not src.swizzle, "Instruction doesn't take swizzles") 263bf215546Sopenharmony_ci die_if(swizzled, "Multiple swizzles specified") 264bf215546Sopenharmony_ci swizzled = True 265bf215546Sopenharmony_ci val = enums['swizzles_16_bit'].bare_values.index(mod) 266bf215546Sopenharmony_ci encoded |= (val << src.offset['swizzle']) 267bf215546Sopenharmony_ci elif mod in enums['lane_8_bit'].bare_values: 268bf215546Sopenharmony_ci die_if(not src.lane, "Instruction doesn't take a lane") 269bf215546Sopenharmony_ci die_if(swizzled, "Multiple swizzles specified") 270bf215546Sopenharmony_ci swizzled = True 271bf215546Sopenharmony_ci val = enums['lane_8_bit'].bare_values.index(mod) 272bf215546Sopenharmony_ci encoded |= (val << src.lane) 273bf215546Sopenharmony_ci elif mod in enums['lanes_8_bit'].bare_values: 274bf215546Sopenharmony_ci die_if(not src.lanes, "Instruction doesn't take a lane") 275bf215546Sopenharmony_ci die_if(swizzled, "Multiple swizzles specified") 276bf215546Sopenharmony_ci swizzled = True 277bf215546Sopenharmony_ci val = enums['lanes_8_bit'].bare_values.index(mod) 278bf215546Sopenharmony_ci encoded |= (val << src.offset['widen']) 279bf215546Sopenharmony_ci elif mod in ['w0', 'w1']: 280bf215546Sopenharmony_ci # Chck for special 281bf215546Sopenharmony_ci die_if(not needs_word_select, 'Unexpected word select') 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci if mod == 'w1': 284bf215546Sopenharmony_ci encoded_src |= 0x1 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci needs_word_select = False 287bf215546Sopenharmony_ci else: 288bf215546Sopenharmony_ci die(f"Unknown modifier {mod}") 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ci # Encode the identity if a swizzle is required but not specified 291bf215546Sopenharmony_ci if src.swizzle and not swizzled and src.size == 16: 292bf215546Sopenharmony_ci mod = enums['swizzles_16_bit'].default 293bf215546Sopenharmony_ci val = enums['swizzles_16_bit'].bare_values.index(mod) 294bf215546Sopenharmony_ci encoded |= (val << src.offset['swizzle']) 295bf215546Sopenharmony_ci elif src.widen and not swizzled and src.size == 16: 296bf215546Sopenharmony_ci die_if(swizzled, "Multiple swizzles specified") 297bf215546Sopenharmony_ci mod = enums['swizzles_16_bit'].default 298bf215546Sopenharmony_ci val = enums['swizzles_16_bit'].bare_values.index(mod) 299bf215546Sopenharmony_ci encoded |= (val << src.offset['widen']) 300bf215546Sopenharmony_ci 301bf215546Sopenharmony_ci encoded |= encoded_src << src.start 302bf215546Sopenharmony_ci fau.push(encoded_src) 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_ci operands = operands[len(ins.srcs):] 305bf215546Sopenharmony_ci 306bf215546Sopenharmony_ci for i, (op, imm) in enumerate(zip(operands, ins.immediates)): 307bf215546Sopenharmony_ci if op[0] == '#': 308bf215546Sopenharmony_ci die_if(imm.name != 'constant', "Wrong syntax for immediate") 309bf215546Sopenharmony_ci parts = [imm.name, op[1:]] 310bf215546Sopenharmony_ci else: 311bf215546Sopenharmony_ci parts = op.split(':') 312bf215546Sopenharmony_ci die_if(len(parts) != 2, f"Wrong syntax for immediate, wrong number of colons in {op}") 313bf215546Sopenharmony_ci die_if(parts[0] != imm.name, f"Wrong immediate, expected {imm.name}, got {parts[0]}") 314bf215546Sopenharmony_ci 315bf215546Sopenharmony_ci if imm.signed: 316bf215546Sopenharmony_ci minimum = -(1 << (imm.size - 1)) 317bf215546Sopenharmony_ci maximum = +(1 << (imm.size - 1)) - 1 318bf215546Sopenharmony_ci else: 319bf215546Sopenharmony_ci minimum = 0 320bf215546Sopenharmony_ci maximum = (1 << imm.size) - 1 321bf215546Sopenharmony_ci 322bf215546Sopenharmony_ci val = parse_int(parts[1], minimum, maximum) 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_ci if val < 0: 325bf215546Sopenharmony_ci # Sign extends 326bf215546Sopenharmony_ci val = (1 << imm.size) + val 327bf215546Sopenharmony_ci 328bf215546Sopenharmony_ci encoded |= (val << imm.start) 329bf215546Sopenharmony_ci 330bf215546Sopenharmony_ci operands = operands[len(ins.immediates):] 331bf215546Sopenharmony_ci 332bf215546Sopenharmony_ci # Encode the operation itself 333bf215546Sopenharmony_ci encoded |= (ins.opcode << 48) 334bf215546Sopenharmony_ci encoded |= (ins.opcode2 << ins.secondary_shift) 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci # Encode FAU page 337bf215546Sopenharmony_ci if fau.page: 338bf215546Sopenharmony_ci encoded |= (fau.page << 57) 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_ci # Encode modifiers 341bf215546Sopenharmony_ci has_flow = False 342bf215546Sopenharmony_ci for mod in mods: 343bf215546Sopenharmony_ci if len(mod) == 0: 344bf215546Sopenharmony_ci continue 345bf215546Sopenharmony_ci 346bf215546Sopenharmony_ci if mod in enums['flow'].bare_values: 347bf215546Sopenharmony_ci die_if(has_flow, "Multiple flow control modifiers specified") 348bf215546Sopenharmony_ci has_flow = True 349bf215546Sopenharmony_ci encoded |= (enums['flow'].bare_values.index(mod) << 59) 350bf215546Sopenharmony_ci else: 351bf215546Sopenharmony_ci candidates = [c for c in ins.modifiers if mod in c.bare_values] 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_ci die_if(len(candidates) == 0, f"Invalid modifier {mod} used") 354bf215546Sopenharmony_ci assert(len(candidates) == 1) # No ambiguous modifiers 355bf215546Sopenharmony_ci opts = candidates[0] 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci value = opts.bare_values.index(mod) 358bf215546Sopenharmony_ci assert(value is not None) 359bf215546Sopenharmony_ci 360bf215546Sopenharmony_ci die_if(opts.name in modifier_map, f"{opts.name} specified twice") 361bf215546Sopenharmony_ci modifier_map[opts.name] = value 362bf215546Sopenharmony_ci 363bf215546Sopenharmony_ci for mod in ins.modifiers: 364bf215546Sopenharmony_ci value = modifier_map.get(mod.name, mod.default) 365bf215546Sopenharmony_ci die_if(value is None, f"Missing required modifier {mod.name}") 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_ci assert(value < (1 << mod.size)) 368bf215546Sopenharmony_ci encoded |= (value << mod.start) 369bf215546Sopenharmony_ci 370bf215546Sopenharmony_ci return encoded 371bf215546Sopenharmony_ci 372bf215546Sopenharmony_ciif __name__ == "__main__": 373bf215546Sopenharmony_ci # Provide commandline interface 374bf215546Sopenharmony_ci parser = argparse.ArgumentParser(description='Assemble Valhall shaders') 375bf215546Sopenharmony_ci parser.add_argument('infile', nargs='?', type=argparse.FileType('r'), 376bf215546Sopenharmony_ci default=sys.stdin) 377bf215546Sopenharmony_ci parser.add_argument('outfile', type=argparse.FileType('wb')) 378bf215546Sopenharmony_ci args = parser.parse_args() 379bf215546Sopenharmony_ci 380bf215546Sopenharmony_ci lines = args.infile.read().strip().split('\n') 381bf215546Sopenharmony_ci lines = [l for l in lines if len(l) > 0 and l[0] != '#'] 382bf215546Sopenharmony_ci 383bf215546Sopenharmony_ci packed = b''.join([struct.pack('<Q', parse_asm(ln)) for ln in lines]) 384bf215546Sopenharmony_ci args.outfile.write(packed) 385