119 changes: 119 additions & 0 deletions roms/edk2-build.config
@@ -0,0 +1,119 @@
[global]
core = edk2

####################################################################################
# options

[opts.common]
NETWORK_HTTP_BOOT_ENABLE = TRUE
NETWORK_IP6_ENABLE = TRUE
NETWORK_TLS_ENABLE = TRUE
NETWORK_ISCSI_ENABLE = TRUE
NETWORK_ALLOW_HTTP_CONNECTIONS = TRUE
TPM2_ENABLE = TRUE
TPM2_CONFIG_ENABLE = TRUE
TPM1_ENABLE = TRUE
CAVIUM_ERRATUM_27456 = TRUE

[opts.ovmf.sb.smm]
SECURE_BOOT_ENABLE = TRUE
SMM_REQUIRE = TRUE

[pcds.nx.broken.grub]
# grub.efi uses EfiLoaderData for code
PcdDxeNxMemoryProtectionPolicy = 0xC000000000007FD1

####################################################################################
# i386

[build.ovmf.i386]
desc = ovmf build (32-bit)
conf = OvmfPkg/OvmfPkgIa32.dsc
arch = IA32
opts = common
plat = OvmfIa32
dest = ../pc-bios
cpy1 = FV/OVMF_CODE.fd edk2-i386-code.fd
cpy2 = FV/OVMF_VARS.fd edk2-i386-vars.fd

[build.ovmf.i386.secure]
desc = ovmf build (32-bit, secure boot)
conf = OvmfPkg/OvmfPkgIa32.dsc
arch = IA32
opts = common
ovmf.sb.smm
plat = OvmfIa32
dest = ../pc-bios
cpy1 = FV/OVMF_CODE.fd edk2-i386-secure-code.fd

####################################################################################
# x86_64

[build.ovmf.x86_64]
desc = ovmf build (64-bit)
conf = OvmfPkg/OvmfPkgX64.dsc
arch = X64
opts = common
plat = OvmfX64
dest = ../pc-bios
cpy1 = FV/OVMF_CODE.fd edk2-x86_64-code.fd

[build.ovmf.x86_64.secure]
desc = ovmf build (64-bit, secure boot)
conf = OvmfPkg/OvmfPkgIa32X64.dsc
arch = IA32 X64
opts = common
ovmf.sb.smm
plat = Ovmf3264
dest = ../pc-bios
cpy1 = FV/OVMF_CODE.fd edk2-x86_64-secure-code.fd

[build.ovmf.microvm]
desc = ovmf build for microvm
conf = OvmfPkg/Microvm/MicrovmX64.dsc
arch = X64
opts = common
plat = MicrovmX64
dest = ../pc-bios
cpy1 = FV/MICROVM.fd edk2-x86_64-microvm.fd

####################################################################################
# arm

[build.armvirt.arm]
desc = ArmVirt build, 32-bit (arm v7)
conf = ArmVirtPkg/ArmVirtQemu.dsc
arch = ARM
opts = common
pcds = nx.broken.grub
plat = ArmVirtQemu-ARM
dest = ../pc-bios
cpy1 = FV/QEMU_EFI.fd edk2-arm-code.fd
cpy2 = FV/QEMU_VARS.fd edk2-arm-vars.fd
pad1 = edk2-arm-code.fd 64m
pad2 = edk2-arm-vars.fd 64m

####################################################################################
# aarch64

[build.armvirt.aa64]
desc = ArmVirt build, 64-bit (arm v8)
conf = ArmVirtPkg/ArmVirtQemu.dsc
arch = AARCH64
opts = common
pcds = nx.broken.grub
plat = ArmVirtQemu-AARCH64
dest = ../pc-bios
cpy1 = FV/QEMU_EFI.fd edk2-aarch64-code.fd
pad1 = edk2-aarch64-code.fd 64m

####################################################################################
# riscv64

[build.riscv.qemu]
conf = OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
arch = RISCV64
plat = RiscVVirtQemu
dest = ../pc-bios
cpy1 = FV/RISCV_VIRT.fd edk2-riscv.fd
pad1 = edk2-riscv.fd 32m
372 changes: 372 additions & 0 deletions roms/edk2-build.py
@@ -0,0 +1,372 @@
#!/usr/bin/python3
"""
build helper script for edk2, see
https://gitlab.com/kraxel/edk2-build-config
"""
import os
import sys
import glob
import shutil
import optparse
import subprocess
import configparser

rebase_prefix = ""
version_override = None
release_date = None

def check_rebase():
""" detect 'git rebase -x edk2-build.py master' testbuilds """
global rebase_prefix
global version_override
gitdir = '.git'

if os.path.isfile(gitdir):
with open(gitdir) as f:
(unused, gitdir) = f.read().split()

if not os.path.exists(f'{gitdir}/rebase-merge/msgnum'):
return ""
with open(f'{gitdir}/rebase-merge/msgnum', 'r') as f:
msgnum = int(f.read())
with open(f'{gitdir}/rebase-merge/end', 'r') as f:
end = int(f.read())
with open(f'{gitdir}/rebase-merge/head-name', 'r') as f:
head = f.read().strip().split('/')

rebase_prefix = f'[ {int(msgnum/2)} / {int(end/2)} - {head[-1]} ] '
if msgnum != end and not version_override:
# fixed version speeds up builds
version_override = "test-build-patch-series"

def get_coredir(cfg):
if cfg.has_option('global', 'core'):
return os.path.abspath(cfg['global']['core'])
else:
return os.getcwd()

def get_version(cfg):
coredir = get_coredir(cfg)
if version_override:
version = version_override
print('')
print(f'### version [override]: {version}')
return version
if os.environ.get('RPM_PACKAGE_NAME'):
version = os.environ.get('RPM_PACKAGE_NAME');
version += '-' + os.environ.get('RPM_PACKAGE_VERSION');
version += '-' + os.environ.get('RPM_PACKAGE_RELEASE');
print('')
print(f'### version [rpmbuild]: {version}')
return version
if os.path.exists(coredir + '/.git'):
cmdline = [ 'git', 'describe', '--tags', '--abbrev=8',
'--match=edk2-stable*' ]
result = subprocess.run(cmdline, cwd = coredir,
stdout = subprocess.PIPE)
version = result.stdout.decode().strip()
print('')
print(f'### version [git]: {version}')
return version
return None

def pcd_string(name, value):
return f'{name}=L{value}\\0'

def pcd_version(cfg):
version = get_version(cfg)
if version is None:
return []
return [ '--pcd', pcd_string('PcdFirmwareVersionString', version) ]

def pcd_release_date(cfg):
if release_date is None:
return []
return [ '--pcd', pcd_string('PcdFirmwareReleaseDateString', release_date) ]

def build_message(line, line2 = None):
if os.environ.get('TERM') in [ 'xterm', 'xterm-256color' ]:
# setxterm title
start = '\x1b]2;'
end = '\x07'
print(f'{start}{rebase_prefix}{line}{end}', end = '')

print('')
print('###')
print(f'### {rebase_prefix}{line}')
if line2:
print(f'### {line2}')
print('###')

def build_run(cmdline, name, section, silent = False):
print(cmdline)
if silent:
print('### building in silent mode ...', flush = True)
result = subprocess.run(cmdline,
stdout = subprocess.PIPE,
stderr = subprocess.STDOUT)

logfile = f'{section}.log'
print(f'### writing log to {logfile} ...')
with open(logfile, 'wb') as f:
f.write(result.stdout)

if result.returncode:
print('### BUILD FAILURE')
print('### output')
print(result.stdout.decode())
print(f'### exit code: {result.returncode}')
else:
print('### OK')
else:
result = subprocess.run(cmdline)
if result.returncode:
print(f'ERROR: {cmdline[0]} exited with {result.returncode}'
f' while building {name}')
sys.exit(result.returncode)

def build_copy(plat, tgt, dstdir, copy):
srcdir = f'Build/{plat}/{tgt}_GCC5'
names = copy.split()
srcfile = names[0]
if len(names) > 1:
dstfile = names[1]
else:
dstfile = os.path.basename(srcfile)
print(f'# copy: {srcdir} / {srcfile} => {dstdir} / {dstfile}')

src = srcdir + '/' + srcfile
dst = dstdir + '/' + dstfile
os.makedirs(os.path.dirname(dst), exist_ok = True)
shutil.copy(src, dst)

def pad_file(dstdir, pad):
args = pad.split()
if len(args) < 2:
raise RuntimeError(f'missing arg for pad ({args})')
name = args[0]
size = args[1]
cmdline = [
'truncate',
'--size', size,
dstdir + '/' + name,
]
print(f'# padding: {dstdir} / {name} => {size}')
subprocess.run(cmdline)

def build_one(cfg, build, jobs = None, silent = False):
cmdline = [ 'build' ]
cmdline += [ '-t', 'GCC5' ]
cmdline += [ '-p', cfg[build]['conf'] ]

if (cfg[build]['conf'].startswith('OvmfPkg/') or
cfg[build]['conf'].startswith('ArmVirtPkg/')):
cmdline += pcd_version(cfg)
cmdline += pcd_release_date(cfg)

if jobs:
cmdline += [ '-n', jobs ]
for arch in cfg[build]['arch'].split():
cmdline += [ '-a', arch ]
if 'opts' in cfg[build]:
for name in cfg[build]['opts'].split():
section = 'opts.' + name
for opt in cfg[section]:
cmdline += [ '-D', opt + '=' + cfg[section][opt] ]
if 'pcds' in cfg[build]:
for name in cfg[build]['pcds'].split():
section = 'pcds.' + name
for pcd in cfg[section]:
cmdline += [ '--pcd', pcd + '=' + cfg[section][pcd] ]
if 'tgts' in cfg[build]:
tgts = cfg[build]['tgts'].split()
else:
tgts = [ 'DEBUG' ]
for tgt in tgts:
desc = None
if 'desc' in cfg[build]:
desc = cfg[build]['desc']
build_message(f'building: {cfg[build]["conf"]} ({cfg[build]["arch"]}, {tgt})',
f'description: {desc}')
build_run(cmdline + [ '-b', tgt ],
cfg[build]['conf'],
build + '.' + tgt,
silent)

if 'plat' in cfg[build]:
# copy files
for cpy in cfg[build]:
if not cpy.startswith('cpy'):
continue
build_copy(cfg[build]['plat'],
tgt,
cfg[build]['dest'],
cfg[build][cpy])
# pad builds
for pad in cfg[build]:
if not pad.startswith('pad'):
continue
pad_file(cfg[build]['dest'],
cfg[build][pad])

def build_basetools(silent = False):
build_message(f'building: BaseTools')
basedir = os.environ['EDK_TOOLS_PATH']
cmdline = [ 'make', '-C', basedir ]
build_run(cmdline, 'BaseTools', 'build.basetools', silent)

def binary_exists(name):
for dir in os.environ['PATH'].split(':'):
if os.path.exists(dir + '/' + name):
return True
return False

def prepare_env(cfg):
""" mimic Conf/BuildEnv.sh """
workspace = os.getcwd()
packages = [ workspace, ]
path = os.environ['PATH'].split(':')
dirs = [
'BaseTools/Bin/Linux-x86_64',
'BaseTools/BinWrappers/PosixLike'
]

