From patchwork Fri Feb 28 16:43:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Taylor Simpson X-Patchwork-Id: 11412949 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2BD9D924 for ; Fri, 28 Feb 2020 17:08:57 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E6AF624691 for ; Fri, 28 Feb 2020 17:08:56 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=quicinc.com header.i=@quicinc.com header.b="zb6pRbYR" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E6AF624691 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=quicinc.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Received: from localhost ([::1]:50984 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j7j8C-0000KV-0q for patchwork-qemu-devel@patchwork.kernel.org; Fri, 28 Feb 2020 12:08:56 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:58221) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1j7ilS-0004YS-Ux for qemu-devel@nongnu.org; Fri, 28 Feb 2020 11:45:30 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1j7ilP-0006Wr-6O for qemu-devel@nongnu.org; Fri, 28 Feb 2020 11:45:26 -0500 Received: from alexa-out-sd-01.qualcomm.com ([199.106.114.38]:13301) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1j7iks-0005cG-6t for qemu-devel@nongnu.org; Fri, 28 Feb 2020 11:45:23 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1582908290; x=1614444290; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=yGYxHfH+spxucmBWiu25yYVocsuwWLSqiw6dypnmJC4=; b=zb6pRbYRjlvtnUwHrByNFCxo26uwh4OIN4A2bNwhk6s9o17QPMnVD+ot tDoRGHogBCDNe80p+iPj2SC3AVB/fH8WOEWdQbmeFV1nLXAzwuNc4oDfP ZN2Q6JmNwtRABirqsdWlJUPJWL0ka6sLl3hdIr7tFRrlcAjFEnvpin+SZ I=; Received: from unknown (HELO ironmsg03-sd.qualcomm.com) ([10.53.140.143]) by alexa-out-sd-01.qualcomm.com with ESMTP; 28 Feb 2020 08:44:30 -0800 Received: from vu-tsimpson-aus.qualcomm.com (HELO vu-tsimpson1-aus.qualcomm.com) ([10.222.150.1]) by ironmsg03-sd.qualcomm.com with ESMTP; 28 Feb 2020 08:44:29 -0800 Received: by vu-tsimpson1-aus.qualcomm.com (Postfix, from userid 47164) id B55B7FCD; Fri, 28 Feb 2020 10:44:29 -0600 (CST) From: Taylor Simpson To: qemu-devel@nongnu.org Subject: [RFC PATCH v2 22/67] Hexagon generator phase 2 - qemu_def_generated.h Date: Fri, 28 Feb 2020 10:43:18 -0600 Message-Id: <1582908244-304-23-git-send-email-tsimpson@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1582908244-304-1-git-send-email-tsimpson@quicinc.com> References: <1582908244-304-1-git-send-email-tsimpson@quicinc.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: FreeBSD 9.x [fuzzy] X-Received-From: 199.106.114.38 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: riku.voipio@iki.fi, richard.henderson@linaro.org, laurent@vivier.eu, Taylor Simpson , philmd@redhat.com, aleksandar.m.mail@gmail.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" For each instruction we create DEF_HELPER function prototype TCG code to generate call to helper Helper definition Signed-off-by: Taylor Simpson --- target/hexagon/do_qemu.py | 769 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 769 insertions(+) create mode 100755 target/hexagon/do_qemu.py diff --git a/target/hexagon/do_qemu.py b/target/hexagon/do_qemu.py new file mode 100755 index 0000000..6f0e376 --- /dev/null +++ b/target/hexagon/do_qemu.py @@ -0,0 +1,769 @@ +#!/usr/bin/env python3 + +## +## Copyright(c) 2019-2020 Qualcomm Innovation Center, Inc. All Rights Reserved. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see . +## + +import sys +import re +import string +from io import StringIO + + +import operator +from itertools import chain + + + +behdict = {} # tag ->behavior +semdict = {} # tag -> semantics +extdict = {} # tag -> What extension an instruction belongs to (or "") +extnames = {} # ext name -> True +attribdict = {} # tag -> attributes +macros = {} # macro -> macro information... +attribinfo = {} # Register information and misc +tags = [] # list of all tags + +def get_macro(macname,ext=""): + mackey = macname + ":" + ext + if ext and mackey not in macros: + return get_macro(macname,"") + return macros[mackey] + +# We should do this as a hash for performance, +# but to keep order let's keep it as a list. +def uniquify(seq): + seen = set() + seen_add = seen.add + return [x for x in seq if x not in seen and not seen_add(x)] + +regre = re.compile( + r"((?" % l) + macro.attribs |= expand_macro_attribs( + get_macro(submacro,macro.ext), allmac_re) + finished_macros.add(macro.key) + return macro.attribs + +immextre = re.compile(r'f(MUST_)?IMMEXT[(]([UuSsRr])') +def calculate_attribs(): + # Recurse down macros, find attributes from sub-macros + macroValues = list(macros.values()) + allmacros_restr = "|".join(set([ m.re.pattern for m in macroValues ])) + allmacros_re = re.compile(allmacros_restr) + for macro in macroValues: + expand_macro_attribs(macro,allmacros_re) + # Append attributes to all instructions + for tag in tags: + for macname in allmacros_re.findall(semdict[tag]): + if not macname: continue + macro = get_macro(macname,extdict[tag]) + attribdict[tag] |= set(macro.attribs) + m = immextre.search(semdict[tag]) + if m: + if m.group(2).isupper(): + attrib = 'A_EXT_UPPER_IMMED' + elif m.group(2).islower(): + attrib = 'A_EXT_LOWER_IMMED' + else: + raise "Not a letter: %s (%s)" % (m.group(1),tag) + if not attrib in attribdict[tag]: + attribdict[tag].add(attrib) + +def SEMANTICS(tag, beh, sem): + #print tag,beh,sem + extdict[tag] = "" + behdict[tag] = beh + semdict[tag] = sem + attribdict[tag] = set() + tags.append(tag) # dicts have no order, this is for order + +def ATTRIBUTES(tag, attribstring): + attribstring = \ + attribstring.replace("ATTRIBS","").replace("(","").replace(")","") + if not attribstring: + return + attribs = attribstring.split(",") + for attrib in attribs: + attribdict[tag].add(attrib.strip()) + +class Macro(object): + __slots__ = ['key','name', 'beh', 'attribs', 're','ext'] + def __init__(self,key, name, beh, attribs,ext): + self.key = key + self.name = name + self.beh = beh + self.attribs = set(attribs) + self.ext = ext + self.re = re.compile("\\b" + name + "\\b") + +def MACROATTRIB(macname,beh,attribstring,ext=""): + attribstring = attribstring.replace("(","").replace(")","") + mackey = macname + ":" + ext + if attribstring: + attribs = attribstring.split(",") + else: + attribs = [] + macros[mackey] = Macro(mackey,macname,beh,attribs,ext) + +# read in file. Evaluate each line: each line calls a function above + +for line in open(sys.argv[1], 'rt').readlines(): + if not line.startswith("#"): + eval(line.strip()) + + +calculate_attribs() + + +attribre = re.compile(r'DEF_ATTRIB\(([A-Za-z0-9_]+), ([^,]*), ' + + r'"([A-Za-z0-9_\.]*)", "([A-Za-z0-9_\.]*)"\)') +for line in open(sys.argv[2], 'rt').readlines(): + if not attribre.match(line): + continue + (attrib_base,descr,rreg,wreg) = attribre.findall(line)[0] + attrib_base = 'A_' + attrib_base + attribinfo[attrib_base] = {'rreg':rreg, 'wreg':wreg, 'descr':descr} + +def compute_tag_regs(tag): + return uniquify(regre.findall(behdict[tag])) + +def compute_tag_immediates(tag): + return uniquify(immre.findall(behdict[tag])) + +## +## tagregs is the main data structure we'll use +## tagregs[tag] will contain the registers used by an instruction +## Within each entry, we'll use the regtype and regid fields +## regtype can be one of the following +## C control register +## N new register value +## P predicate register +## R GPR register +## M modifier register +## regid can be one of the following +## d, e destination register +## dd destination register pair +## s, t, u, v, w source register +## ss, tt, uu, vv source register pair +## x, y read-write register +## xx, yy read-write register pair +## +tagregs = dict(zip(tags, list(map(compute_tag_regs, tags)))) + +def is_pair(regid): + return len(regid) == 2 + +def is_single(regid): + return len(regid) == 1 + +def is_written(regid): + return regid[0] in "dexy" + +def is_writeonly(regid): + return regid[0] in "de" + +def is_read(regid): + return regid[0] in "stuvwxy" + +def is_readwrite(regid): + return regid[0] in "xy" + +def is_scalar_reg(regtype): + return regtype in "RPC" + +def is_old_val(regtype, regid, tag): + return regtype+regid+'V' in semdict[tag] + +def is_new_val(regtype, regid, tag): + return regtype+regid+'N' in semdict[tag] + +tagimms = dict(zip(tags, list(map(compute_tag_immediates, tags)))) + +def need_slot(tag): + if ('A_CONDEXEC' in attribdict[tag] or + 'A_STORE' in attribdict[tag]): + return 1 + else: + return 0 + +def need_part1(tag): + return re.compile(r"fPART1").search(semdict[tag]) + +def need_ea(tag): + return re.compile(r"\bEA\b").search(semdict[tag]) + +def imm_name(immlett): + return "%siV" % immlett + +## +## Helpers for gen_helper_prototype +## +def_helper_types = { + 'N' : 's32', + 'O' : 's32', + 'P' : 's32', + 'M' : 's32', + 'C' : 's32', + 'R' : 's32', + 'V' : 'ptr', + 'Q' : 'ptr' +} + +def_helper_types_pair = { + 'R' : 's64', + 'C' : 's64', + 'S' : 's64', + 'G' : 's64', + 'V' : 'ptr', + 'Q' : 'ptr' +} + +def gen_def_helper_opn(f, tag, regtype, regid, toss, numregs, i): + if (is_pair(regid)): + f.write(", %s" % (def_helper_types_pair[regtype])) + elif (is_single(regid)): + f.write(", %s" % (def_helper_types[regtype])) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +## +## Generate the DEF_HELPER prototype for an instruction +## For A2_add: Rd32=add(Rs32,Rt32) +## We produce: +## #ifndef fWRAP_A2_add +## DEF_HELPER_3(A2_add, s32, env, s32, s32) +## #endif +## +def gen_helper_prototype(f, tag, regs, imms): + f.write('#ifndef fWRAP_%s\n' % tag) + numresults = 0 + numscalarresults = 0 + numscalarreadwrite = 0 + for regtype,regid,toss,numregs in regs: + if (is_written(regid)): + numresults += 1 + if (is_scalar_reg(regtype)): + numscalarresults += 1 + if (is_readwrite(regid)): + if (is_scalar_reg(regtype)): + numscalarreadwrite += 1 + + if (numscalarresults > 1): + ## The helper is bogus when there is more than one result + f.write('DEF_HELPER_1(%s, void, env)\n' % tag) + else: + ## Figure out how many arguments the helper will take + if (numscalarresults == 0): + def_helper_size = len(regs)+len(imms)+numscalarreadwrite+1 + if need_part1(tag): def_helper_size += 1 + if need_slot(tag): def_helper_size += 1 + f.write('DEF_HELPER_%s(%s' % (def_helper_size, tag)) + ## The return type is void + f.write(', void' ) + else: + def_helper_size = len(regs)+len(imms)+numscalarreadwrite + if need_part1(tag): def_helper_size += 1 + if need_slot(tag): def_helper_size += 1 + f.write('DEF_HELPER_%s(%s' % (def_helper_size, tag)) + + ## Generate the qemu DEF_HELPER type for each result + i=0 + for regtype,regid,toss,numregs in regs: + if (is_written(regid)): + gen_def_helper_opn(f, tag, regtype, regid, toss, numregs, i) + i += 1 + + ## Put the env between the outputs and inputs + f.write(', env' ) + i += 1 + + ## Generate the qemu type for each input operand (regs and immediates) + for regtype,regid,toss,numregs in regs: + if (is_read(regid)): + gen_def_helper_opn(f, tag, regtype, regid, toss, numregs, i) + i += 1 + for immlett,bits,immshift in imms: + f.write(", s32") + + ## Add the arguments for the instruction slot and part1 (if needed) + if need_slot(tag): f.write(', i32' ) + if need_part1(tag): f.write(' , i32' ) + f.write(')\n') + f.write('#endif\n') + +## +## Helpers for gen_tcg_func +## +def gen_decl_ea_tcg(f): + f.write("DECL_EA;\n") + +def gen_free_ea_tcg(f): + f.write("FREE_EA;\n") + +def genptr_decl(f,regtype,regid,regno): + regN="%s%sN" % (regtype,regid) + macro = "DECL_%sREG_%s" % (regtype, regid) + f.write("%s(%s%sV, %s, %d, 0);\n" % \ + (macro, regtype, regid, regN, regno)) + +def genptr_decl_new(f,regtype,regid,regno): + regN="%s%sX" % (regtype,regid) + macro = "DECL_NEW_%sREG_%s" % (regtype, regid) + f.write("%s(%s%sN, %s, %d, 0);\n" % \ + (macro, regtype, regid, regN, regno)) + +def genptr_decl_opn(f, tag, regtype, regid, toss, numregs, i): + if (is_pair(regid)): + genptr_decl(f,regtype,regid,i) + elif (is_single(regid)): + if is_old_val(regtype, regid, tag): + genptr_decl(f,regtype,regid,i) + elif is_new_val(regtype, regid, tag): + genptr_decl_new(f,regtype,regid,i) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +def genptr_decl_imm(f,immlett): + if (immlett.isupper()): + i = 1 + else: + i = 0 + f.write("DECL_IMM(%s,%d);\n" % (imm_name(immlett),i)) + +def genptr_free(f,regtype,regid,regno): + macro = "FREE_%sREG_%s" % (regtype, regid) + f.write("%s(%s%sV);\n" % (macro, regtype, regid)) + +def genptr_free_new(f,regtype,regid,regno): + macro = "FREE_NEW_%sREG_%s" % (regtype, regid) + f.write("%s(%s%sN);\n" % (macro, regtype, regid)) + +def genptr_free_opn(f,regtype,regid,i): + if (is_pair(regid)): + genptr_free(f,regtype,regid,i) + elif (is_single(regid)): + if is_old_val(regtype, regid, tag): + genptr_free(f,regtype,regid,i) + elif is_new_val(regtype, regid, tag): + genptr_free_new(f,regtype,regid,i) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +def genptr_free_imm(f,immlett): + f.write("FREE_IMM(%s);\n" % (imm_name(immlett))) + +def genptr_src_read(f,regtype,regid): + macro = "READ_%sREG_%s" % (regtype, regid) + f.write("%s(%s%sV, %s%sN);\n" % \ + (macro,regtype,regid,regtype,regid)) + +def genptr_src_read_new(f,regtype,regid): + macro = "READ_NEW_%sREG_%s" % (regtype, regid) + f.write("%s(%s%sN, %s%sX);\n" % \ + (macro,regtype,regid,regtype,regid)) + +def genptr_src_read_opn(f,regtype,regid): + if (is_pair(regid)): + genptr_src_read(f,regtype,regid) + elif (is_single(regid)): + if is_old_val(regtype, regid, tag): + genptr_src_read(f,regtype,regid) + elif is_new_val(regtype, regid, tag): + genptr_src_read_new(f,regtype,regid) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +def gen_helper_call_opn(f, tag, regtype, regid, toss, numregs, i): + if (i > 0): f.write(", ") + if (is_pair(regid)): + f.write("%s%sV" % (regtype,regid)) + elif (is_single(regid)): + if is_old_val(regtype, regid, tag): + f.write("%s%sV" % (regtype,regid)) + elif is_new_val(regtype, regid, tag): + f.write("%s%sN" % (regtype,regid)) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +def gen_helper_decl_imm(f,immlett): + f.write("DECL_TCG_IMM(tcgv_%s, %s);\n" % \ + (imm_name(immlett), imm_name(immlett))) + +def gen_helper_call_imm(f,immlett): + f.write(", tcgv_%s" % imm_name(immlett)) + +def gen_helper_free_imm(f,immlett): + f.write("FREE_TCG_IMM(tcgv_%s);\n" % imm_name(immlett)) + +def genptr_dst_write(f,regtype, regid): + macro = "WRITE_%sREG_%s" % (regtype, regid) + f.write("%s(%s%sN, %s%sV);\n" % (macro, regtype, regid, regtype, regid)) + +def genptr_dst_write_opn(f,regtype, regid, tag): + if (is_pair(regid)): + genptr_dst_write(f, regtype, regid) + elif (is_single(regid)): + genptr_dst_write(f, regtype, regid) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +## +## Generate the TCG code to call the helper +## For A2_add: Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;} +## We produce: +## { +## /* A2_add */ +## DECL_RREG_d(RdV, RdN, 0, 0); +## DECL_RREG_s(RsV, RsN, 1, 0); +## DECL_RREG_t(RtV, RtN, 2, 0); +## READ_RREG_s(RsV, RsN); +## READ_RREG_t(RtV, RtN); +## fWRAP_A2_add( +## do { +## gen_helper_A2_add(RdV, cpu_env, RsV, RtV); +## while (0), +## { RdV=RsV+RtV;}); +## WRITE_RREG_d(RdN, RdV); +## FREE_RREG_d(RdV); +## FREE_RREG_s(RsV); +## FREE_RREG_t(RtV); +## /* A2_add */ +## } +## +def gen_tcg_func(f, tag, regs, imms): + f.write('{\n') + f.write('/* %s */\n' % tag) + if need_ea(tag): gen_decl_ea_tcg(f) + i=0 + ## Declare all the operands (regs and immediates) + for regtype,regid,toss,numregs in regs: + genptr_decl_opn(f, tag, regtype, regid, toss, numregs, i) + i += 1 + for immlett,bits,immshift in imms: + genptr_decl_imm(f,immlett) + + if 'A_PRIV' in attribdict[tag]: + f.write('fCHECKFORPRIV();\n') + if 'A_GUEST' in attribdict[tag]: + f.write('fCHECKFORGUEST();\n') + if 'A_FPOP' in attribdict[tag]: + f.write('fFPOP_START();\n'); + + ## Read all the inputs + for regtype,regid,toss,numregs in regs: + if (is_read(regid)): + genptr_src_read_opn(f,regtype,regid) + + ## Generate the call to the helper + f.write("fWRAP_%s(\n" % tag) + f.write("do {\n") + for immlett,bits,immshift in imms: + gen_helper_decl_imm(f,immlett) + if need_part1(tag): f.write("PART1_WRAP(") + if need_slot(tag): f.write("SLOT_WRAP(") + f.write("gen_helper_%s(" % (tag)) + i=0 + ## If there is a scalar result, it is the return type + for regtype,regid,toss,numregs in regs: + if (is_written(regid)): + gen_helper_call_opn(f, tag, regtype, regid, toss, numregs, i) + i += 1 + if (i > 0): f.write(", ") + f.write("cpu_env") + i=1 + for regtype,regid,toss,numregs in regs: + if (is_read(regid)): + gen_helper_call_opn(f, tag, regtype, regid, toss, numregs, i) + i += 1 + for immlett,bits,immshift in imms: + gen_helper_call_imm(f,immlett) + + if need_slot(tag): f.write(", slot") + if need_part1(tag): f.write(", part1" ) + f.write(")") + if need_slot(tag): f.write(")") + if need_part1(tag): f.write(")") + f.write(";\n") + for immlett,bits,immshift in imms: + gen_helper_free_imm(f,immlett) + f.write("} while (0)") + f.write(",\n%s);\n" % semdict[tag] ) + + ## Write all the outputs + for regtype,regid,toss,numregs in regs: + if (is_written(regid)): + genptr_dst_write_opn(f,regtype, regid, tag) + + if 'A_FPOP' in attribdict[tag]: + f.write('fFPOP_END();\n'); + + + ## Free all the operands (regs and immediates) + if need_ea(tag): gen_free_ea_tcg(f) + for regtype,regid,toss,numregs in regs: + genptr_free_opn(f,regtype,regid,i) + i += 1 + for immlett,bits,immshift in imms: + genptr_free_imm(f,immlett) + + f.write("/* %s */\n" % tag) + f.write("}") + +## +## Helpers for gen_helper_definition +## +def gen_decl_ea(f): + f.write("size4u_t EA;\n") + +def gen_helper_return_type(f,regtype,regid,regno): + if regno > 1 : f.write(", ") + f.write("int32_t") + +def gen_helper_return_type_pair(f,regtype,regid,regno): + if regno > 1 : f.write(", ") + f.write("int64_t") + +def gen_helper_arg(f,regtype,regid,regno): + if regno > 0 : f.write(", " ) + f.write("int32_t %s%sV" % (regtype,regid)) + +def gen_helper_arg_new(f,regtype,regid,regno): + if regno >= 0 : f.write(", " ) + f.write("int32_t %s%sN" % (regtype,regid)) + +def gen_helper_arg_pair(f,regtype,regid,regno): + if regno >= 0 : f.write(", ") + f.write("int64_t %s%sV" % (regtype,regid)) + +def gen_helper_arg_opn(f,regtype,regid,i): + if (is_pair(regid)): + gen_helper_arg_pair(f,regtype,regid,i) + elif (is_single(regid)): + if is_old_val(regtype, regid, tag): + gen_helper_arg(f,regtype,regid,i) + elif is_new_val(regtype, regid, tag): + gen_helper_arg_new(f,regtype,regid,i) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +def gen_helper_arg_imm(f,immlett): + f.write(", int32_t %s" % (imm_name(immlett))) + +def gen_helper_dest_decl(f,regtype,regid,regno,subfield=""): + f.write("int32_t %s%sV%s = 0;\n" % \ + (regtype,regid,subfield)) + +def gen_helper_dest_decl_pair(f,regtype,regid,regno,subfield=""): + f.write("int64_t %s%sV%s = 0;\n" % \ + (regtype,regid,subfield)) + +def gen_helper_dest_decl_opn(f,regtype,regid,i): + if (is_pair(regid)): + gen_helper_dest_decl_pair(f,regtype,regid,i) + elif (is_single(regid)): + gen_helper_dest_decl(f,regtype,regid,i) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +def gen_helper_return(f,regtype,regid,regno): + f.write("return %s%sV;\n" % (regtype,regid)) + +def gen_helper_return_pair(f,regtype,regid,regno): + f.write("return %s%sV;\n" % (regtype,regid)) + +def gen_helper_return_opn(f, regtype, regid, i): + if (is_pair(regid)): + gen_helper_return_pair(f,regtype,regid,i) + elif (is_single(regid)): + gen_helper_return(f,regtype,regid,i) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +## +## Generate the TCG code to call the helper +## For A2_add: Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;} +## We produce: +## #ifndef fWRAP_A2_add +## int32_t HELPER(A2_add)(CPUHexagonState *env, int32_t RsV, int32_t RtV) +## { +## uint32_t slot = 4; slot = slot; +## int32_t RdV = 0; +## { RdV=RsV+RtV;} +## COUNT_HELPER(A2_add); +## return RdV; +## } +## #endif +## +def gen_helper_definition(f, tag, regs, imms): + f.write('#ifndef fWRAP_%s\n' % tag) + numresults = 0 + numscalarresults = 0 + numscalarreadwrite = 0 + for regtype,regid,toss,numregs in regs: + if (is_written(regid)): + numresults += 1 + if (is_scalar_reg(regtype)): + numscalarresults += 1 + if (is_readwrite(regid)): + if (is_scalar_reg(regtype)): + numscalarreadwrite += 1 + + if (numscalarresults > 1): + ## The helper is bogus when there is more than one result + f.write("void HELPER(%s)(CPUHexagonState *env) { BOGUS_HELPER(%s); }\n" + % (tag, tag)) + else: + ## The return type of the function is the type of the destination + ## register + i=0 + for regtype,regid,toss,numregs in regs: + if (is_written(regid)): + if (is_pair(regid)): + gen_helper_return_type_pair(f,regtype,regid,i) + elif (is_single(regid)): + gen_helper_return_type(f,regtype,regid,i) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + i += 1 + + if (numscalarresults == 0): + f.write("void") + f.write(" HELPER(%s)(CPUHexagonState *env" % tag) + + i = 1 + ## Arguments to the helper function are the source regs and immediates + for regtype,regid,toss,numregs in regs: + if (is_read(regid)): + gen_helper_arg_opn(f,regtype,regid,i) + i += 1 + for immlett,bits,immshift in imms: + gen_helper_arg_imm(f,immlett) + i += 1 + if need_slot(tag): + if i > 0: f.write(", ") + f.write("uint32_t slot") + i += 1 + if need_part1(tag): + if i > 0: f.write(", ") + f.write("uint32_t part1") + f.write(")\n{\n") + if (not need_slot(tag)): f.write("uint32_t slot = 4; slot = slot;\n" ) + if need_ea(tag): gen_decl_ea(f) + ## Declare the return variable + i=0 + for regtype,regid,toss,numregs in regs: + if (is_writeonly(regid)): + gen_helper_dest_decl_opn(f,regtype,regid,i) + i += 1 + + if 'A_FPOP' in attribdict[tag]: + f.write('fFPOP_START();\n'); + + f.write(semdict[tag]) + f.write("\n") + f.write("COUNT_HELPER(%s);\n" % tag ) + + if 'A_FPOP' in attribdict[tag]: + f.write('fFPOP_END();\n'); + + ## Save/return the return variable + for regtype,regid,toss,numregs in regs: + if (is_written(regid)): + gen_helper_return_opn(f, regtype, regid, i) + f.write("}\n") + ## End of the helper definition + f.write('#endif\n') + +## +## Bring it all together in the DEF_QEMU macro +## +def gen_qemu(f, tag): + regs = tagregs[tag] + imms = tagimms[tag] + + f.write('DEF_QEMU(%s,%s,\n' % (tag,semdict[tag])) + gen_helper_prototype(f, tag, regs, imms) + f.write(",\n" ) + gen_tcg_func(f, tag, regs, imms) + f.write(",\n" ) + gen_helper_definition(f, tag, regs, imms) + f.write(")\n") + +## +## Generate the qemu_def_generated.h file +## +f = StringIO() + +f.write("#ifndef DEF_QEMU\n") +f.write("#define DEF_QEMU(TAG,SHORTCODE,HELPER,GENFN,HELPFN) /* Nothing */\n") +f.write("#endif\n\n") + + +for tag in tags: + ## Skip assembler mapped instructions + if "A_MAPPING" in attribdict[tag]: + continue + ## Skip the fake instructions + if ( "A_FAKEINSN" in attribdict[tag] ) : + continue + ## Skip the priv instructions + if ( "A_PRIV" in attribdict[tag] ) : + continue + ## Skip the guest instructions + if ( "A_GUEST" in attribdict[tag] ) : + continue + ## Skip the diag instructions + if ( tag == "Y6_diag" ) : + continue + if ( tag == "Y6_diag0" ) : + continue + if ( tag == "Y6_diag1" ) : + continue + + gen_qemu(f, tag) + +realf = open('qemu_def_generated.h','w') +realf.write(f.getvalue()) +realf.close() +f.close() +