if cfg.has_option('global', 'pkgs'):
for pkgdir in cfg['global']['pkgs'].split():
packages.append(os.path.abspath(pkgdir))
coredir = get_coredir(cfg)
if coredir != workspace:
packages.append(coredir)

# add basetools to path
for dir in dirs:
p = coredir + '/' + dir
if not os.path.exists(p):
continue
if p in path:
continue
path.insert(0, p)

# run edksetup if needed
toolsdef = coredir + '/Conf/tools_def.txt';
if not os.path.exists(toolsdef):
os.makedirs(os.path.dirname(toolsdef), exist_ok = True)
build_message('running BaseTools/BuildEnv')
cmdline = [ 'sh', 'BaseTools/BuildEnv' ]
subprocess.run(cmdline, cwd = coredir)

# set variables
os.environ['PATH'] = ':'.join(path)
os.environ['PACKAGES_PATH'] = ':'.join(packages)
os.environ['WORKSPACE'] = workspace
os.environ['EDK_TOOLS_PATH'] = coredir + '/BaseTools'
os.environ['CONF_PATH'] = coredir + '/Conf'
os.environ['PYTHON_COMMAND'] = '/usr/bin/python3'
os.environ['PYTHONHASHSEED'] = '1'

# for cross builds
if binary_exists('arm-linux-gnu-gcc'):
os.environ['GCC5_ARM_PREFIX'] = 'arm-linux-gnu-'
if binary_exists('loongarch64-linux-gnu-gcc'):
os.environ['GCC5_LOONGARCH64_PREFIX'] = 'loongarch64-linux-gnu-'

hostarch = os.uname().machine
if binary_exists('aarch64-linux-gnu-gcc') and hostarch != 'aarch64':
os.environ['GCC5_AARCH64_PREFIX'] = 'aarch64-linux-gnu-'
if binary_exists('riscv64-linux-gnu-gcc') and hostarch != 'riscv64':
os.environ['GCC5_RISCV64_PREFIX'] = 'riscv64-linux-gnu-'
if binary_exists('x86_64-linux-gnu-gcc') and hostarch != 'x86_64':
os.environ['GCC5_IA32_PREFIX'] = 'x86_64-linux-gnu-'
os.environ['GCC5_X64_PREFIX'] = 'x86_64-linux-gnu-'
os.environ['GCC5_BIN'] = 'x86_64-linux-gnu-'

def build_list(cfg):
for build in cfg.sections():
if not build.startswith('build.'):
continue
name = build.lstrip('build.')
desc = 'no description'
if 'desc' in cfg[build]:
desc = cfg[build]['desc']
print(f'# {name:20s} - {desc}')

def main():
parser = optparse.OptionParser()
parser.add_option('-c', '--config', dest = 'configfile',
type = 'string', default = '.edk2.builds', metavar = 'FILE',
help = 'read configuration from FILE (default: .edk2.builds)')
parser.add_option('-C', '--directory', dest = 'directory', type = 'string',
help = 'change to DIR before building', metavar = 'DIR')
parser.add_option('-j', '--jobs', dest = 'jobs', type = 'string',
help = 'allow up to JOBS parallel build jobs',
metavar = 'JOBS')
parser.add_option('-m', '--match', dest = 'match', type = 'string',
help = 'only run builds matching INCLUDE (substring)',
metavar = 'INCLUDE')
parser.add_option('-x', '--exclude', dest = 'exclude', type = 'string',
help = 'skip builds matching EXCLUDE (substring)',
metavar = 'EXCLUDE')
parser.add_option('-l', '--list', dest = 'list',
action = 'store_true', default = False,
help = 'list build configs available')
parser.add_option('--silent', dest = 'silent',
action = 'store_true', default = False,
help = 'write build output to logfiles, '
'write to console only on errors')
parser.add_option('--core', dest = 'core', type = 'string', metavar = 'DIR',
help = 'location of the core edk2 repository '
'(i.e. where BuildTools are located)')
parser.add_option('--pkg', '--package', dest = 'pkgs',
type = 'string', action = 'append', metavar = 'DIR',
help = 'location(s) of additional packages '
'(can be specified multiple times)')
parser.add_option('--version-override', dest = 'version_override',
type = 'string', metavar = 'VERSION',
help = 'set firmware build version')
parser.add_option('--release-date', dest = 'release_date',
type = 'string', metavar = 'DATE',
help = 'set firmware build release date (in MM/DD/YYYY format)')
(options, args) = parser.parse_args()

if options.directory:
os.chdir(options.directory)

cfg = configparser.ConfigParser()
cfg.optionxform = str
cfg.read(options.configfile)

if options.list:
build_list(cfg)
return

if not cfg.has_section('global'):
cfg.add_section('global')
if options.core:
cfg.set('global', 'core', options.core)
if options.pkgs:
cfg.set('global', 'pkgs', ' '.join(options.pkgs))

global version_override
global release_date
check_rebase()
if options.version_override:
version_override = options.version_override
if options.release_date:
release_date = options.release_date

prepare_env(cfg)
build_basetools(options.silent)
for build in cfg.sections():
if not build.startswith('build.'):
continue
if options.match and options.match not in build:
print(f'# skipping "{build}" (not matching "{options.match}")')
continue
if options.exclude and options.exclude in build:
print(f'# skipping "{build}" (matching "{options.exclude}")')
continue
build_one(cfg, build, options.jobs, options.silent)

if __name__ == '__main__':
sys.exit(main())
55 changes: 0 additions & 55 deletions roms/edk2-build.sh

This file was deleted.

273 changes: 0 additions & 273 deletions roms/edk2-funcs.sh

This file was deleted.

31 changes: 12 additions & 19 deletions target/hexagon/README
Expand Up @@ -52,6 +52,7 @@ header files in <BUILD_DIR>/target/hexagon
gen_tcg_func_table.py -> tcg_func_table_generated.c.inc
gen_helper_funcs.py -> helper_funcs_generated.c.inc
gen_idef_parser_funcs.py -> idef_parser_input.h
gen_analyze_funcs.py -> analyze_funcs_generated.c.inc

Qemu helper functions have 3 parts
DEF_HELPER declaration indicates the signature of the helper
Expand Down Expand Up @@ -87,7 +88,6 @@ tcg_funcs_generated.c.inc
TCGv RtV = hex_gpr[insn->regno[2]];
gen_helper_A2_add(RdV, cpu_env, RsV, RtV);
gen_log_reg_write(RdN, RdV);
ctx_log_reg_write(ctx, RdN);
}

helper_funcs_generated.c.inc
Expand Down Expand Up @@ -136,12 +136,9 @@ For HVX vectors, the generator behaves slightly differently. The wide vectors
won't fit in a TCGv or TCGv_i64, so we pass TCGv_ptr variables to pass the
address to helper functions. Here's an example for an HVX vector-add-word
istruction.
static void generate_V6_vaddw(
CPUHexagonState *env,
DisasContext *ctx,
Insn *insn,
Packet *pkt)
static void generate_V6_vaddw(DisasContext *ctx)
{
Insn *insn __attribute__((unused)) = ctx->insn;
const int VdN = insn->regno[0];
const intptr_t VdV_off =
ctx_future_vreg_off(ctx, VdN, 1, true);
Expand All @@ -157,10 +154,7 @@ istruction.
TCGv_ptr VvV = tcg_temp_new_ptr();
tcg_gen_addi_ptr(VuV, cpu_env, VuV_off);
tcg_gen_addi_ptr(VvV, cpu_env, VvV_off);
TCGv slot = tcg_constant_tl(insn->slot);
gen_helper_V6_vaddw(cpu_env, VdV, VuV, VvV, slot);
gen_log_vreg_write(ctx, VdV_off, VdN, EXT_DFL, insn->slot, false);
ctx_log_vreg_write(ctx, VdN, EXT_DFL, false);
gen_helper_V6_vaddw(cpu_env, VdV, VuV, VvV);
}

Notice that we also generate a variable named <operand>_off for each operand of
Expand All @@ -173,12 +167,9 @@ functions from tcg-op-gvec.h. Here's the override for this instruction.
Finally, we notice that the override doesn't use the TCGv_ptr variables, so
we don't generate them when an override is present. Here is what we generate
when the override is present.
static void generate_V6_vaddw(
CPUHexagonState *env,
DisasContext *ctx,
Insn *insn,
Packet *pkt)
static void generate_V6_vaddw(DisasContext *ctx)
{
Insn *insn __attribute__((unused)) = ctx->insn;
const int VdN = insn->regno[0];
const intptr_t VdV_off =
ctx_future_vreg_off(ctx, VdN, 1, true);
Expand All @@ -189,10 +180,14 @@ when the override is present.
const intptr_t VvV_off =
vreg_src_off(ctx, VvN);
fGEN_TCG_V6_vaddw({ fHIDE(int i;) fVFOREACH(32, i) { VdV.w[i] = VuV.w[i] + VvV.w[i] ; } });
gen_log_vreg_write(ctx, VdV_off, VdN, EXT_DFL, insn->slot, false);
ctx_log_vreg_write(ctx, VdN, EXT_DFL, false);
}

We also generate an analyze_<tag> function for each instruction. Currently,
these functions record the writes to registers by calling ctx_log_*. During
gen_start_packet, we invoke the analyze_<tag> function for each instruction in
the packet, and we mark the implicit writes. After the analysis is performed,
we initialize hex_new_value for each of the predicated assignments.

In addition to instruction semantics, we use a generator to create the decode
tree. This generation is also a two step process. The first step is to run
target/hexagon/gen_dectree_import.c to produce
Expand Down Expand Up @@ -277,10 +272,8 @@ For Hexagon Vector eXtensions (HVX), the following fields are used
VRegs Vector registers
future_VRegs Registers to be stored during packet commit
tmp_VRegs Temporary registers *not* stored during commit
VRegs_updated Mask of predicated vector writes
QRegs Q (vector predicate) registers
future_QRegs Registers to be stored during packet commit
QRegs_updated Mask of predicated vector writes

*** Debugging ***

Expand Down
1 change: 1 addition & 0 deletions target/hexagon/attribs_def.h.inc
Expand Up @@ -44,6 +44,7 @@ DEF_ATTRIB(MEMSIZE_1B, "Memory width is 1 byte", "", "")
DEF_ATTRIB(MEMSIZE_2B, "Memory width is 2 bytes", "", "")
DEF_ATTRIB(MEMSIZE_4B, "Memory width is 4 bytes", "", "")
DEF_ATTRIB(MEMSIZE_8B, "Memory width is 8 bytes", "", "")
DEF_ATTRIB(SCALAR_LOAD, "Load is scalar", "", "")
DEF_ATTRIB(SCALAR_STORE, "Store is scalar", "", "")
DEF_ATTRIB(REGWRSIZE_1B, "Memory width is 1 byte", "", "")
DEF_ATTRIB(REGWRSIZE_2B, "Memory width is 2 bytes", "", "")
Expand Down
5 changes: 1 addition & 4 deletions target/hexagon/cpu.h
@@ -1,5 +1,5 @@
/*
* Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
* Copyright(c) 2019-2023 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
Expand Down Expand Up @@ -111,11 +111,8 @@ typedef struct CPUArchState {
MMVector future_VRegs[VECTOR_TEMPS_MAX] QEMU_ALIGNED(16);
MMVector tmp_VRegs[VECTOR_TEMPS_MAX] QEMU_ALIGNED(16);

VRegMask VRegs_updated;

MMQReg QRegs[NUM_QREGS] QEMU_ALIGNED(16);
MMQReg future_QRegs[NUM_QREGS] QEMU_ALIGNED(16);
QRegMask QRegs_updated;

/* Temporaries used within instructions */
MMVectorPair VuuV QEMU_ALIGNED(16);
Expand Down
252 changes: 252 additions & 0 deletions target/hexagon/gen_analyze_funcs.py
@@ -0,0 +1,252 @@
#!/usr/bin/env python3

##
## Copyright(c) 2022-2023 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 <http://www.gnu.org/licenses/>.
##

import sys
import re
import string
import hex_common

##
## Helpers for gen_analyze_func
##
def is_predicated(tag):
return 'A_CONDEXEC' in hex_common.attribdict[tag]

def analyze_opn_old(f, tag, regtype, regid, regno):
regN = "%s%sN" % (regtype, regid)
predicated = "true" if is_predicated(tag) else "false"
if (regtype == "R"):
if (regid in {"ss", "tt"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
elif (regid in {"dd", "ee", "xx", "yy"}):
f.write(" const int %s = insn->regno[%d];\n" % (regN, regno))
f.write(" ctx_log_reg_write_pair(ctx, %s, %s);\n" % \
(regN, predicated))
elif (regid in {"s", "t", "u", "v"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
elif (regid in {"d", "e", "x", "y"}):
f.write(" const int %s = insn->regno[%d];\n" % (regN, regno))
f.write(" ctx_log_reg_write(ctx, %s, %s);\n" % \
(regN, predicated))
else:
print("Bad register parse: ", regtype, regid)
elif (regtype == "P"):
if (regid in {"s", "t", "u", "v"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
elif (regid in {"d", "e", "x"}):
f.write(" const int %s = insn->regno[%d];\n" % (regN, regno))
f.write(" ctx_log_pred_write(ctx, %s);\n" % (regN))
else:
print("Bad register parse: ", regtype, regid)
elif (regtype == "C"):
if (regid == "ss"):
f.write("// const int %s = insn->regno[%d] + HEX_REG_SA0;\n" % \
(regN, regno))
elif (regid == "dd"):
f.write(" const int %s = insn->regno[%d] + HEX_REG_SA0;\n" % \
(regN, regno))
f.write(" ctx_log_reg_write_pair(ctx, %s, %s);\n" % \
(regN, predicated))
elif (regid == "s"):
f.write("// const int %s = insn->regno[%d] + HEX_REG_SA0;\n" % \
(regN, regno))
elif (regid == "d"):
f.write(" const int %s = insn->regno[%d] + HEX_REG_SA0;\n" % \
(regN, regno))
f.write(" ctx_log_reg_write(ctx, %s, %s);\n" % \
(regN, predicated))
else:
print("Bad register parse: ", regtype, regid)
elif (regtype == "M"):
if (regid == "u"):
f.write("// const int %s = insn->regno[%d];\n"% \
(regN, regno))
else:
print("Bad register parse: ", regtype, regid)
elif (regtype == "V"):
newv = "EXT_DFL"
if (hex_common.is_new_result(tag)):
newv = "EXT_NEW"
elif (hex_common.is_tmp_result(tag)):
newv = "EXT_TMP"
if (regid in {"dd", "xx"}):
f.write(" const int %s = insn->regno[%d];\n" %\
(regN, regno))
f.write(" ctx_log_vreg_write_pair(ctx, %s, %s, %s);\n" % \
(regN, newv, predicated))
elif (regid in {"uu", "vv"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
elif (regid in {"s", "u", "v", "w"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
elif (regid in {"d", "x", "y"}):
f.write(" const int %s = insn->regno[%d];\n" % \
(regN, regno))
f.write(" ctx_log_vreg_write(ctx, %s, %s, %s);\n" % \
(regN, newv, predicated))
else:
print("Bad register parse: ", regtype, regid)
elif (regtype == "Q"):
if (regid in {"d", "e", "x"}):
f.write(" const int %s = insn->regno[%d];\n" % \
(regN, regno))
f.write(" ctx_log_qreg_write(ctx, %s);\n" % (regN))
elif (regid in {"s", "t", "u", "v"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
else:
print("Bad register parse: ", regtype, regid)
elif (regtype == "G"):
if (regid in {"dd"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
elif (regid in {"d"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
elif (regid in {"ss"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
elif (regid in {"s"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
else:
print("Bad register parse: ", regtype, regid)
elif (regtype == "S"):
if (regid in {"dd"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
elif (regid in {"d"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
elif (regid in {"ss"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
elif (regid in {"s"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
else:
print("Bad register parse: ", regtype, regid)
else:
print("Bad register parse: ", regtype, regid)

def analyze_opn_new(f, tag, regtype, regid, regno):
regN = "%s%sN" % (regtype, regid)
if (regtype == "N"):
if (regid in {"s", "t"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
else:
print("Bad register parse: ", regtype, regid)
elif (regtype == "P"):
if (regid in {"t", "u", "v"}):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
else:
print("Bad register parse: ", regtype, regid)
elif (regtype == "O"):
if (regid == "s"):
f.write("// const int %s = insn->regno[%d];\n" % \
(regN, regno))
else:
print("Bad register parse: ", regtype, regid)
else:
print("Bad register parse: ", regtype, regid)

def analyze_opn(f, tag, regtype, regid, toss, numregs, i):
if (hex_common.is_pair(regid)):
analyze_opn_old(f, tag, regtype, regid, i)
elif (hex_common.is_single(regid)):
if hex_common.is_old_val(regtype, regid, tag):
analyze_opn_old(f,tag, regtype, regid, i)
elif hex_common.is_new_val(regtype, regid, tag):
analyze_opn_new(f, tag, regtype, regid, i)
else:
print("Bad register parse: ", regtype, regid, toss, numregs)
else:
print("Bad register parse: ", regtype, regid, toss, numregs)

##
## Generate the code to analyze the instruction
## For A2_add: Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;}
## We produce:
## static void analyze_A2_add(DisasContext *ctx)
## {
## Insn *insn G_GNUC_UNUSED = ctx->insn;
## const int RdN = insn->regno[0];
## ctx_log_reg_write(ctx, RdN, false);
## // const int RsN = insn->regno[1];
## // const int RtN = insn->regno[2];
## }
##
def gen_analyze_func(f, tag, regs, imms):
f.write("static void analyze_%s(DisasContext *ctx)\n" %tag)
f.write('{\n')

f.write(" Insn *insn G_GNUC_UNUSED = ctx->insn;\n")

i=0
## Analyze all the registers
for regtype, regid, toss, numregs in regs:
analyze_opn(f, tag, regtype, regid, toss, numregs, i)
i += 1

has_generated_helper = (not hex_common.skip_qemu_helper(tag) and
not hex_common.is_idef_parser_enabled(tag))
if (has_generated_helper and
'A_SCALAR_LOAD' in hex_common.attribdict[tag]):
f.write(" ctx->need_pkt_has_store_s1 = true;\n")

f.write("}\n\n")

def main():
hex_common.read_semantics_file(sys.argv[1])
hex_common.read_attribs_file(sys.argv[2])
hex_common.read_overrides_file(sys.argv[3])
hex_common.read_overrides_file(sys.argv[4])
## Whether or not idef-parser is enabled is
## determined by the number of arguments to
## this script:
##
## 5 args. -> not enabled,
## 6 args. -> idef-parser enabled.
##
## The 6:th arg. then holds a list of the successfully
## parsed instructions.
is_idef_parser_enabled = len(sys.argv) > 6
if is_idef_parser_enabled:
hex_common.read_idef_parser_enabled_file(sys.argv[5])
hex_common.calculate_attribs()
tagregs = hex_common.get_tagregs()
tagimms = hex_common.get_tagimms()

with open(sys.argv[-1], 'w') as f:
f.write("#ifndef HEXAGON_TCG_FUNCS_H\n")
f.write("#define HEXAGON_TCG_FUNCS_H\n\n")

for tag in hex_common.tags:
gen_analyze_func(f, tag, tagregs[tag], tagimms[tag])

f.write("#endif /* HEXAGON_TCG_FUNCS_H */\n")

if __name__ == "__main__":
main()
19 changes: 14 additions & 5 deletions target/hexagon/gen_helper_funcs.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3

##
## Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
## Copyright(c) 2019-2023 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
Expand Down Expand Up @@ -226,6 +226,14 @@ def gen_helper_function(f, tag, tagregs, tagimms):
print("Bad register parse: ",regtype,regid,toss,numregs)
i += 1

## For conditional instructions, we pass in the destination register
if 'A_CONDEXEC' in hex_common.attribdict[tag]:
for regtype, regid, toss, numregs in regs:
if (hex_common.is_writeonly(regid) and
not hex_common.is_hvx_reg(regtype)):
gen_helper_arg_opn(f, regtype, regid, i, tag)
i += 1

## Arguments to the helper function are the source regs and immediates
for regtype,regid,toss,numregs in regs:
if (hex_common.is_read(regid)):
Expand Down Expand Up @@ -262,10 +270,11 @@ def gen_helper_function(f, tag, tagregs, tagimms):
if hex_common.need_ea(tag): gen_decl_ea(f)
## Declare the return variable
i=0
for regtype,regid,toss,numregs in regs:
if (hex_common.is_writeonly(regid)):
gen_helper_dest_decl_opn(f,regtype,regid,i)
i += 1
if 'A_CONDEXEC' not in hex_common.attribdict[tag]:
for regtype,regid,toss,numregs in regs:
if (hex_common.is_writeonly(regid)):
gen_helper_dest_decl_opn(f,regtype,regid,i)
i += 1

for regtype,regid,toss,numregs in regs:
if (hex_common.is_read(regid)):
Expand Down
12 changes: 11 additions & 1 deletion target/hexagon/gen_helper_protos.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3

##
## Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
## Copyright(c) 2019-2023 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
Expand Down Expand Up @@ -87,6 +87,7 @@ def gen_helper_prototype(f, tag, tagregs, tagimms):
if hex_common.need_slot(tag): def_helper_size += 1
if hex_common.need_PC(tag): def_helper_size += 1
if hex_common.helper_needs_next_PC(tag): def_helper_size += 1
if hex_common.need_condexec_reg(tag, regs): def_helper_size += 1
f.write('DEF_HELPER_%s(%s' % (def_helper_size, tag))
## The return type is void
f.write(', void' )
Expand All @@ -96,6 +97,7 @@ def gen_helper_prototype(f, tag, tagregs, tagimms):
if hex_common.need_part1(tag): def_helper_size += 1
if hex_common.need_slot(tag): def_helper_size += 1
if hex_common.need_PC(tag): def_helper_size += 1
if hex_common.need_condexec_reg(tag, regs): def_helper_size += 1
if hex_common.helper_needs_next_PC(tag): def_helper_size += 1
f.write('DEF_HELPER_%s(%s' % (def_helper_size, tag))

Expand All @@ -121,6 +123,14 @@ def gen_helper_prototype(f, tag, tagregs, tagimms):
gen_def_helper_opn(f, tag, regtype, regid, toss, numregs, i)
i += 1

## For conditional instructions, we pass in the destination register
if 'A_CONDEXEC' in hex_common.attribdict[tag]:
for regtype, regid, toss, numregs in regs:
if (hex_common.is_writeonly(regid) and
not hex_common.is_hvx_reg(regtype)):
gen_def_helper_opn(f, tag, regtype, regid, toss, numregs, i)
i += 1

## Generate the qemu type for each input operand (regs and immediates)
for regtype,regid,toss,numregs in regs:
if (hex_common.is_read(regid)):
Expand Down
90 changes: 81 additions & 9 deletions target/hexagon/gen_tcg.h
@@ -1,5 +1,5 @@
/*
* Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
* Copyright(c) 2019-2023 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
Expand Down Expand Up @@ -332,8 +332,6 @@
tcg_gen_movi_tl(EA, 0); \
PRED; \
CHECK_NOSHUF_PRED(GET_EA, SIZE, LSB); \
PRED_LOAD_CANCEL(LSB, EA); \
tcg_gen_movi_tl(RdV, 0); \
tcg_gen_brcondi_tl(TCG_COND_EQ, LSB, 0, label); \
fLOAD(1, SIZE, SIGN, EA, RdV); \
gen_set_label(label); \
Expand Down Expand Up @@ -391,8 +389,6 @@
tcg_gen_movi_tl(EA, 0); \
PRED; \
CHECK_NOSHUF_PRED(GET_EA, 8, LSB); \
PRED_LOAD_CANCEL(LSB, EA); \
tcg_gen_movi_i64(RddV, 0); \
tcg_gen_brcondi_tl(TCG_COND_EQ, LSB, 0, label); \
fLOAD(1, 8, u, EA, RddV); \
gen_set_label(label); \
Expand All @@ -419,16 +415,16 @@

#define fGEN_TCG_STORE(SHORTCODE) \
do { \
TCGv HALF = tcg_temp_new(); \
TCGv BYTE = tcg_temp_new(); \
TCGv HALF G_GNUC_UNUSED = tcg_temp_new(); \
TCGv BYTE G_GNUC_UNUSED = tcg_temp_new(); \
SHORTCODE; \
} while (0)

#define fGEN_TCG_STORE_pcr(SHIFT, STORE) \
do { \
TCGv ireg = tcg_temp_new(); \
TCGv HALF = tcg_temp_new(); \
TCGv BYTE = tcg_temp_new(); \
TCGv HALF G_GNUC_UNUSED = tcg_temp_new(); \
TCGv BYTE G_GNUC_UNUSED = tcg_temp_new(); \
tcg_gen_mov_tl(EA, RxV); \
gen_read_ireg(ireg, MuV, SHIFT); \
gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \
Expand Down Expand Up @@ -491,6 +487,59 @@
#define fGEN_TCG_S2_storerinew_pcr(SHORTCODE) \
fGEN_TCG_STORE_pcr(2, fSTORE(1, 4, EA, NtN))

/*
* dealloc_return
* Assembler mapped to
* r31:30 = dealloc_return(r30):raw
*/
#define fGEN_TCG_L4_return(SHORTCODE) \
gen_return(ctx, RddV, RsV)

/*
* sub-instruction version (no RddV, so handle it manually)
*/
#define fGEN_TCG_SL2_return(SHORTCODE) \
do { \
TCGv_i64 RddV = get_result_gpr_pair(ctx, HEX_REG_FP); \
gen_return(ctx, RddV, hex_gpr[HEX_REG_FP]); \
gen_log_reg_write_pair(HEX_REG_FP, RddV); \
} while (0)

/*
* Conditional returns follow this naming convention
* _t predicate true
* _f predicate false
* _tnew_pt predicate.new true predict taken
* _fnew_pt predicate.new false predict taken
* _tnew_pnt predicate.new true predict not taken
* _fnew_pnt predicate.new false predict not taken
* Predictions are not modelled in QEMU
*
* Example:
* if (p1) r31:30 = dealloc_return(r30):raw
*/
#define fGEN_TCG_L4_return_t(SHORTCODE) \
gen_cond_return(ctx, RddV, RsV, PvV, TCG_COND_EQ);
#define fGEN_TCG_L4_return_f(SHORTCODE) \
gen_cond_return(ctx, RddV, RsV, PvV, TCG_COND_NE)
#define fGEN_TCG_L4_return_tnew_pt(SHORTCODE) \
gen_cond_return(ctx, RddV, RsV, PvN, TCG_COND_EQ)
#define fGEN_TCG_L4_return_fnew_pt(SHORTCODE) \
gen_cond_return(ctx, RddV, RsV, PvN, TCG_COND_NE)
#define fGEN_TCG_L4_return_tnew_pnt(SHORTCODE) \
gen_cond_return(ctx, RddV, RsV, PvN, TCG_COND_EQ)
#define fGEN_TCG_L4_return_fnew_pnt(SHORTCODE) \
gen_cond_return(ctx, RddV, RsV, PvN, TCG_COND_NE)

#define fGEN_TCG_SL2_return_t(SHORTCODE) \
gen_cond_return_subinsn(ctx, TCG_COND_EQ, hex_pred[0])
#define fGEN_TCG_SL2_return_f(SHORTCODE) \
gen_cond_return_subinsn(ctx, TCG_COND_NE, hex_pred[0])
#define fGEN_TCG_SL2_return_tnew(SHORTCODE) \
gen_cond_return_subinsn(ctx, TCG_COND_EQ, hex_new_pred_value[0])
#define fGEN_TCG_SL2_return_fnew(SHORTCODE) \
gen_cond_return_subinsn(ctx, TCG_COND_NE, hex_new_pred_value[0])

/*
* Mathematical operations with more than one definition require
* special handling
Expand Down Expand Up @@ -589,14 +638,24 @@

#define fGEN_TCG_J2_call(SHORTCODE) \
gen_call(ctx, riV)
#define fGEN_TCG_J2_callr(SHORTCODE) \
gen_callr(ctx, RsV)

#define fGEN_TCG_J2_callt(SHORTCODE) \
gen_cond_call(ctx, PuV, TCG_COND_EQ, riV)
#define fGEN_TCG_J2_callf(SHORTCODE) \
gen_cond_call(ctx, PuV, TCG_COND_NE, riV)
#define fGEN_TCG_J2_callrt(SHORTCODE) \
gen_cond_callr(ctx, TCG_COND_EQ, PuV, RsV)
#define fGEN_TCG_J2_callrf(SHORTCODE) \
gen_cond_callr(ctx, TCG_COND_NE, PuV, RsV)

#define fGEN_TCG_J2_endloop0(SHORTCODE) \
gen_endloop0(ctx)
#define fGEN_TCG_J2_endloop1(SHORTCODE) \
gen_endloop1(ctx)
#define fGEN_TCG_J2_endloop01(SHORTCODE) \
gen_endloop01(ctx)

/*
* Compound compare and jump instructions
Expand Down Expand Up @@ -986,6 +1045,19 @@
#define fGEN_TCG_S2_asl_r_r_sat(SHORTCODE) \
gen_asl_r_r_sat(RdV, RsV, RtV)

#define fGEN_TCG_SL2_jumpr31(SHORTCODE) \
gen_jumpr(ctx, hex_gpr[HEX_REG_LR])

#define fGEN_TCG_SL2_jumpr31_t(SHORTCODE) \
gen_cond_jumpr31(ctx, TCG_COND_EQ, hex_pred[0])
#define fGEN_TCG_SL2_jumpr31_f(SHORTCODE) \
gen_cond_jumpr31(ctx, TCG_COND_NE, hex_pred[0])

#define fGEN_TCG_SL2_jumpr31_tnew(SHORTCODE) \
gen_cond_jumpr31(ctx, TCG_COND_EQ, hex_new_pred_value[0])
#define fGEN_TCG_SL2_jumpr31_fnew(SHORTCODE) \
gen_cond_jumpr31(ctx, TCG_COND_NE, hex_new_pred_value[0])

/* Floating point */
#define fGEN_TCG_F2_conv_sf2df(SHORTCODE) \
gen_helper_conv_sf2df(RddV, cpu_env, RsV)
Expand Down
152 changes: 54 additions & 98 deletions target/hexagon/gen_tcg_funcs.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3

##
## Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
## Copyright(c) 2019-2023 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
Expand Down Expand Up @@ -30,37 +30,33 @@ def gen_decl_ea_tcg(f, tag):

def genptr_decl_pair_writable(f, tag, regtype, regid, regno):
regN="%s%sN" % (regtype,regid)
f.write(" TCGv_i64 %s%sV = tcg_temp_new_i64();\n" % \
(regtype, regid))
if (regtype == "C"):
if (regtype == "R"):
f.write(" const int %s = insn->regno[%d];\n" % (regN, regno))
elif (regtype == "C"):
f.write(" const int %s = insn->regno[%d] + HEX_REG_SA0;\n" % \
(regN, regno))
else:
f.write(" const int %s = insn->regno[%d];\n" % (regN, regno))
if ('A_CONDEXEC' in hex_common.attribdict[tag]):
f.write(" if (!is_preloaded(ctx, %s)) {\n" % regN)
f.write(" tcg_gen_mov_tl(hex_new_value[%s], hex_gpr[%s]);\n" % \
(regN, regN))
f.write(" }\n")
f.write(" if (!is_preloaded(ctx, %s + 1)) {\n" % regN)
f.write(" tcg_gen_mov_tl(hex_new_value[%s + 1], hex_gpr[%s + 1]);\n" % \
(regN, regN))
f.write(" }\n")
print("Bad register parse: ", regtype, regid)
f.write(" TCGv_i64 %s%sV = get_result_gpr_pair(ctx, %s);\n" % \
(regtype, regid, regN))

def genptr_decl_writable(f, tag, regtype, regid, regno):
regN="%s%sN" % (regtype,regid)
f.write(" TCGv %s%sV = tcg_temp_new();\n" % \
(regtype, regid))
if (regtype == "C"):
if (regtype == "R"):
f.write(" const int %s = insn->regno[%d];\n" % (regN, regno))
f.write(" TCGv %s%sV = get_result_gpr(ctx, %s);\n" % \
(regtype, regid, regN))
elif (regtype == "C"):
f.write(" const int %s = insn->regno[%d] + HEX_REG_SA0;\n" % \
(regN, regno))
else:
f.write(" TCGv %s%sV = get_result_gpr(ctx, %s);\n" % \
(regtype, regid, regN))
elif (regtype == "P"):
f.write(" const int %s = insn->regno[%d];\n" % (regN, regno))
if ('A_CONDEXEC' in hex_common.attribdict[tag]):
f.write(" if (!is_preloaded(ctx, %s)) {\n" % regN)
f.write(" tcg_gen_mov_tl(hex_new_value[%s], hex_gpr[%s]);\n" % \
(regN, regN))
f.write(" }\n")
f.write(" TCGv %s%sV = tcg_temp_new();\n" % \
(regtype, regid))
else:
print("Bad register parse: ", regtype, regid)

def genptr_decl(f, tag, regtype, regid, regno):
regN="%s%sN" % (regtype,regid)
Expand Down Expand Up @@ -166,17 +162,6 @@ def genptr_decl(f, tag, regtype, regid, regno):
f.write(" ctx_future_vreg_off(ctx, %s%sN," % \
(regtype, regid))
f.write(" 1, true);\n");
if 'A_CONDEXEC' in hex_common.attribdict[tag]:
f.write(" if (!is_vreg_preloaded(ctx, %s)) {\n" % (regN))
f.write(" intptr_t src_off =")
f.write(" offsetof(CPUHexagonState, VRegs[%s%sN]);\n"% \
(regtype, regid))
f.write(" tcg_gen_gvec_mov(MO_64, %s%sV_off,\n" % \
(regtype, regid))
f.write(" src_off,\n")
f.write(" sizeof(MMVector),\n")
f.write(" sizeof(MMVector));\n")
f.write(" }\n")

if (not hex_common.skip_qemu_helper(tag)):
f.write(" TCGv_ptr %s%sV = tcg_temp_new_ptr();\n" % \
Expand All @@ -191,8 +176,7 @@ def genptr_decl(f, tag, regtype, regid, regno):
(regtype, regid, regno))
f.write(" const intptr_t %s%sV_off =\n" % \
(regtype, regid))
f.write(" offsetof(CPUHexagonState,\n")
f.write(" future_QRegs[%s%sN]);\n" % \
f.write(" get_result_qreg(ctx, %s%sN);\n" % \
(regtype, regid))
if (not hex_common.skip_qemu_helper(tag)):
f.write(" TCGv_ptr %s%sV = tcg_temp_new_ptr();\n" % \
Expand Down Expand Up @@ -274,8 +258,12 @@ def genptr_src_read(f, tag, regtype, regid):
f.write(" hex_gpr[%s%sN + 1]);\n" % \
(regtype, regid))
elif (regid in {"x", "y"}):
f.write(" tcg_gen_mov_tl(%s%sV, hex_gpr[%s%sN]);\n" % \
(regtype,regid,regtype,regid))
## For read/write registers, we need to get the original value into
## the result TCGv. For conditional instructions, this is done in
## gen_start_packet. For unconditional instructions, we do it here.
if ('A_CONDEXEC' not in hex_common.attribdict[tag]):
f.write(" tcg_gen_mov_tl(%s%sV, hex_gpr[%s%sN]);\n" % \
(regtype, regid, regtype, regid))
elif (regid not in {"s", "t", "u", "v"}):
print("Bad register parse: ", regtype, regid)
elif (regtype == "P"):
Expand Down Expand Up @@ -385,37 +373,22 @@ def gen_helper_call_imm(f,immlett):
f.write(", tcgv_%s" % hex_common.imm_name(immlett))

def genptr_dst_write_pair(f, tag, regtype, regid):
if ('A_CONDEXEC' in hex_common.attribdict[tag]):
f.write(" gen_log_predicated_reg_write_pair(%s%sN, %s%sV, insn->slot);\n" % \
(regtype, regid, regtype, regid))
else:
f.write(" gen_log_reg_write_pair(%s%sN, %s%sV);\n" % \
(regtype, regid, regtype, regid))
f.write(" ctx_log_reg_write_pair(ctx, %s%sN);\n" % \
(regtype, regid))
f.write(" gen_log_reg_write_pair(%s%sN, %s%sV);\n" % \
(regtype, regid, regtype, regid))

def genptr_dst_write(f, tag, regtype, regid):
if (regtype == "R"):
if (regid in {"dd", "xx", "yy"}):
genptr_dst_write_pair(f, tag, regtype, regid)
elif (regid in {"d", "e", "x", "y"}):
if ('A_CONDEXEC' in hex_common.attribdict[tag]):
f.write(" gen_log_predicated_reg_write(%s%sN, %s%sV,\n" % \
(regtype, regid, regtype, regid))
f.write(" insn->slot);\n")
else:
f.write(" gen_log_reg_write(%s%sN, %s%sV);\n" % \
(regtype, regid, regtype, regid))
f.write(" ctx_log_reg_write(ctx, %s%sN);\n" % \
(regtype, regid))
f.write(" gen_log_reg_write(%s%sN, %s%sV);\n" % \
(regtype, regid, regtype, regid))
else:
print("Bad register parse: ", regtype, regid)
elif (regtype == "P"):
if (regid in {"d", "e", "x"}):
f.write(" gen_log_pred_write(ctx, %s%sN, %s%sV);\n" % \
(regtype, regid, regtype, regid))
f.write(" ctx_log_pred_write(ctx, %s%sN);\n" % \
(regtype, regid))
else:
print("Bad register parse: ", regtype, regid)
elif (regtype == "C"):
Expand All @@ -432,43 +405,18 @@ def genptr_dst_write(f, tag, regtype, regid):

def genptr_dst_write_ext(f, tag, regtype, regid, newv="EXT_DFL"):
if (regtype == "V"):
if (regid in {"dd", "xx", "yy"}):
if ('A_CONDEXEC' in hex_common.attribdict[tag]):
is_predicated = "true"
else:
is_predicated = "false"
if (regid in {"xx"}):
f.write(" gen_log_vreg_write_pair(ctx, %s%sV_off, %s%sN, " % \
(regtype, regid, regtype, regid))
f.write("%s, insn->slot, %s);\n" % \
(newv, is_predicated))
f.write(" ctx_log_vreg_write_pair(ctx, %s%sN, %s,\n" % \
(regtype, regid, newv))
f.write(" %s);\n" % (is_predicated))
elif (regid in {"d", "x", "y"}):
if ('A_CONDEXEC' in hex_common.attribdict[tag]):
is_predicated = "true"
else:
is_predicated = "false"
f.write(" gen_log_vreg_write(ctx, %s%sV_off, %s%sN, %s, " % \
f.write("%s);\n" % \
(newv))
elif (regid in {"y"}):
f.write(" gen_log_vreg_write(ctx, %s%sV_off, %s%sN, %s);\n" % \
(regtype, regid, regtype, regid, newv))
f.write("insn->slot, %s);\n" % \
(is_predicated))
f.write(" ctx_log_vreg_write(ctx, %s%sN, %s, %s);\n" % \
(regtype, regid, newv, is_predicated))
else:
elif (regid not in {"dd", "d", "x"}):
print("Bad register parse: ", regtype, regid)
elif (regtype == "Q"):
if (regid in {"d", "e", "x"}):
if ('A_CONDEXEC' in hex_common.attribdict[tag]):
is_predicated = "true"
else:
is_predicated = "false"
f.write(" gen_log_qreg_write(%s%sV_off, %s%sN, %s, " % \
(regtype, regid, regtype, regid, newv))
f.write("insn->slot, %s);\n" % (is_predicated))
f.write(" ctx_log_qreg_write(ctx, %s%sN, %s);\n" % \
(regtype, regid, is_predicated))
else:
if (regid not in {"d", "e", "x"}):
print("Bad register parse: ", regtype, regid)
else:
print("Bad register parse: ", regtype, regid)
Expand Down Expand Up @@ -500,15 +448,15 @@ def genptr_dst_write_opn(f,regtype, regid, tag):
## For A2_add: Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;}
## We produce:
## static void generate_A2_add(DisasContext *ctx)
## {
## TCGv RdV = tcg_temp_new();
## const int RdN = insn->regno[0];
## TCGv RsV = hex_gpr[insn->regno[1]];
## TCGv RtV = hex_gpr[insn->regno[2]];
## <GEN>
## gen_log_reg_write(RdN, RdV);
## ctx_log_reg_write(ctx, RdN);
## }
## {
## Insn *insn __attribute__((unused)) = ctx->insn;
## const int RdN = insn->regno[0];
## TCGv RdV = get_result_gpr(ctx, RdN);
## TCGv RsV = hex_gpr[insn->regno[1]];
## TCGv RtV = hex_gpr[insn->regno[2]];
## <GEN>
## gen_log_reg_write(RdN, RdV);
## }
##
## where <GEN> depends on hex_common.skip_qemu_helper(tag)
## if hex_common.skip_qemu_helper(tag) is True
Expand Down Expand Up @@ -592,6 +540,14 @@ def gen_tcg_func(f, tag, regs, imms):
if (i > 0): f.write(", ")
f.write("cpu_env")
i=1
## For conditional instructions, we pass in the destination register
if 'A_CONDEXEC' in hex_common.attribdict[tag]:
for regtype, regid, toss, numregs in regs:
if (hex_common.is_writeonly(regid) and
not hex_common.is_hvx_reg(regtype)):
gen_helper_call_opn(f, tag, regtype, regid, toss, \
numregs, i)
i += 1
for regtype,regid,toss,numregs in regs:
if (hex_common.is_written(regid)):
if (not hex_common.is_hvx_reg(regtype)):
Expand Down
17 changes: 1 addition & 16 deletions target/hexagon/gen_tcg_hvx.h
@@ -1,5 +1,5 @@
/*
* Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
* Copyright(c) 2019-2023 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
Expand Down Expand Up @@ -133,16 +133,11 @@ static inline void assert_vhist_tmp(DisasContext *ctx)
do { \
TCGv lsb = tcg_temp_new(); \
TCGLabel *false_label = gen_new_label(); \
TCGLabel *end_label = gen_new_label(); \
tcg_gen_andi_tl(lsb, PsV, 1); \
tcg_gen_brcondi_tl(TCG_COND_NE, lsb, PRED, false_label); \
tcg_gen_gvec_mov(MO_64, VdV_off, VuV_off, \
sizeof(MMVector), sizeof(MMVector)); \
tcg_gen_br(end_label); \
gen_set_label(false_label); \
tcg_gen_ori_tl(hex_slot_cancelled, hex_slot_cancelled, \
1 << insn->slot); \
gen_set_label(end_label); \
} while (0)


Expand Down Expand Up @@ -547,17 +542,12 @@ static inline void assert_vhist_tmp(DisasContext *ctx)
do { \
TCGv LSB = tcg_temp_new(); \
TCGLabel *false_label = gen_new_label(); \
TCGLabel *end_label = gen_new_label(); \
GET_EA; \
PRED; \
tcg_gen_brcondi_tl(TCG_COND_EQ, LSB, 0, false_label); \
gen_vreg_load(ctx, DSTOFF, EA, true); \
INC; \
tcg_gen_br(end_label); \
gen_set_label(false_label); \
tcg_gen_ori_tl(hex_slot_cancelled, hex_slot_cancelled, \
1 << insn->slot); \
gen_set_label(end_label); \
} while (0)

#define fGEN_TCG_PRED_VEC_LOAD_pred_pi \
Expand Down Expand Up @@ -717,17 +707,12 @@ static inline void assert_vhist_tmp(DisasContext *ctx)
do { \
TCGv LSB = tcg_temp_new(); \
TCGLabel *false_label = gen_new_label(); \
TCGLabel *end_label = gen_new_label(); \
GET_EA; \
PRED; \
tcg_gen_brcondi_tl(TCG_COND_EQ, LSB, 0, false_label); \
gen_vreg_store(ctx, EA, SRCOFF, insn->slot, ALIGN); \
INC; \
tcg_gen_br(end_label); \
gen_set_label(false_label); \
tcg_gen_ori_tl(hex_slot_cancelled, hex_slot_cancelled, \
1 << insn->slot); \
gen_set_label(end_label); \
} while (0)

#define fGEN_TCG_PRED_VEC_STORE_pred_pi(ALIGN) \
Expand Down
296 changes: 188 additions & 108 deletions target/hexagon/genptr.c

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion target/hexagon/hex_common.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3

##
## Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
## Copyright(c) 2019-2023 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
Expand Down Expand Up @@ -89,6 +89,7 @@ def calculate_attribs():
add_qemu_macro_attrib('fWRITE_P3', 'A_WRITES_PRED_REG')
add_qemu_macro_attrib('fSET_OVERFLOW', 'A_IMPLICIT_WRITES_USR')
add_qemu_macro_attrib('fSET_LPCFG', 'A_IMPLICIT_WRITES_USR')
add_qemu_macro_attrib('fLOAD', 'A_SCALAR_LOAD')
add_qemu_macro_attrib('fSTORE', 'A_SCALAR_STORE')

# Recurse down macros, find attributes from sub-macros
Expand Down Expand Up @@ -236,6 +237,13 @@ def helper_needs_next_PC(tag):
def need_pkt_has_multi_cof(tag):
return 'A_COF' in attribdict[tag]

def need_condexec_reg(tag, regs):
if 'A_CONDEXEC' in attribdict[tag]:
for regtype, regid, toss, numregs in regs:
if is_writeonly(regid) and not is_hvx_reg(regtype):
return True
return False

def skip_qemu_helper(tag):
return tag in overrides.keys()

Expand Down
1 change: 0 additions & 1 deletion target/hexagon/idef-parser/idef-parser.h
Expand Up @@ -82,7 +82,6 @@ enum ImmUnionTag {
VALUE,
QEMU_TMP,
IMM_PC,
IMM_NPC,
IMM_CONSTEXT,
};

Expand Down
31 changes: 4 additions & 27 deletions target/hexagon/idef-parser/idef-parser.lex
Expand Up @@ -5,7 +5,7 @@

%{
/*
* Copyright(c) 2019-2022 rev.ng Labs Srl. All Rights Reserved.
* Copyright(c) 2019-2023 rev.ng Labs Srl. 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
Expand Down Expand Up @@ -140,8 +140,6 @@ STRING_LIT \"(\\.|[^"\\])*\"
yylval->rvalue.is_dotnew = true;
yylval->rvalue.signedness = SIGNED;
return PRED; }
"IV1DEAD()" |
"fPAUSE(uiV);" { return ';'; }
"+=" { return INC; }
"-=" { return DEC; }
"++" { return PLUSPLUS; }
Expand All @@ -159,9 +157,8 @@ STRING_LIT \"(\\.|[^"\\])*\"
"else" { return ELSE; }
"for" { return FOR; }
"fREAD_IREG" { return ICIRC; }
"fPART1" { return PART1; }
"if" { return IF; }
"fFRAME_SCRAMBLE" { return FSCR; }
"fFRAME_SCRAMBLE" |
"fFRAME_UNSCRAMBLE" { return FSCR; }
"fFRAMECHECK" { return FCHK; }
"Constant_extended" { return CONSTEXT; }
Expand Down Expand Up @@ -312,14 +309,10 @@ STRING_LIT \"(\\.|[^"\\])*\"
"(unsigned int)" { yylval->cast.bit_width = 32;
yylval->cast.signedness = UNSIGNED;
return CAST; }
"fREAD_PC()" |
"PC" { return PC; }
"fREAD_NPC()" |
"NPC" { return NPC; }
"fGET_LPCFG" |
"fREAD_PC()" { return PC; }
"USR.LPCFG" { return LPCFG; }
"LOAD_CANCEL(EA)" { return LOAD_CANCEL; }
"STORE_CANCEL(EA)" |
"STORE_CANCEL(EA)" { return STORE_CANCEL; }
"CANCEL" { return CANCEL; }
"N"{LOWER_ID}"N" { yylval->rvalue.type = REGISTER_ARG;
yylval->rvalue.reg.type = DOTNEW;
Expand Down Expand Up @@ -360,14 +353,6 @@ STRING_LIT \"(\\.|[^"\\])*\"
yylval->rvalue.bit_width = 32;
yylval->rvalue.signedness = UNSIGNED;
return REG; }
"fREAD_LC"[01] { yylval->rvalue.type = REGISTER;
yylval->rvalue.reg.type = CONTROL;
yylval->rvalue.reg.id = HEX_REG_LC0
+ (yytext[8] - '0') * 2;
yylval->rvalue.reg.bit_width = 32;
yylval->rvalue.bit_width = 32;
yylval->rvalue.signedness = UNSIGNED;
return REG; }
"LC"[01] { yylval->rvalue.type = REGISTER;
yylval->rvalue.reg.type = CONTROL;
yylval->rvalue.reg.id = HEX_REG_LC0
Expand All @@ -376,14 +361,6 @@ STRING_LIT \"(\\.|[^"\\])*\"
yylval->rvalue.bit_width = 32;
yylval->rvalue.signedness = UNSIGNED;
return REG; }
"fREAD_SA"[01] { yylval->rvalue.type = REGISTER;
yylval->rvalue.reg.type = CONTROL;
yylval->rvalue.reg.id = HEX_REG_SA0
+ (yytext[8] - '0') * 2;
yylval->rvalue.reg.bit_width = 32;
yylval->rvalue.bit_width = 32;
yylval->rvalue.signedness = UNSIGNED;
return REG; }
"SA"[01] { yylval->rvalue.type = REGISTER;
yylval->rvalue.reg.type = CONTROL;
yylval->rvalue.reg.id = HEX_REG_SA0
Expand Down
49 changes: 5 additions & 44 deletions target/hexagon/idef-parser/idef-parser.y
@@ -1,6 +1,6 @@
%{
/*
* Copyright(c) 2019-2022 rev.ng Labs Srl. All Rights Reserved.
* Copyright(c) 2019-2023 rev.ng Labs Srl. All Rights Reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
Expand Down Expand Up @@ -52,8 +52,8 @@
%token IN INAME VAR
%token ABS CROUND ROUND CIRCADD COUNTONES INC DEC ANDA ORA XORA PLUSPLUS ASL
%token ASR LSR EQ NEQ LTE GTE MIN MAX ANDL FOR ICIRC IF MUN FSCR FCHK SXT
%token ZXT CONSTEXT LOCNT BREV SIGN LOAD STORE PC NPC LPCFG
%token LOAD_CANCEL CANCEL IDENTITY PART1 ROTL INSBITS SETBITS EXTRANGE
%token ZXT CONSTEXT LOCNT BREV SIGN LOAD STORE PC LPCFG
%token LOAD_CANCEL STORE_CANCEL CANCEL IDENTITY ROTL INSBITS SETBITS EXTRANGE
%token CAST4_8U FAIL CARRY_FROM_ADD ADDSAT64 LSBNEW
%token TYPE_SIZE_T TYPE_INT TYPE_SIGNED TYPE_UNSIGNED TYPE_LONG

Expand Down Expand Up @@ -336,15 +336,6 @@ assign_statement : lvalue '=' rvalue
OUT(c, &@1, &$1, " = ", &$3, ";\n");
$$ = $1;
}
| PC '=' rvalue
{
@1.last_column = @3.last_column;
yyassert(c, &@1, !is_inside_ternary(c),
"Assignment side-effect not modeled!");
$3 = gen_rvalue_truncate(c, &@1, &$3);
$3 = rvalue_materialize(c, &@1, &$3);
OUT(c, &@1, "gen_write_new_pc(", &$3, ");\n");
}
| LOAD '(' IMM ',' IMM ',' SIGN ',' var ',' lvalue ')'
{
@1.last_column = @12.last_column;
Expand Down Expand Up @@ -412,7 +403,6 @@ control_statement : frame_check
| cancel_statement
| if_statement
| for_statement
| fpart1_statement
;

frame_check : FCHK '(' rvalue ',' rvalue ')' ';'
Expand All @@ -422,10 +412,11 @@ cancel_statement : LOAD_CANCEL
{
gen_load_cancel(c, &@1);
}
| CANCEL
| STORE_CANCEL
{
gen_cancel(c, &@1);
}
| CANCEL
;

if_statement : if_stmt
Expand Down Expand Up @@ -462,17 +453,6 @@ for_statement : FOR '(' IMM '=' IMM ';' IMM '<' IMM ';' IMM PLUSPLUS ')'
}
;

fpart1_statement : PART1
{
OUT(c, &@1, "if (insn->part1) {\n");
}
'(' statements ')'
{
@1.last_column = @3.last_column;
OUT(c, &@1, "return; }\n");
}
;

if_stmt : IF '(' rvalue ')'
{
@1.last_column = @3.last_column;
Expand Down Expand Up @@ -512,20 +492,6 @@ rvalue : FAIL
rvalue.signedness = UNSIGNED;
$$ = rvalue;
}
| NPC
{
/*
* NPC is only read from CALLs, so we can hardcode it
* at translation time
*/
HexValue rvalue;
memset(&rvalue, 0, sizeof(HexValue));
rvalue.type = IMMEDIATE;
rvalue.imm.type = IMM_NPC;
rvalue.bit_width = 32;
rvalue.signedness = UNSIGNED;
$$ = rvalue;
}
| CONSTEXT
{
HexValue rvalue;
Expand Down Expand Up @@ -781,11 +747,6 @@ rvalue : FAIL
/* Ones count */
$$ = gen_ctpop_op(c, &@1, &$3);
}
| LPCFG
{
$$ = gen_tmp(c, &@1, 32, UNSIGNED);
OUT(c, &@1, "GET_USR_FIELD(USR_LPCFG, ", &$$, ");\n");
}
| EXTRACT '(' rvalue ',' rvalue ')'
{
@1.last_column = @6.last_column;
Expand Down
9 changes: 0 additions & 9 deletions target/hexagon/idef-parser/macros.inc
Expand Up @@ -97,16 +97,8 @@
#define fWRITE_LR(A) (LR = A)
#define fWRITE_FP(A) (FP = A)
#define fWRITE_SP(A) (SP = A)
/*
* Note: There is a rule in the parser that matches `PC = ...` and emits
* a call to `gen_write_new_pc`. We need to call `gen_write_new_pc` to
* get the correct semantics when there are multiple stores in a packet.
*/
#define fBRANCH(LOC, TYPE) (PC = LOC)
#define fJUMPR(REGNO, TARGET, TYPE) (PC = TARGET)
#define fWRITE_LOOP_REGS0(START, COUNT) SA0 = START; (LC0 = COUNT)
#define fWRITE_LOOP_REGS1(START, COUNT) SA1 = START; (LC1 = COUNT)
#define fWRITE_LC0(VAL) (LC0 = VAL)
#define fWRITE_LC1(VAL) (LC1 = VAL)
#define fSET_LPCFG(VAL) (USR.LPCFG = VAL)
#define fWRITE_P0(VAL) P0 = VAL;
Expand All @@ -121,7 +113,6 @@
#define fEA_GPI(IMM) (EA = fREAD_GP() + IMM)
#define fPM_I(REG, IMM) (REG = REG + IMM)
#define fPM_M(REG, MVAL) (REG = REG + MVAL)
#define fWRITE_NPC(VAL) (PC = VAL)

/* Unary operators */
#define fROUND(A) (A + 0x8000)
Expand Down
19 changes: 3 additions & 16 deletions target/hexagon/idef-parser/parser-helpers.c
@@ -1,5 +1,5 @@
/*
* Copyright(c) 2019-2022 rev.ng Labs Srl. All Rights Reserved.
* Copyright(c) 2019-2023 rev.ng Labs Srl. 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
Expand Down Expand Up @@ -185,9 +185,6 @@ void imm_print(Context *c, YYLTYPE *locp, HexImm *imm)
case IMM_PC:
EMIT(c, "ctx->base.pc_next");
break;
case IMM_NPC:
EMIT(c, "ctx->npc");
break;
case IMM_CONSTEXT:
EMIT(c, "insn->extension_valid");
break;
Expand Down Expand Up @@ -1323,10 +1320,6 @@ void gen_write_reg(Context *c, YYLTYPE *locp, HexValue *reg, HexValue *value)
locp,
"gen_log_reg_write(", &reg->reg.id, ", ",
&value_m, ");\n");
OUT(c,
locp,
"ctx_log_reg_write(ctx, ", &reg->reg.id,
");\n");
}

void gen_assign(Context *c,
Expand Down Expand Up @@ -1675,9 +1668,7 @@ void gen_inst_init_args(Context *c, YYLTYPE *locp)
for (unsigned i = 0; i < c->inst.init_list->len; i++) {
HexValue *val = &g_array_index(c->inst.init_list, HexValue, i);
if (val->type == REGISTER_ARG) {
char reg_id[5];
reg_compose(c, locp, &val->reg, reg_id);
EMIT_HEAD(c, "tcg_gen_movi_i%u(%s, 0);\n", val->bit_width, reg_id);
/* Nothing to do here */
} else if (val->type == PREDICATE) {
char suffix = val->is_dotnew ? 'N' : 'V';
EMIT_HEAD(c, "tcg_gen_movi_i%u(P%c%c, 0);\n", val->bit_width,
Expand Down Expand Up @@ -1722,13 +1713,10 @@ void gen_pred_assign(Context *c, YYLTYPE *locp, HexValue *left_pred,
*left_pred = gen_tmp(c, locp, 32, UNSIGNED);
}
/* Extract first 8 bits, and store new predicate value */
OUT(c, locp, "tcg_gen_mov_i32(", left_pred, ", ", &r, ");\n");
OUT(c, locp, "tcg_gen_andi_i32(", left_pred, ", ", left_pred,
", 0xff);\n");
OUT(c, locp, "tcg_gen_andi_i32(", left_pred, ", ", &r, ", 0xff);\n");
if (is_direct) {
OUT(c, locp, "gen_log_pred_write(ctx, ", pred_id, ", ", left_pred,
");\n");
OUT(c, locp, "ctx_log_pred_write(ctx, ", pred_id, ");\n");
}
}

Expand All @@ -1739,7 +1727,6 @@ void gen_cancel(Context *c, YYLTYPE *locp)

void gen_load_cancel(Context *c, YYLTYPE *locp)
{
gen_cancel(c, locp);
OUT(c, locp, "if (insn->slot == 0 && pkt->pkt_has_store_s1) {\n");
OUT(c, locp, "ctx->s1_store_processed = false;\n");
OUT(c, locp, "process_store(ctx, 1);\n");
Expand Down
29 changes: 2 additions & 27 deletions target/hexagon/macros.h
@@ -1,5 +1,5 @@
/*
* Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
* Copyright(c) 2019-2023 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
Expand Down Expand Up @@ -205,26 +205,11 @@ static inline void gen_cancel(uint32_t slot)

#define CANCEL gen_cancel(slot);
#else
#define CANCEL cancel_slot(env, slot)
#define CANCEL do { } while (0)
#endif

#define LOAD_CANCEL(EA) do { CANCEL; } while (0)

#ifdef QEMU_GENERATE
static inline void gen_pred_cancel(TCGv pred, uint32_t slot_num)
{
TCGv slot_mask = tcg_temp_new();
TCGv tmp = tcg_temp_new();
TCGv zero = tcg_constant_tl(0);
tcg_gen_ori_tl(slot_mask, hex_slot_cancelled, 1 << slot_num);
tcg_gen_andi_tl(tmp, pred, 1);
tcg_gen_movcond_tl(TCG_COND_EQ, hex_slot_cancelled, tmp, zero,
slot_mask, hex_slot_cancelled);
}
#define PRED_LOAD_CANCEL(PRED, EA) \
gen_pred_cancel(PRED, insn->is_endloop ? 4 : insn->slot)
#endif

#define STORE_CANCEL(EA) { env->slot_cancelled |= (1 << slot); }

#define fMAX(A, B) (((A) > (B)) ? (A) : (B))
Expand Down Expand Up @@ -415,16 +400,6 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift)
#define fBRANCH(LOC, TYPE) fWRITE_NPC(LOC)
#define fJUMPR(REGNO, TARGET, TYPE) fBRANCH(TARGET, COF_TYPE_JUMPR)
#define fHINTJR(TARGET) { /* Not modelled in qemu */}
#define fCALL(A) \
do { \
fWRITE_LR(fREAD_NPC()); \
fBRANCH(A, COF_TYPE_CALL); \
} while (0)
#define fCALLR(A) \
do { \
fWRITE_LR(fREAD_NPC()); \
fBRANCH(A, COF_TYPE_CALLR); \
} while (0)
#define fWRITE_LOOP_REGS0(START, COUNT) \
do { \
WRITE_RREG(HEX_REG_LC0, COUNT); \
Expand Down
11 changes: 10 additions & 1 deletion target/hexagon/meson.build
@@ -1,5 +1,5 @@
##
## Copyright(c) 2020-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
## Copyright(c) 2020-2023 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
Expand Down Expand Up @@ -276,4 +276,13 @@ tcg_funcs_generated = custom_target(
)
hexagon_ss.add(tcg_funcs_generated)

analyze_funcs_generated = custom_target(
'analyze_funcs_generated.c.inc',
output: 'analyze_funcs_generated.c.inc',
depends: helper_dep,
depend_files: [hex_common_py, attribs_def, gen_tcg_h, gen_tcg_hvx_h],
command: [python, files('gen_analyze_funcs.py'), helper_in, '@OUTPUT@'],
)
hexagon_ss.add(analyze_funcs_generated)

target_arch += {'hexagon': hexagon_ss}
60 changes: 19 additions & 41 deletions target/hexagon/op_helper.c
@@ -1,5 +1,5 @@
/*
* Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
* Copyright(c) 2019-2023 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
Expand Down Expand Up @@ -30,6 +30,7 @@
#include "mmvec/mmvec.h"
#include "mmvec/macros.h"
#include "op_helper.h"
#include "translate.h"

#define SF_BIAS 127
#define SF_MANTBITS 23
Expand Down Expand Up @@ -105,30 +106,6 @@ void log_store64(CPUHexagonState *env, target_ulong addr,
env->mem_log_stores[slot].data64 = val;
}

void write_new_pc(CPUHexagonState *env, bool pkt_has_multi_cof,
target_ulong addr)
{
HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr);

if (pkt_has_multi_cof) {
/*
* If more than one branch is taken in a packet, only the first one
* is actually done.
*/
if (env->branch_taken) {
HEX_DEBUG_LOG("INFO: multiple branches taken in same packet, "
"ignoring the second one\n");
} else {
fCHECK_PCALIGN(addr);
env->gpr[HEX_REG_PC] = addr;
env->branch_taken = 1;
}
} else {
fCHECK_PCALIGN(addr);
env->gpr[HEX_REG_PC] = addr;
}
}

/* Handy place to set a breakpoint */
void HELPER(debug_start_packet)(CPUHexagonState *env)
{
Expand Down Expand Up @@ -439,9 +416,10 @@ int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
return PeV;
}

static void probe_store(CPUHexagonState *env, int slot, int mmu_idx)
static void probe_store(CPUHexagonState *env, int slot, int mmu_idx,
bool is_predicated)
{
if (!(env->slot_cancelled & (1 << slot))) {
if (!is_predicated || !(env->slot_cancelled & (1 << slot))) {
size1u_t width = env->mem_log_stores[slot].width;
target_ulong va = env->mem_log_stores[slot].va;
uintptr_t ra = GETPC();
Expand All @@ -461,9 +439,12 @@ void HELPER(probe_noshuf_load)(CPUHexagonState *env, target_ulong va,
}

/* Called during packet commit when there are two scalar stores */
void HELPER(probe_pkt_scalar_store_s0)(CPUHexagonState *env, int mmu_idx)
void HELPER(probe_pkt_scalar_store_s0)(CPUHexagonState *env, int args)
{
probe_store(env, 0, mmu_idx);
int mmu_idx = FIELD_EX32(args, PROBE_PKT_SCALAR_STORE_S0, MMU_IDX);
bool is_predicated =
FIELD_EX32(args, PROBE_PKT_SCALAR_STORE_S0, IS_PREDICATED);
probe_store(env, 0, mmu_idx, is_predicated);
}

void HELPER(probe_hvx_stores)(CPUHexagonState *env, int mmu_idx)
Expand Down Expand Up @@ -510,15 +491,18 @@ void HELPER(probe_hvx_stores)(CPUHexagonState *env, int mmu_idx)
void HELPER(probe_pkt_scalar_hvx_stores)(CPUHexagonState *env, int mask,
int mmu_idx)
{
bool has_st0 = (mask >> 0) & 1;
bool has_st1 = (mask >> 1) & 1;
bool has_hvx_stores = (mask >> 2) & 1;
bool has_st0 = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_ST0);
bool has_st1 = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_ST1);
bool has_hvx_stores =
FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_HVX_STORES);
bool s0_is_pred = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, S0_IS_PRED);
bool s1_is_pred = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, S1_IS_PRED);

if (has_st0) {
probe_store(env, 0, mmu_idx);
probe_store(env, 0, mmu_idx, s0_is_pred);
}
if (has_st1) {
probe_store(env, 1, mmu_idx);
probe_store(env, 1, mmu_idx, s1_is_pred);
}
if (has_hvx_stores) {
HELPER(probe_hvx_stores)(env, mmu_idx);
Expand Down Expand Up @@ -1193,7 +1177,7 @@ float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV,
{
float32 neg_RsV;
arch_fpop_start(env);
neg_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
neg_RsV = float32_set_sign(RsV, float32_is_neg(RsV) ? 0 : 1);
RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status);
arch_fpop_end(env);
return RxV;
Expand Down Expand Up @@ -1468,12 +1452,6 @@ void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV)
}
}

void cancel_slot(CPUHexagonState *env, uint32_t slot)
{
HEX_DEBUG_LOG("Slot %d cancelled\n", slot);
env->slot_cancelled |= (1 << slot);
}

/* These macros can be referenced in the generated helper functions */
#define warn(...) /* Nothing */
#define fatal(...) g_assert_not_reached();
Expand Down
3 changes: 1 addition & 2 deletions target/hexagon/op_helper.h
@@ -1,5 +1,5 @@
/*
* Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
* Copyright(c) 2019-2023 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
Expand All @@ -19,7 +19,6 @@
#define HEXAGON_OP_HELPER_H

/* Misc functions */
void cancel_slot(CPUHexagonState *env, uint32_t slot);
void write_new_pc(CPUHexagonState *env, bool pkt_has_multi_cof, target_ulong addr);

uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, target_ulong vaddr);
Expand Down
288 changes: 171 additions & 117 deletions target/hexagon/translate.c

Large diffs are not rendered by default.

86 changes: 52 additions & 34 deletions target/hexagon/translate.h
@@ -1,5 +1,5 @@
/*
* Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
* Copyright(c) 2019-2023 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
Expand Down Expand Up @@ -38,6 +38,7 @@ typedef struct DisasContext {
int reg_log[REG_WRITES_MAX];
int reg_log_idx;
DECLARE_BITMAP(regs_written, TOTAL_PER_THREAD_REGS);
DECLARE_BITMAP(predicated_regs, TOTAL_PER_THREAD_REGS);
int preg_log[PRED_WRITES_MAX];
int preg_log_idx;
DECLARE_BITMAP(pregs_written, NUM_PREGS);
Expand All @@ -48,52 +49,54 @@ typedef struct DisasContext {
int tmp_vregs_idx;
int tmp_vregs_num[VECTOR_TEMPS_MAX];
int vreg_log[NUM_VREGS];
bool vreg_is_predicated[NUM_VREGS];
int vreg_log_idx;
DECLARE_BITMAP(vregs_updated_tmp, NUM_VREGS);
DECLARE_BITMAP(vregs_updated, NUM_VREGS);
DECLARE_BITMAP(vregs_select, NUM_VREGS);
DECLARE_BITMAP(predicated_future_vregs, NUM_VREGS);
DECLARE_BITMAP(predicated_tmp_vregs, NUM_VREGS);
int qreg_log[NUM_QREGS];
bool qreg_is_predicated[NUM_QREGS];
int qreg_log_idx;
bool pre_commit;
TCGCond branch_cond;
target_ulong branch_dest;
bool is_tight_loop;
bool need_pkt_has_store_s1;
} DisasContext;

static inline void ctx_log_reg_write(DisasContext *ctx, int rnum)
{
if (test_bit(rnum, ctx->regs_written)) {
HEX_DEBUG_LOG("WARNING: Multiple writes to r%d\n", rnum);
}
ctx->reg_log[ctx->reg_log_idx] = rnum;
ctx->reg_log_idx++;
set_bit(rnum, ctx->regs_written);
}

static inline void ctx_log_reg_write_pair(DisasContext *ctx, int rnum)
{
ctx_log_reg_write(ctx, rnum);
ctx_log_reg_write(ctx, rnum + 1);
}

static inline void ctx_log_pred_write(DisasContext *ctx, int pnum)
{
ctx->preg_log[ctx->preg_log_idx] = pnum;
ctx->preg_log_idx++;
set_bit(pnum, ctx->pregs_written);
if (!test_bit(pnum, ctx->pregs_written)) {
ctx->preg_log[ctx->preg_log_idx] = pnum;
ctx->preg_log_idx++;
set_bit(pnum, ctx->pregs_written);
}
}

static inline bool is_preloaded(DisasContext *ctx, int num)
static inline void ctx_log_reg_write(DisasContext *ctx, int rnum,
bool is_predicated)
{
return test_bit(num, ctx->regs_written);
if (rnum == HEX_REG_P3_0_ALIASED) {
for (int i = 0; i < NUM_PREGS; i++) {
ctx_log_pred_write(ctx, i);
}
} else {
if (!test_bit(rnum, ctx->regs_written)) {
ctx->reg_log[ctx->reg_log_idx] = rnum;
ctx->reg_log_idx++;
set_bit(rnum, ctx->regs_written);
}
if (is_predicated) {
set_bit(rnum, ctx->predicated_regs);
}
}
}

static inline bool is_vreg_preloaded(DisasContext *ctx, int num)
static inline void ctx_log_reg_write_pair(DisasContext *ctx, int rnum,
bool is_predicated)
{
return test_bit(num, ctx->vregs_updated) ||
test_bit(num, ctx->vregs_updated_tmp);
ctx_log_reg_write(ctx, rnum, is_predicated);
ctx_log_reg_write(ctx, rnum + 1, is_predicated);
}

intptr_t ctx_future_vreg_off(DisasContext *ctx, int regnum,
Expand All @@ -106,17 +109,25 @@ static inline void ctx_log_vreg_write(DisasContext *ctx,
bool is_predicated)
{
if (type != EXT_TMP) {
ctx->vreg_log[ctx->vreg_log_idx] = rnum;
ctx->vreg_is_predicated[ctx->vreg_log_idx] = is_predicated;
ctx->vreg_log_idx++;
if (!test_bit(rnum, ctx->vregs_updated)) {
ctx->vreg_log[ctx->vreg_log_idx] = rnum;
ctx->vreg_log_idx++;
set_bit(rnum, ctx->vregs_updated);
}

set_bit(rnum, ctx->vregs_updated);
if (is_predicated) {
set_bit(rnum, ctx->predicated_future_vregs);
}
}
if (type == EXT_NEW) {
set_bit(rnum, ctx->vregs_select);
}
if (type == EXT_TMP) {
set_bit(rnum, ctx->vregs_updated_tmp);
if (is_predicated) {
set_bit(rnum, ctx->predicated_tmp_vregs);
}
}
}

Expand All @@ -129,10 +140,9 @@ static inline void ctx_log_vreg_write_pair(DisasContext *ctx,
}

static inline void ctx_log_qreg_write(DisasContext *ctx,
int rnum, bool is_predicated)
int rnum)
{
ctx->qreg_log[ctx->qreg_log_idx] = rnum;
ctx->qreg_is_predicated[ctx->qreg_log_idx] = is_predicated;
ctx->qreg_log_idx++;
}

Expand All @@ -153,12 +163,20 @@ extern TCGv hex_dczero_addr;
extern TCGv hex_llsc_addr;
extern TCGv hex_llsc_val;
extern TCGv_i64 hex_llsc_val_i64;
extern TCGv hex_VRegs_updated;
extern TCGv hex_QRegs_updated;
extern TCGv hex_vstore_addr[VSTORES_MAX];
extern TCGv hex_vstore_size[VSTORES_MAX];
extern TCGv hex_vstore_pending[VSTORES_MAX];

bool is_gather_store_insn(DisasContext *ctx);
void process_store(DisasContext *ctx, int slot_num);

FIELD(PROBE_PKT_SCALAR_STORE_S0, MMU_IDX, 0, 2)
FIELD(PROBE_PKT_SCALAR_STORE_S0, IS_PREDICATED, 2, 1)

FIELD(PROBE_PKT_SCALAR_HVX_STORES, HAS_ST0, 0, 1)
FIELD(PROBE_PKT_SCALAR_HVX_STORES, HAS_ST1, 1, 1)
FIELD(PROBE_PKT_SCALAR_HVX_STORES, HAS_HVX_STORES, 2, 1)
FIELD(PROBE_PKT_SCALAR_HVX_STORES, S0_IS_PRED, 3, 1)
FIELD(PROBE_PKT_SCALAR_HVX_STORES, S1_IS_PRED, 4, 1)

#endif
13 changes: 12 additions & 1 deletion tests/tcg/hexagon/Makefile.target
@@ -1,5 +1,5 @@
##
## Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
## Copyright(c) 2019-2023 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
Expand Down Expand Up @@ -45,6 +45,10 @@ HEX_TESTS += fpstuff
HEX_TESTS += overflow
HEX_TESTS += signal_context
HEX_TESTS += reg_mut
HEX_TESTS += vector_add_int
HEX_TESTS += scatter_gather
HEX_TESTS += hvx_misc
HEX_TESTS += hvx_histogram

HEX_TESTS += test_abs
HEX_TESTS += test_bitcnt
Expand Down Expand Up @@ -78,3 +82,10 @@ TESTS += $(HEX_TESTS)
usr: usr.c
$(CC) $(CFLAGS) -mv67t -O2 -Wno-inline-asm -Wno-expansion-to-defined $< -o $@ $(LDFLAGS)

scatter_gather: CFLAGS += -mhvx
vector_add_int: CFLAGS += -mhvx -fvectorize
hvx_misc: CFLAGS += -mhvx
hvx_histogram: CFLAGS += -mhvx -Wno-gnu-folding-constant

hvx_histogram: hvx_histogram.c hvx_histogram_row.S
$(CC) $(CFLAGS) $(CROSS_CC_GUEST_CFLAGS) $^ -o $@ $(LDFLAGS)
31 changes: 30 additions & 1 deletion tests/tcg/hexagon/fpstuff.c
@@ -1,5 +1,5 @@
/*
* Copyright(c) 2020-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
* Copyright(c) 2020-2023 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
Expand Down Expand Up @@ -40,6 +40,7 @@ const int SF_HEX_NAN = 0xffffffff;
const int SF_small_neg = 0xab98fba8;
const int SF_denorm = 0x00000001;
const int SF_random = 0x346001d6;
const int SF_neg_zero = 0x80000000;

const long long DF_QNaN = 0x7ff8000000000000ULL;
const long long DF_SNaN = 0x7ff7000000000000ULL;
Expand Down Expand Up @@ -536,6 +537,33 @@ static void check_sffixupd(void)
check32(result, 0x146001d6);
}

static void check_sffms(void)
{
int result;

/* Check that sffms properly deals with -0 */
result = SF_neg_zero;
asm ("%0 -= sfmpy(%1 , %2)\n\t"
: "+r"(result)
: "r"(SF_ZERO), "r"(SF_ZERO)
: "r12", "r8");
check32(result, SF_neg_zero);

result = SF_ZERO;
asm ("%0 -= sfmpy(%1 , %2)\n\t"
: "+r"(result)
: "r"(SF_neg_zero), "r"(SF_ZERO)
: "r12", "r8");
check32(result, SF_ZERO);

result = SF_ZERO;
asm ("%0 -= sfmpy(%1 , %2)\n\t"
: "+r"(result)
: "r"(SF_ZERO), "r"(SF_neg_zero)
: "r12", "r8");
check32(result, SF_ZERO);
}

static void check_float2int_convs()
{
int res32;
Expand Down Expand Up @@ -688,6 +716,7 @@ int main()
check_invsqrta();
check_sffixupn();
check_sffixupd();
check_sffms();
check_float2int_convs();

puts(err ? "FAIL" : "PASS");
Expand Down
10 changes: 5 additions & 5 deletions tests/tcg/hexagon/preg_alias.c
@@ -1,5 +1,5 @@
/*
* Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
* Copyright(c) 2019-2023 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
Expand Down Expand Up @@ -65,7 +65,7 @@ static inline void creg_alias(int cval, PRegs *pregs)
: "=r"(pregs->pregs.p0), "=r"(pregs->pregs.p1),
"=r"(pregs->pregs.p2), "=r"(pregs->pregs.p3)
: "r"(cval)
: "p0", "p1", "p2", "p3");
: "c4", "p0", "p1", "p2", "p3");
}

int err;
Expand All @@ -92,7 +92,7 @@ static inline void creg_alias_pair(unsigned int cval, PRegs *pregs)
: "=r"(pregs->pregs.p0), "=r"(pregs->pregs.p1),
"=r"(pregs->pregs.p2), "=r"(pregs->pregs.p3), "=r"(c5)
: "r"(cval_pair)
: "p0", "p1", "p2", "p3");
: "c4", "c5", "p0", "p1", "p2", "p3");

check(c5, 0xdeadbeef);
}
Expand All @@ -117,7 +117,7 @@ static void test_packet(void)
"}\n\t"
: "+r"(result)
: "r"(0xffffffff), "r"(0xff00ffff), "r"(0x837ed653)
: "p0", "p1", "p2", "p3");
: "c4", "p0", "p1", "p2", "p3");
check(result, old_val);

/* Test a predicated store */
Expand All @@ -129,7 +129,7 @@ static void test_packet(void)
"}\n\t"
:
: "r"(0), "r"(0xffffffff), "r"(&result)
: "p0", "p1", "p2", "p3", "memory");
: "c4", "p0", "p1", "p2", "p3", "memory");
check(result, 0x0);
}

Expand Down