Compare commits
204 Commits
e2k-v9.0.0
...
termux-pat
Author | SHA1 | Date | |
---|---|---|---|
c8b2424581 | |||
2308e3519b | |||
3c31d9aa44 | |||
f4124b594b | |||
2caefbd238 | |||
2c45fb6f0b | |||
a0e898c7da | |||
7f949defe5 | |||
04cfe2ca8f | |||
50658e7362 | |||
858dcb013c | |||
6ec235945b | |||
7c128bae94 | |||
d50082e84c | |||
8c8f5fc066 | |||
74f2385990 | |||
4546d92c64 | |||
fdc6f360c6 | |||
006d4499bf | |||
afce8392d8 | |||
c78d3d7521 | |||
76ebaa78bd | |||
1f05c5e625 | |||
f0f36b5c78 | |||
d3739540cb | |||
5d6c5ac76e | |||
22f49dc828 | |||
0c7383ce04 | |||
0df8b48268 | |||
8d17c54615 | |||
802e0181d7 | |||
aeb9591179 | |||
ed29047cd7 | |||
e5021e1b70 | |||
7a1c278345 | |||
a3d10a3fa6 | |||
f39faef99d | |||
4e93ac4ed9 | |||
0809a69256 | |||
d6b9366d9d | |||
4a6eb86ce9 | |||
d3943b9e22 | |||
b35195f9ec | |||
3928837609 | |||
4d706ca329 | |||
5c8136309f | |||
f312e258db | |||
d259496a4a | |||
bee1cf054d | |||
1887af755a | |||
676b4a2388 | |||
96e7fcc99b | |||
7c8bfe6e24 | |||
39fec245f6 | |||
4591ac136d | |||
c531460961 | |||
726be4757c | |||
74d4fbcc36 | |||
261326898d | |||
082bbcad2c | |||
2ab153e322 | |||
3267e9ddab | |||
da7593ed5d | |||
b62f9057f5 | |||
f0941a1a6b | |||
24bb677df9 | |||
dc9124a532 | |||
c744d4eb35 | |||
d699173933 | |||
60208a8afa | |||
a004e745e0 | |||
a5a65eab53 | |||
2f1b4b5cf6 | |||
3c55c35c93 | |||
4f3d78cb8e | |||
c5c8c39082 | |||
ac06ae3f2b | |||
85dbd706d8 | |||
83f9917a3c | |||
f6d13b7031 | |||
f1fd51e5b4 | |||
3d6f245d89 | |||
42bbd58714 | |||
6b0e8814cc | |||
dc52e237dc | |||
f651238df2 | |||
611bf22f2f | |||
12ba786e21 | |||
090b58a1cf | |||
d59e62a8a1 | |||
72f880998e | |||
5f46345413 | |||
c481a3c875 | |||
ca1969fe1e | |||
13dd01936d | |||
a1698a963a | |||
d0f3d0ed82 | |||
9fa1537975 | |||
2a66866d38 | |||
61a3d01fe7 | |||
7475849453 | |||
9399581696 | |||
64ec73ec15 | |||
963288c9d2 | |||
038eb6f4ff | |||
16ef8861b7 | |||
c8dc14e3a6 | |||
2f4cae1a19 | |||
b947cf9f8f | |||
7a7cd856c9 | |||
73bc3e7d57 | |||
ddd9a9aca4 | |||
3cc2b2faab | |||
7febde65c7 | |||
f727916e60 | |||
dd87b0e900 | |||
d44b82eba3 | |||
008b9b53e0 | |||
779932661c | |||
8f1771d67d | |||
ccb625ced0 | |||
70076f08e7 | |||
93b5e74e02 | |||
88b9e44d2d | |||
1494afd90f | |||
f78a8ea23f | |||
58663bb93e | |||
d240aa2b85 | |||
5fe6d00b05 | |||
8558652986 | |||
c6f74e98be | |||
8f060b59f0 | |||
a10190535e | |||
5f4abd5e69 | |||
aa64434455 | |||
e5b1f1c0c4 | |||
0c676081e3 | |||
31bfefe9fd | |||
ceae6abea9 | |||
971ebe9eb1 | |||
cc5dbdb102 | |||
d2fb083c8b | |||
e01acef8ad | |||
0f10ca4949 | |||
d81651b6cb | |||
9d2966b336 | |||
3834318a0f | |||
7b81657a6e | |||
77b439a847 | |||
fdd9a777e9 | |||
49dc9ee83e | |||
ea24b9f07e | |||
7ef5d88e25 | |||
c7b6b7f8bf | |||
6bcd4980e9 | |||
5376951493 | |||
a01e83ed54 | |||
74757b094d | |||
59bdb69c27 | |||
88e79dcda9 | |||
a7e726dcb4 | |||
89b9789906 | |||
a23305afc0 | |||
d495f0ffb3 | |||
aca6a33344 | |||
6a79cc4954 | |||
f010864e2d | |||
5365ee90fc | |||
3d679a2dba | |||
d173b8feb7 | |||
231b7e7919 | |||
520053868d | |||
280d8192f9 | |||
4d14a07caf | |||
081bc9eeaa | |||
589c905dfe | |||
642865a2a7 | |||
6445d3e2ce | |||
baf638ddb6 | |||
b546643321 | |||
3432a69a5c | |||
f0d5277ccf | |||
26a18eebd3 | |||
c1a6627904 | |||
e83d027c6f | |||
ed1b58c984 | |||
12a0242083 | |||
3ba4185c39 | |||
a28ea48d7d | |||
90c70b1b66 | |||
03f49b2730 | |||
d683794bee | |||
5bee731164 | |||
57b36ae058 | |||
4d7defbc54 | |||
6922a7b034 | |||
032b505ec9 | |||
c9fcc64cea | |||
fedef3507d | |||
044483f2f8 | |||
a42160fad5 | |||
4e0f0c92bb | |||
774658d846 | |||
eeca891b81 |
@ -47,6 +47,8 @@
|
||||
#include "exec/ram_addr.h"
|
||||
#endif
|
||||
|
||||
#include <linux/mman.h>
|
||||
|
||||
#include "exec/cputlb.h"
|
||||
#include "exec/tb-hash.h"
|
||||
#include "translate-all.h"
|
||||
|
@ -24,13 +24,15 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/soundcard.h>
|
||||
#include <linux/soundcard.h>
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "audio.h"
|
||||
#include "trace.h"
|
||||
|
||||
#include <linux/mman.h>
|
||||
|
||||
#define AUDIO_CAP "oss"
|
||||
#include "audio_int.h"
|
||||
|
||||
|
2
block.c
2
block.c
@ -764,7 +764,7 @@ int get_tmp_filename(char *filename, int size)
|
||||
const char *tmpdir;
|
||||
tmpdir = getenv("TMPDIR");
|
||||
if (!tmpdir) {
|
||||
tmpdir = "/var/tmp";
|
||||
tmpdir = "@TERMUX_PREFIX@/tmp";
|
||||
}
|
||||
if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
|
||||
return -EOVERFLOW;
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include <sys/dkio.h>
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#include <linux/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/syscall.h>
|
||||
|
13
configure
vendored
13
configure
vendored
@ -2939,6 +2939,8 @@ then
|
||||
fi
|
||||
|
||||
has_libgcrypt() {
|
||||
return 0
|
||||
|
||||
if ! has "libgcrypt-config"
|
||||
then
|
||||
return 1
|
||||
@ -3008,10 +3010,7 @@ if test "$gcrypt" != "no"; then
|
||||
# Debian has removed -lgpg-error from libgcrypt-config
|
||||
# as it "spreads unnecessary dependencies" which in
|
||||
# turn breaks static builds...
|
||||
if test "$static" = "yes"
|
||||
then
|
||||
gcrypt_libs="$gcrypt_libs -lgpg-error"
|
||||
fi
|
||||
|
||||
# Link test to make sure the given libraries work (e.g for static).
|
||||
write_c_skeleton
|
||||
@ -4083,6 +4082,7 @@ EOF
|
||||
if compile_prog "" "" ; then
|
||||
signalfd=yes
|
||||
fi
|
||||
signalfd=no
|
||||
|
||||
# check if optreset global is declared by <getopt.h>
|
||||
optreset="no"
|
||||
@ -5947,6 +5947,7 @@ fi
|
||||
if test "$darwin" = "yes" ; then
|
||||
echo "CONFIG_DARWIN=y" >> $config_host_mak
|
||||
fi
|
||||
ivshmem=no
|
||||
|
||||
if test "$solaris" = "yes" ; then
|
||||
echo "CONFIG_SOLARIS=y" >> $config_host_mak
|
||||
@ -6062,9 +6063,9 @@ fi
|
||||
if test "$posix_fallocate" = "yes" ; then
|
||||
echo "CONFIG_POSIX_FALLOCATE=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$sync_file_range" = "yes" ; then
|
||||
echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak
|
||||
fi
|
||||
#if test "$sync_file_range" = "yes" ; then
|
||||
# echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak
|
||||
#fi
|
||||
if test "$fiemap" = "yes" ; then
|
||||
echo "CONFIG_FIEMAP=y" >> $config_host_mak
|
||||
fi
|
||||
|
1
default-configs/targets/e2k-linux-user.mak
Normal file
1
default-configs/targets/e2k-linux-user.mak
Normal file
@ -0,0 +1 @@
|
||||
TARGET_ARCH=e2k
|
2
disas.c
2
disas.c
@ -208,6 +208,8 @@ static void initialize_debug_host(CPUDebug *s)
|
||||
s->info.cap_insn_split = 6;
|
||||
#elif defined(__hppa__)
|
||||
s->info.print_insn = print_insn_hppa;
|
||||
#elif defined(__e2k__)
|
||||
s->info.print_insn = print_insn_e2k;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
14902
disas/e2k-opc.h
Normal file
14902
disas/e2k-opc.h
Normal file
File diff suppressed because it is too large
Load Diff
2730
disas/e2k.c
Normal file
2730
disas/e2k.c
Normal file
File diff suppressed because it is too large
Load Diff
556
disas/e2k.h
Normal file
556
disas/e2k.h
Normal file
@ -0,0 +1,556 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#define COMMON_PART \
|
||||
const char *name; \
|
||||
int (* parse_args) (char **, const struct e2k_opcode_templ *); \
|
||||
const char * (* merge) (struct e2k_opcode_templ *, const struct e2k_opcode_templ *)
|
||||
|
||||
#define ALOPF1 1
|
||||
#define ALOPF2 2
|
||||
#define ALOPF3 3
|
||||
#define ALOPF7 4
|
||||
#define ALOPF8 5
|
||||
#define ALOPF10 6
|
||||
#define ALOPF11 7
|
||||
#define ALOPF11_LIT8 8
|
||||
#define ALOPF11_MERGE 9
|
||||
#define ALOPF12 10
|
||||
#define ALOPF12_PSHUFH 11
|
||||
#define ALOPF12_IBRANCHD 12
|
||||
#define ALOPF12_ICALLD 13
|
||||
#define ALOPF13 14
|
||||
#define ALOPF15 15
|
||||
#define ALOPF16 16
|
||||
#define ALOPF21 17
|
||||
#define ALOPF21_MERGE 18
|
||||
#define ALOPF22 19
|
||||
#define MERGE 20
|
||||
#define MMURR 21
|
||||
#define MMURW 22
|
||||
#define AAURR 23
|
||||
#define AAURW 24
|
||||
#define ALOPF17 25
|
||||
|
||||
#define ALF_PART \
|
||||
u_int8_t alopf; \
|
||||
int need_mas; \
|
||||
u_int8_t opc; \
|
||||
int allowed_channels[6]
|
||||
|
||||
|
||||
#define MAS 1
|
||||
#define NO_MAS 0
|
||||
|
||||
/* ALES.opc2 values. See B.1.2 in iset.single. */
|
||||
#define EXT 0x1
|
||||
#define EXT1 0x2
|
||||
#define EXT2 0x3
|
||||
#define FLB 0x4
|
||||
#define FLH 0x5
|
||||
#define FLW 0x6
|
||||
#define FLD 0x7
|
||||
#define ICMB0 0x8
|
||||
#define ICMB1 0x9
|
||||
#define ICMB2 0xA
|
||||
#define ICMB3 0xB
|
||||
|
||||
#define FCMB0 0xC
|
||||
#define FCMB1 0xD
|
||||
#define PFCMB0 0XE
|
||||
#define PFCMB1 0xF
|
||||
#define LCMBD0 0x10
|
||||
#define LCMBD1 0x11
|
||||
#define LCMBQ0 0x12
|
||||
#define LCMBQ1 0x13
|
||||
#define QPFCMB0 0x16
|
||||
#define QPFCMB1 0x17
|
||||
|
||||
|
||||
/* ALES.opce values. */
|
||||
#define NONE 0xc0
|
||||
|
||||
|
||||
/* It seems that LAS doesn't support %xr's, that's
|
||||
why everywhere where an x-args is supposed we
|
||||
use a d-one. */
|
||||
typedef enum {
|
||||
SINGLE,
|
||||
DOUBLE,
|
||||
QUAD,
|
||||
QPACKED
|
||||
} e2k_register_format;
|
||||
|
||||
|
||||
#define ARGS_S SINGLE
|
||||
#define ARGS_D DOUBLE
|
||||
#define ARGS_Q QUAD
|
||||
#define ARGS_P QPACKED
|
||||
|
||||
#define ARGS_SS {SINGLE, SINGLE}
|
||||
#define ARGS_SD {SINGLE, DOUBLE}
|
||||
#define ARGS_SQ {SINGLE, QUAD}
|
||||
#define ARGS_DS {DOUBLE, SINGLE}
|
||||
#define ARGS_DD {DOUBLE, DOUBLE}
|
||||
#define ARGS_DQ {DOUBLE, QUAD}
|
||||
#define ARGS_DP {DOUBLE, QPACKED}
|
||||
#define ARGS_QS {QUAD, SINGLE}
|
||||
#define ARGS_PS {QPACKED, SINGLE}
|
||||
#define ARGS_QD {QUAD, DOUBLE}
|
||||
#define ARGS_PD {QPACKED, DOUBLE}
|
||||
#define ARGS_QQ {QUAD, QUAD}
|
||||
#define ARGS_PP {QPACKED, QPACKED}
|
||||
|
||||
#define ARGS_SSS {SINGLE, SINGLE, SINGLE}
|
||||
#define ARGS_SSD {SINGLE, SINGLE, DOUBLE}
|
||||
#define ARGS_SSQ {SINGLE, SINGLE, QUAD}
|
||||
#define ARGS_SSP {SINGLE, SINGLE, QPACKED}
|
||||
#define ARGS_SDD {SINGLE, DOUBLE, DOUBLE}
|
||||
#define ARGS_DSS {DOUBLE, SINGLE, SINGLE}
|
||||
#define ARGS_DSD {DOUBLE, SINGLE, DOUBLE}
|
||||
#define ARGS_DDS {DOUBLE, DOUBLE, SINGLE}
|
||||
#define ARGS_DDD {DOUBLE, DOUBLE, DOUBLE}
|
||||
#define ARGS_DDQ {DOUBLE, DOUBLE, QUAD}
|
||||
#define ARGS_DDP {DOUBLE, DOUBLE, QPACKED}
|
||||
#define ARGS_DQQ {DOUBLE, QUAD, QUAD}
|
||||
#define ARGS_DPP {DOUBLE, QPACKED, QPACKED}
|
||||
#define ARGS_QSS {QUAD, SINGLE, SINGLE}
|
||||
#define ARGS_QSD {QUAD, SINGLE, DOUBLE}
|
||||
#define ARGS_QSQ {QUAD, SINGLE, QUAD}
|
||||
#define ARGS_PSP {QPACKED, SINGLE, QPACKED}
|
||||
#define ARGS_QSP {QUAD, SINGLE, QPACKED}
|
||||
#define ARGS_QDQ {QUAD, DOUBLE, QUAD}
|
||||
#define ARGS_PDP {QPACKED, DOUBLE, QPACKED}
|
||||
#define ARGS_QQD {QUAD, QUAD, DOUBLE}
|
||||
#define ARGS_PPD {QPACKED, QPACKED, DOUBLE}
|
||||
#define ARGS_QQQ {QUAD, QUAD, QUAD}
|
||||
#define ARGS_PPP {QPACKED, QPACKED, QPACKED}
|
||||
|
||||
#define ARGS_SSSS {SINGLE, SINGLE, SINGLE, SINGLE}
|
||||
#define ARGS_DDSD {DOUBLE, DOUBLE, SINGLE, DOUBLE}
|
||||
#define ARGS_DDDD {DOUBLE, DOUBLE, DOUBLE, DOUBLE}
|
||||
#define ARGS_QQQQ {QUAD, QUAD, QUAD, QUAD}
|
||||
#define ARGS_PPPP {QPACKED, QPACKED, QPACKED, QPACKED}
|
||||
|
||||
#define ALL_SINGLE {SINGLE, SINGLE, SINGLE}
|
||||
#define ALL_DOUBLE {DOUBLE, DOUBLE, DOUBLE}
|
||||
|
||||
|
||||
|
||||
typedef struct e2k_opcode_templ
|
||||
{
|
||||
COMMON_PART;
|
||||
} e2k_opcode_templ;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
} e2k_alf_opcode_templ;
|
||||
|
||||
|
||||
|
||||
#define ALF1_PART \
|
||||
e2k_register_format arg_fmt[3]
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALF1_PART;
|
||||
} e2k_alf1_opcode_templ;
|
||||
|
||||
|
||||
#define ALF2_PART \
|
||||
e2k_register_format arg_fmt[2]; \
|
||||
u_int8_t opce
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALF2_PART;
|
||||
} e2k_alf2_opcode_templ;
|
||||
|
||||
|
||||
|
||||
#define ALF3_PART \
|
||||
e2k_register_format arg_fmt[3]
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALF3_PART;
|
||||
} e2k_alf3_opcode_templ;
|
||||
|
||||
|
||||
#define ALOPF12_PART \
|
||||
e2k_register_format arg_fmt[2]; \
|
||||
u_int8_t opce; \
|
||||
u_int8_t ales_opce; \
|
||||
u_int8_t ales_opc2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALOPF12_PART;
|
||||
} e2k_alopf12_opcode_templ;
|
||||
|
||||
|
||||
|
||||
#define ALOPF13_PART \
|
||||
e2k_register_format arg_fmt[3]; \
|
||||
u_int8_t ales_opce; \
|
||||
u_int8_t ales_opc2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALOPF13_PART;
|
||||
} e2k_alopf13_opcode_templ;
|
||||
|
||||
|
||||
|
||||
#define ALOPF15_PART \
|
||||
e2k_register_format arg_fmt
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALOPF15_PART;
|
||||
} e2k_alopf15_opcode_templ;
|
||||
|
||||
typedef e2k_alopf15_opcode_templ e2k_alopf16_opcode_templ;
|
||||
|
||||
#define CMPsb 0x20
|
||||
#define CMPdb 0x21
|
||||
#define CMPANDsb 0x22
|
||||
#define FXCMPxb 0x2b
|
||||
#define FCMPdb 0x2f
|
||||
|
||||
typedef enum {
|
||||
CMPOPCE_0 = 0,
|
||||
CMPOPCE_1,
|
||||
CMPOPCE_2,
|
||||
CMPOPCE_3,
|
||||
CMPOPCE_4,
|
||||
CMPOPCE_5,
|
||||
CMPOPCE_6,
|
||||
CMPOPCE_7
|
||||
} cmpopce_t;
|
||||
|
||||
#define ALF7_PART \
|
||||
e2k_register_format arg_fmt[2]; \
|
||||
cmpopce_t cmpopce; \
|
||||
int implicit_nops;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALF7_PART;
|
||||
} e2k_alf7_opcode_templ;
|
||||
|
||||
#define ALF9_PART \
|
||||
e2k_register_format arg_fmt;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALF9_PART;
|
||||
} e2k_alf9_opcode_templ;
|
||||
|
||||
|
||||
#define ALF10_PART \
|
||||
e2k_register_format arg_fmt;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALF10_PART;
|
||||
} e2k_alf10_opcode_templ;
|
||||
|
||||
|
||||
#define ALF8_PART \
|
||||
e2k_register_format arg_fmt; \
|
||||
cmpopce_t cmpopce
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALF8_PART;
|
||||
} e2k_alf8_opcode_templ;
|
||||
|
||||
#define ALOPF11_PART \
|
||||
e2k_register_format arg_fmt[3]; \
|
||||
u_int8_t ales_opce; \
|
||||
u_int8_t ales_opc2[6]; \
|
||||
int explicit_ales25_v4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALOPF11_PART;
|
||||
} e2k_alopf11_opcode_templ;
|
||||
|
||||
|
||||
#define ALOPF11_LIT8_PART \
|
||||
u_int8_t max_lit8; \
|
||||
const char *warn
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALOPF11_PART;
|
||||
ALOPF11_LIT8_PART;
|
||||
} e2k_alopf11_lit8_opcode_templ;
|
||||
|
||||
|
||||
#define ALOPF21_PART \
|
||||
e2k_register_format arg_fmt[4]; \
|
||||
u_int8_t ales_opc2;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
ALF_PART;
|
||||
ALOPF21_PART;
|
||||
} e2k_alopf21_opcode_templ;
|
||||
|
||||
|
||||
#define NO_LABEL 0
|
||||
#define EXPECT_LABEL 1
|
||||
|
||||
#define NO_CTPR {0, 0, 0}
|
||||
#define CTPR2 {0, 1, 0}
|
||||
#define CTPR3 {0, 0, 1}
|
||||
#define ALL_CTPRS {1, 1, 1}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
u_int8_t ctp_opc;
|
||||
int allowed_ctprs[3];
|
||||
int label_expected;
|
||||
} e2k_copf2_opcode_templ;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
unsigned id;
|
||||
} e2k_setcmd_opcode_templ;
|
||||
|
||||
#define MOVA_PART \
|
||||
u_int16_t opc; \
|
||||
e2k_register_format arg_fmt;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
COMMON_PART;
|
||||
MOVA_PART;
|
||||
} e2k_mova_opcode_templ;
|
||||
|
||||
|
||||
|
||||
|
||||
static int parse_alf_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_copf2_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_pref_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_copf4_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_nop_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_setcmd_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_setsft_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_wait_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_ct_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_hcall_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_ipd_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
static int parse_loop_mode_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_alc_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_abn_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_abp_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_abg_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_bap_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_eap_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
|
||||
static int parse_pass_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_andp_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_landp_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_ibranch_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_done_hret_glaunch_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
static int parse_incr_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_mova_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_fapb_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_movep_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
static int parse_flushts_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
static int parse_cpl_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
static int parse_set_mark_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
static int parse_vfdi_args (char **s, const e2k_opcode_templ *t) { return 0; }
|
||||
|
||||
|
||||
|
||||
extern struct e2k_opcode_templ *e2k_opcode_templs[];
|
||||
extern size_t e2k_num_opcodes;
|
||||
|
||||
|
||||
typedef enum {
|
||||
WINDOW,
|
||||
BASED,
|
||||
GLOBAL,
|
||||
SPECIAL,
|
||||
AASTI
|
||||
} e2k_register_type;
|
||||
|
||||
typedef struct {
|
||||
u_int8_t idx;
|
||||
e2k_register_type type;
|
||||
e2k_register_format fmt;
|
||||
} e2k_generic_register;
|
||||
|
||||
|
||||
typedef enum {
|
||||
LITERAL_4 = -3,
|
||||
LITERAL_5,
|
||||
/* LITERAL_8 should be used exclusively for encoding ALEF2.opce
|
||||
in PSHUF{W,H}. */
|
||||
LITERAL_8,
|
||||
LITERAL_16,
|
||||
LITERAL_32,
|
||||
LITERAL_64
|
||||
} e2k_literal_size;
|
||||
|
||||
typedef struct {
|
||||
e2k_literal_size size;
|
||||
int sgnd;
|
||||
} e2k_literal_format;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int negated;
|
||||
int pred_num;
|
||||
int pred_fld;
|
||||
} e2k_pred;
|
||||
|
||||
/* The maximal possible number of ALCes in the wide instruction. */
|
||||
#define ALS_CHANNELS_NUMBER 6
|
||||
|
||||
#define opc_field \
|
||||
struct { \
|
||||
u_int8_t cop : 7; \
|
||||
u_int8_t spec : 1; \
|
||||
} opc
|
||||
|
||||
#define GENERIC_ALS \
|
||||
/* May be 1, 2, 3, 5, 6, 7, 8, 9, 10 for appropriate ALF's. */ \
|
||||
int fmt; \
|
||||
/* Pointer to a function which will finalize this ALS after all long \
|
||||
literals in the containing wide instruction have been \
|
||||
accommodated. */ \
|
||||
int (* finish) (struct e2k_als *); \
|
||||
/* The value of ALS which should be encoded. */ \
|
||||
union { \
|
||||
struct { \
|
||||
u_int8_t dst, src2, src1; \
|
||||
opc_field; \
|
||||
} alf1; \
|
||||
struct { \
|
||||
u_int8_t dst, src2, opce; \
|
||||
opc_field; \
|
||||
} alf2; \
|
||||
struct { \
|
||||
u_int8_t src3, src2, src1; \
|
||||
opc_field; \
|
||||
} alf3; \
|
||||
struct { \
|
||||
u_int8_t regn, src2, opce; \
|
||||
opc_field; \
|
||||
} alf5; \
|
||||
struct { \
|
||||
u_int8_t dst, none, regn; \
|
||||
opc_field; \
|
||||
} alf6; \
|
||||
struct { \
|
||||
struct { \
|
||||
u_int8_t pdst : 5; \
|
||||
u_int8_t cmpopce : 3; \
|
||||
} dst2; \
|
||||
u_int8_t src2, src1; \
|
||||
opc_field; \
|
||||
} alf7; \
|
||||
struct { \
|
||||
struct { \
|
||||
u_int8_t pdst : 5; \
|
||||
u_int8_t cmpopce : 3; \
|
||||
} dst2; \
|
||||
u_int8_t src2, opce; \
|
||||
opc_field; \
|
||||
} alf8; \
|
||||
struct { \
|
||||
u_int8_t dst; \
|
||||
u_int8_t opce1_lo; \
|
||||
u_int8_t opce1_hi; \
|
||||
opc_field; \
|
||||
} alf9; \
|
||||
struct { \
|
||||
u_int8_t src3; \
|
||||
u_int8_t opce1_lo; \
|
||||
u_int8_t opce1_hi; \
|
||||
opc_field; \
|
||||
} alf10; \
|
||||
u_int32_t val; \
|
||||
} u[2]; \
|
||||
\
|
||||
/* Therse two are used for quad ops occupying two channels. */ \
|
||||
unsigned real_als_nmb; \
|
||||
/* The first element in real_alses will always be the minor \
|
||||
channel number. I want the user to be able to write \
|
||||
stapq,5 instead of stapq,2. */ \
|
||||
unsigned real_alses[6][2]; \
|
||||
\
|
||||
/* This means that ALS{j,k}.src1 should contain the same value \
|
||||
in both channels. This is required to encode LDAPQ and STAPQ \
|
||||
properly. */ \
|
||||
int same_src1_quad; \
|
||||
\
|
||||
/* The number of valid placements. It can be 6 at maximum, which \
|
||||
corresponds to ALC0, . . , ALC5. */ \
|
||||
int plcmnt_nmb; \
|
||||
int pos[ALS_CHANNELS_NUMBER]; \
|
||||
/* The most optimal index in pos[]. */ \
|
||||
int optimal_plcmnt_idx
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
u_int8_t src3;
|
||||
u_int8_t opc2;
|
||||
} alef1;
|
||||
|
||||
struct {
|
||||
u_int8_t opce;
|
||||
u_int8_t opc2;
|
||||
} alef2;
|
||||
|
||||
u_int16_t hword;
|
||||
} e2k_ales;
|
||||
|
||||
|
||||
extern void init_opcode_templs (void);
|
||||
|
||||
extern int mcpu;
|
@ -6,6 +6,7 @@ common_ss.add(when: 'CONFIG_ARM_A64_DIS', if_true: files('arm-a64.cc'))
|
||||
common_ss.add_all(when: 'CONFIG_ARM_A64_DIS', if_true: libvixl_ss)
|
||||
common_ss.add(when: 'CONFIG_ARM_DIS', if_true: files('arm.c'))
|
||||
common_ss.add(when: 'CONFIG_CRIS_DIS', if_true: files('cris.c'))
|
||||
common_ss.add(when: 'CONFIG_E2K_DIS', if_true: files('e2k.c'))
|
||||
common_ss.add(when: 'CONFIG_HPPA_DIS', if_true: files('hppa.c'))
|
||||
common_ss.add(when: 'CONFIG_I386_DIS', if_true: files('i386.c'))
|
||||
common_ss.add(when: 'CONFIG_LM32_DIS', if_true: files('lm32.c'))
|
||||
|
@ -138,7 +138,7 @@ static FloatParts parts_default_nan(float_status *status)
|
||||
/* !snan_bit_is_one, set all bits */
|
||||
frac = (1ULL << DECOMPOSED_BINARY_POINT) - 1;
|
||||
#elif defined(TARGET_I386) || defined(TARGET_X86_64) \
|
||||
|| defined(TARGET_MICROBLAZE)
|
||||
|| defined(TARGET_MICROBLAZE) || defined(TARGET_E2K)
|
||||
/* !snan_bit_is_one, set sign and msb */
|
||||
frac = 1ULL << (DECOMPOSED_BINARY_POINT - 1);
|
||||
sign = 1;
|
||||
|
@ -44,6 +44,18 @@ typedef struct V9fsIattr {
|
||||
int64_t mtime_nsec;
|
||||
} V9fsIattr;
|
||||
|
||||
#ifdef st_atime_nsec
|
||||
# undef st_atime_nsec
|
||||
#endif
|
||||
|
||||
#ifdef st_mtime_nsec
|
||||
# undef st_mtime_nsec
|
||||
#endif
|
||||
|
||||
#ifdef st_ctime_nsec
|
||||
# undef st_ctime_nsec
|
||||
#endif
|
||||
|
||||
typedef struct V9fsStatDotl {
|
||||
uint64_t st_result_mask;
|
||||
V9fsQID qid;
|
||||
|
40
gdbstub.c
40
gdbstub.c
@ -2177,6 +2177,12 @@ static void handle_query_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
|
||||
gdbserver_state.multiprocess = true;
|
||||
}
|
||||
|
||||
#ifdef TARGET_E2K
|
||||
// TODO: qXfer:tags:write+
|
||||
// TODO: qXfer:packed_tags:read+
|
||||
g_string_append(gdbserver_state.str_buf, ";qXfer:tags:read+");
|
||||
#endif
|
||||
|
||||
g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+");
|
||||
put_strbuf();
|
||||
}
|
||||
@ -2271,6 +2277,32 @@ static void handle_set_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx, void *user_ctx)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_E2K
|
||||
static void handle_query_e2k_tags_read(GdbCmdContext *gdb_ctx, void *user_ctx)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(gdbserver_state.g_cpu);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
target_ulong addr = gdb_ctx->params[0].val_ull;
|
||||
unsigned long len = gdb_ctx->params[1].val_ul;
|
||||
unsigned int i;
|
||||
int tags = 0;
|
||||
|
||||
g_string_assign(gdbserver_state.str_buf, "l");
|
||||
if (env->psp.base <= addr && addr < (env->psp.base + env->psp.size)) {
|
||||
target_ulong offset = addr - env->psp.base;
|
||||
tags = cpu_ldub_data(env, env->psp.base_tag + offset / 8);
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int tag = (tags >> i * E2K_TAG_SIZE) & 0x3;
|
||||
g_string_append_c(gdbserver_state.str_buf, tag);
|
||||
}
|
||||
|
||||
put_packet_binary(gdbserver_state.str_buf->str,
|
||||
gdbserver_state.str_buf->len, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
static GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
|
||||
/* Order is important if has same prefix */
|
||||
{
|
||||
@ -2357,6 +2389,14 @@ static GdbCmdParseEntry gdb_gen_query_table[] = {
|
||||
.cmd = "qemu.PhyMemMode",
|
||||
},
|
||||
#endif
|
||||
#ifdef TARGET_E2K
|
||||
{
|
||||
.handler = handle_query_e2k_tags_read,
|
||||
.cmd = "Xfer:tags:read::",
|
||||
.cmd_startswith = 1,
|
||||
.schema = "L,l0",
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static GdbCmdParseEntry gdb_gen_set_table[] = {
|
||||
|
@ -535,9 +535,23 @@ static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
|
||||
rewinddir(fs->dir.stream);
|
||||
}
|
||||
|
||||
struct DIR {
|
||||
int fd_;
|
||||
};
|
||||
|
||||
static long android_telldir(struct DIR *dirp)
|
||||
{
|
||||
return (long) lseek(dirp->fd_, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
static void android_seekdir(DIR *dirp, long loc)
|
||||
{
|
||||
(void) lseek(dirp->fd_, loc, SEEK_SET);
|
||||
}
|
||||
|
||||
static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
|
||||
{
|
||||
return telldir(fs->dir.stream);
|
||||
return android_telldir(fs->dir.stream);
|
||||
}
|
||||
|
||||
static bool local_is_mapped_file_metadata(FsContext *fs_ctx, const char *name)
|
||||
@ -571,7 +585,7 @@ again:
|
||||
|
||||
static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
|
||||
{
|
||||
seekdir(fs->dir.stream, off);
|
||||
android_seekdir(fs->dir.stream, off);
|
||||
}
|
||||
|
||||
static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,
|
||||
|
@ -675,9 +675,23 @@ static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
|
||||
rewinddir(fs->dir.stream);
|
||||
}
|
||||
|
||||
struct DIR {
|
||||
int fd_;
|
||||
};
|
||||
|
||||
static long android_telldir(struct DIR *dirp)
|
||||
{
|
||||
return (long) lseek(dirp->fd_, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
static void android_seekdir(DIR *dirp, long loc)
|
||||
{
|
||||
(void) lseek(dirp->fd_, loc, SEEK_SET);
|
||||
}
|
||||
|
||||
static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs)
|
||||
{
|
||||
return telldir(fs->dir.stream);
|
||||
return android_telldir(fs->dir.stream);
|
||||
}
|
||||
|
||||
static struct dirent *proxy_readdir(FsContext *ctx, V9fsFidOpenState *fs)
|
||||
@ -687,7 +701,7 @@ static struct dirent *proxy_readdir(FsContext *ctx, V9fsFidOpenState *fs)
|
||||
|
||||
static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
|
||||
{
|
||||
seekdir(fs->dir.stream, off);
|
||||
android_seekdir(fs->dir.stream, off);
|
||||
}
|
||||
|
||||
static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs,
|
||||
|
@ -101,19 +101,19 @@ static FWCfgState *create_fw_cfg(MachineState *ms)
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, ms->ram_size);
|
||||
|
||||
val = cpu_to_le64(MIN_SEABIOS_HPPA_VERSION);
|
||||
fw_cfg_add_file(fw_cfg, "/etc/firmware-min-version",
|
||||
fw_cfg_add_file(fw_cfg, "@TERMUX_PREFIX@/etc/firmware-min-version",
|
||||
g_memdup(&val, sizeof(val)), sizeof(val));
|
||||
|
||||
val = cpu_to_le64(HPPA_TLB_ENTRIES);
|
||||
fw_cfg_add_file(fw_cfg, "/etc/cpu/tlb_entries",
|
||||
fw_cfg_add_file(fw_cfg, "@TERMUX_PREFIX@/etc/cpu/tlb_entries",
|
||||
g_memdup(&val, sizeof(val)), sizeof(val));
|
||||
|
||||
val = cpu_to_le64(HPPA_BTLB_ENTRIES);
|
||||
fw_cfg_add_file(fw_cfg, "/etc/cpu/btlb_entries",
|
||||
fw_cfg_add_file(fw_cfg, "@TERMUX_PREFIX@/etc/cpu/btlb_entries",
|
||||
g_memdup(&val, sizeof(val)), sizeof(val));
|
||||
|
||||
val = cpu_to_le64(HPA_POWER_BUTTON);
|
||||
fw_cfg_add_file(fw_cfg, "/etc/power-button-addr",
|
||||
fw_cfg_add_file(fw_cfg, "@TERMUX_PREFIX@/etc/power-button-addr",
|
||||
g_memdup(&val, sizeof(val)), sizeof(val));
|
||||
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ms->boot_order[0]);
|
||||
|
@ -417,7 +417,7 @@ static void clean_event_notifier(EmulatedState *card)
|
||||
event_notifier_cleanup(&card->notifier);
|
||||
}
|
||||
|
||||
#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
|
||||
#define CERTIFICATES_DEFAULT_DB "@TERMUX_PREFIX@/etc/pki/nssdb"
|
||||
#define CERTIFICATES_ARGS_TEMPLATE\
|
||||
"db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)"
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/kvm.h>
|
||||
#endif
|
||||
#include <linux/vfio.h>
|
||||
#include <linux/mman.h>
|
||||
|
||||
#include "hw/vfio/vfio-common.h"
|
||||
#include "hw/vfio/vfio.h"
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include "pci.h"
|
||||
#include "trace.h"
|
||||
|
||||
#include <linux/mman.h>
|
||||
|
||||
/*
|
||||
* List of device ids/vendor ids for which to disable
|
||||
* option rom loading. This avoids the guest hangs during rom
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "standard-headers/linux/vhost_types.h"
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
#include <linux/mman.h>
|
||||
#include <linux/userfaultfd.h>
|
||||
#endif
|
||||
|
||||
|
@ -235,6 +235,23 @@ enum bfd_architecture
|
||||
#define bfd_mach_cris_v32 32
|
||||
#define bfd_mach_cris_v10_v32 1032
|
||||
bfd_arch_microblaze, /* Xilinx MicroBlaze. */
|
||||
bfd_arch_e2k, /* MCST E2K. */
|
||||
/* It's crucial that the underlying `bfd_mach_e2k*' have the same values as */
|
||||
/* the corresponding `E_E2K_MACH_*'s!!! */
|
||||
#define bfd_mach_e2k_generic 0
|
||||
#define bfd_mach_e2k_ev1 1
|
||||
/* This is interpreted as the common subset of all Elbrus V2 iterations.
|
||||
Currently it is the same as the common subset of all elbrus-2c+. */
|
||||
#define bfd_mach_e2k_ev2 2
|
||||
#define bfd_mach_e2k_ev3 3
|
||||
#define bfd_mach_e2k_ev4 4
|
||||
#define bfd_mach_e2k_ev5 5
|
||||
#define bfd_mach_e2k_ev6 6
|
||||
/* Values 16, 17 and 18 used to be reserved for the first three iterations
|
||||
of `elbrus-v2'. See `include/elf/e2k.h' for why they can't be reused right
|
||||
now. */
|
||||
#define bfd_mach_e2k_8c 19
|
||||
#define bfd_mach_e2k_1cplus 20
|
||||
bfd_arch_moxie, /* The Moxie core. */
|
||||
bfd_arch_ia64, /* HP/Intel ia64 */
|
||||
#define bfd_mach_ia64_elf64 64
|
||||
@ -404,6 +421,14 @@ typedef struct disassemble_info {
|
||||
int cap_insn_unit;
|
||||
int cap_insn_split;
|
||||
|
||||
/* If non-zero then try not disassemble beyond this address, even if
|
||||
there are values left in the buffer. This address is the address
|
||||
of the nearest symbol forwards from the start of the disassembly,
|
||||
and it is assumed that it lies on the boundary between instructions.
|
||||
If an instruction spans this address then this is an error in the
|
||||
file being disassembled. */
|
||||
bfd_vma stop_vma;
|
||||
|
||||
} disassemble_info;
|
||||
|
||||
/* Standard disassemblers. Disassemble one instruction at the given
|
||||
@ -459,6 +484,7 @@ int print_insn_xtensa (bfd_vma, disassemble_info*);
|
||||
int print_insn_riscv32 (bfd_vma, disassemble_info*);
|
||||
int print_insn_riscv64 (bfd_vma, disassemble_info*);
|
||||
int print_insn_rx(bfd_vma, disassemble_info *);
|
||||
int print_insn_e2k (bfd_vma, disassemble_info*);
|
||||
|
||||
#ifdef CONFIG_CAPSTONE
|
||||
bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size);
|
||||
|
@ -178,6 +178,9 @@ typedef struct mips_elf_abiflags_v0 {
|
||||
|
||||
#define EM_RX 173 /* Renesas RX family */
|
||||
|
||||
#define EM_MCST_ELBRUS 175 /* MCST Elbrus */
|
||||
#define EM_E2K_OLD 49 /* `e_machine' used in old binaries for E2K */
|
||||
|
||||
#define EM_RISCV 243 /* RISC-V */
|
||||
|
||||
#define EM_NANOMIPS 249 /* Wave Computing nanoMIPS */
|
||||
@ -1415,6 +1418,82 @@ typedef struct {
|
||||
#define EF_RISCV_RVE 0x0008
|
||||
#define EF_RISCV_TSO 0x0010
|
||||
|
||||
/* E2k specific definitions. */
|
||||
|
||||
/* Values for Elf32/64_Ehdr.e_flags. */
|
||||
|
||||
#define EF_E2K_IPD 3
|
||||
#define EF_E2K_X86APP 4
|
||||
#define EF_E2K_4MB_PAGES 8
|
||||
#define EF_E2K_INCOMPAT 16
|
||||
#define EF_E2K_PM 32
|
||||
#define EF_E2K_BUG_75842 64
|
||||
|
||||
/* E2k relocs. */
|
||||
|
||||
#define R_E2K_32_ABS 0 /* Direct 32 bit */
|
||||
#define R_E2K_32_PC 2 /* PC relative 32 bit */
|
||||
#define R_E2K_32_JMP_SLOT 8 /* Create PLT entry */
|
||||
#define R_E2K_32_COPY 9 /* Copy relocation */
|
||||
#define R_E2K_32_RELATIVE 10 /* Adjust by program base */
|
||||
#define R_E2K_32_IRELATIVE 11
|
||||
#define R_E2K_32_SIZE 12
|
||||
|
||||
#define R_E2K_64_ABS 50 /* Direct 64 bit */
|
||||
#define R_E2K_64_ABS_LIT 51 /* Direct 64 bit for literal */
|
||||
#define R_E2K_64_PC_LIT 54 /* PC relative 64 bit for literal */
|
||||
#define R_E2K_64_JMP_SLOT 63 /* Create PLT entry */
|
||||
#define R_E2K_64_COPY 64 /* Copy relocation */
|
||||
#define R_E2K_64_RELATIVE 65 /* Adjust by program base */
|
||||
#define R_E2K_64_RELATIVE_LIT 66 /* Adjust by program base for literal */
|
||||
#define R_E2K_64_IRELATIVE 67
|
||||
#define R_E2K_64_SIZE 68
|
||||
#define R_E2K_64_GOTOFF 69
|
||||
|
||||
#define R_E2K_TLS_GDMOD 70
|
||||
#define R_E2K_TLS_GDREL 71
|
||||
#define R_E2K_TLS_IE 74
|
||||
#define R_E2K_32_TLS_LE 75
|
||||
#define R_E2K_64_TLS_LE 76
|
||||
#define R_E2K_TLS_32_DTPMOD 80 /* ID of module containing symbol */
|
||||
#define R_E2K_TLS_32_DTPREL 81
|
||||
#define R_E2K_TLS_64_DTPMOD 82 /* ID of module containing symbol */
|
||||
#define R_E2K_TLS_64_DTPREL 83
|
||||
#define R_E2K_TLS_32_TPREL 84
|
||||
#define R_E2K_TLS_64_TPREL 85
|
||||
|
||||
#define R_E2K_AP 100
|
||||
#define R_E2K_PL 101
|
||||
|
||||
#define R_E2K_GOT 108 /* 32 bit GOT entry */
|
||||
#define R_E2K_GOTOFF 109 /* 32 bit offset to GOT */
|
||||
#define R_E2K_DISP 110 /* PC relative 28 bit for DISP */
|
||||
#define R_E2K_PREF 111
|
||||
#define R_E2K_NONE 112 /* No reloc */
|
||||
|
||||
|
||||
/* Legal values for d_tag field of Elf32_Dyn. */
|
||||
|
||||
/* FIXME: find out whether old dynamic tags may be renamed and their names
|
||||
* be used by modern ones or new names should be customized for modern tags.
|
||||
* This concerns DT_E2K_LAZY renamed to DT_E2K_LAZY_DEFECTIVE. */
|
||||
#define DT_E2K_LAZY_DEFECTIVE (DT_LOPROC + 0)
|
||||
#define DT_E2K_LAZY (DT_LOPROC + 1)
|
||||
|
||||
/* This tag will be hopefully used for a limited period of time. `DT_LOPROC + 1'
|
||||
* has already been reserved in glibc-2.16 and binutils-2.23.1 to mark
|
||||
* non-defective lazy binding implementation without this awful Bug #75842 taken
|
||||
* into account. */
|
||||
#define DT_E2K_LAZY_BUG_75842 (DT_LOPROC + 2)
|
||||
#define DT_E2K_LAZY_GOT (DT_LOPROC + 3)
|
||||
|
||||
#define DT_E2K_INIT_GOT (DT_LOPROC + 0x101c)
|
||||
#define DT_E2K_EXPORT_PL (DT_LOPROC + 0x101d)
|
||||
#define DT_E2K_EXPORT_PLSZ (DT_LOPROC + 0x101e)
|
||||
#define DT_E2K_REAL_PLTGOT (DT_LOPROC + 0x101f)
|
||||
|
||||
#define DT_E2K_NUM 0x1020
|
||||
|
||||
typedef struct elf32_rel {
|
||||
Elf32_Addr r_offset;
|
||||
Elf32_Word r_info;
|
||||
|
@ -11,6 +11,10 @@
|
||||
#ifndef QAPI_UTIL_H
|
||||
#define QAPI_UTIL_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct Error Error;
|
||||
|
||||
typedef struct QEnumLookup {
|
||||
const char *const *array;
|
||||
int size;
|
||||
|
@ -275,7 +275,7 @@ typedef struct TCGPool {
|
||||
|
||||
#define TCG_POOL_CHUNK_SIZE 32768
|
||||
|
||||
#define TCG_MAX_TEMPS 512
|
||||
#define TCG_MAX_TEMPS 1024
|
||||
#define TCG_MAX_INSNS 512
|
||||
|
||||
/* when the size of the arguments of a called function is smaller than
|
||||
|
@ -38,7 +38,7 @@ struct target_ucontext {
|
||||
target_stack_t tuc_stack;
|
||||
target_sigset_t tuc_sigmask;
|
||||
/* glibc uses a 1024-bit sigset_t */
|
||||
char __unused[1024 / 8 - sizeof(target_sigset_t)];
|
||||
char __qemu_unused[1024 / 8 - sizeof(target_sigset_t)];
|
||||
/* last for future expansion */
|
||||
struct target_sigcontext tuc_mcontext;
|
||||
};
|
||||
|
@ -59,7 +59,7 @@ struct target_ucontext_v2 {
|
||||
target_stack_t tuc_stack;
|
||||
struct target_sigcontext tuc_mcontext;
|
||||
target_sigset_t tuc_sigmask; /* mask last for extensibility */
|
||||
char __unused[128 - sizeof(target_sigset_t)];
|
||||
char __qemu_unused[128 - sizeof(target_sigset_t)];
|
||||
abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
|
||||
};
|
||||
|
||||
|
129
linux-user/e2k/cpu_loop.c
Normal file
129
linux-user/e2k/cpu_loop.c
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* qemu user cpu loop
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu.h"
|
||||
#include "cpu_loop-common.h"
|
||||
|
||||
void cpu_loop(CPUE2KState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
int trapnr;
|
||||
target_siginfo_t info;
|
||||
|
||||
while (1) {
|
||||
cpu_exec_start(cs);
|
||||
trapnr = cpu_exec(cs);
|
||||
cpu_exec_end(cs);
|
||||
process_queued_cpu_work(cs);
|
||||
|
||||
switch (trapnr) {
|
||||
case E2K_EXCP_SYSCALL: {
|
||||
int offset = E2K_NR_COUNT + env->wd.base + env->syscall_wbs * 2;
|
||||
uint64_t *regs = env->regs;
|
||||
abi_ulong ret = do_syscall(env,
|
||||
regs[(0 + offset) % E2K_NR_COUNT],
|
||||
regs[(1 + offset) % E2K_NR_COUNT],
|
||||
regs[(2 + offset) % E2K_NR_COUNT],
|
||||
regs[(3 + offset) % E2K_NR_COUNT],
|
||||
regs[(4 + offset) % E2K_NR_COUNT],
|
||||
regs[(5 + offset) % E2K_NR_COUNT],
|
||||
regs[(6 + offset) % E2K_NR_COUNT],
|
||||
regs[(7 + offset) % E2K_NR_COUNT],
|
||||
regs[(8 + offset) % E2K_NR_COUNT]
|
||||
);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
/* TODO: restart syscall */
|
||||
abort();
|
||||
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
|
||||
unsigned int i;
|
||||
|
||||
env->regs[offset % E2K_NR_COUNT] = ret;
|
||||
env->tags[offset % E2K_NR_COUNT] = 0;
|
||||
|
||||
for (i = 1; i < 8; i++) {
|
||||
int idx = (offset + i) % E2K_NR_COUNT;
|
||||
env->regs[idx] = 0;
|
||||
env->tags[idx] = E2K_TAG_NON_NUMBER64;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case E2K_EXCP_ILLOPC:
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPC;
|
||||
info._sifields._sigfault._addr = env->ip;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case E2K_EXCP_ILLOPN:
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPN;
|
||||
info._sifields._sigfault._addr = env->ip;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case E2K_EXCP_MAPERR:
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
info._sifields._sigfault._addr = env->ip;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
/* QEMU common interrupts */
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
{
|
||||
info.si_signo = TARGET_SIGTRAP;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_TRAP_BRKPT;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
}
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
break;
|
||||
case EXCP_HLT:
|
||||
case EXCP_HALTED:
|
||||
case EXCP_YIELD:
|
||||
fprintf(stderr, "Unhandled QEMU trap: 0x%x\n", trapnr);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
|
||||
cpu_dump_state(cs, stderr, 0);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
process_pending_signals (env);
|
||||
}
|
||||
}
|
||||
|
||||
void target_cpu_copy_regs(CPUE2KState *env, struct target_pt_regs *regs)
|
||||
{
|
||||
env->ip = regs->ip;
|
||||
env->pcsp = regs->pcsp;
|
||||
env->psp = regs->psp;
|
||||
env->usd.lo = regs->usd_lo;
|
||||
env->usd.hi = regs->usd_hi;
|
||||
env->sbr = regs->sbr;
|
||||
|
||||
e2k_break_save_state(env);
|
||||
}
|
112
linux-user/e2k/signal.c
Normal file
112
linux-user/e2k/signal.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Emulation of Linux signals
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
* Copyright (c) 2020 Alibek Omarov
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu.h"
|
||||
#include "signal-common.h"
|
||||
#include "linux-user/trace.h"
|
||||
|
||||
#define MAX_TC_SIZE 10
|
||||
|
||||
#define TIR_NUM 19
|
||||
#define DAM_ENTRIES_NUM 32
|
||||
#define SBBP_ENTRIES_NUM 32
|
||||
|
||||
/* from user.h !!! */
|
||||
#define MLT_NUM (16 * 3) /* common for E3M and E3S */
|
||||
|
||||
struct target_sigcontext {
|
||||
abi_ulong cr0_lo;
|
||||
abi_ulong cr0_hi;
|
||||
abi_ulong cr1_lo;
|
||||
abi_ulong cr1_hi;
|
||||
abi_ulong sbr; /* 21 Stack base register: top of */
|
||||
/* local data (user) stack */
|
||||
abi_ulong usd_lo; /* 22 Local data (user) stack */
|
||||
abi_ulong usd_hi; /* 23 descriptor: base & size */
|
||||
abi_ulong psp_lo; /* 24 Procedure stack pointer: */
|
||||
abi_ulong psp_hi; /* 25 base & index & size */
|
||||
abi_ulong pcsp_lo; /* 26 Procedure chain stack */
|
||||
abi_ulong pcsp_hi; /* 27 pointer: base & index & size */
|
||||
/*
|
||||
* additional part (for binary compiler)
|
||||
*/
|
||||
uint8_t bincomp_padding[sizeof(abi_ulong)*184 + 10];
|
||||
|
||||
#if 0
|
||||
abi_ulong rpr_hi;
|
||||
abi_ulong rpr_lo;
|
||||
|
||||
abi_ulong nr_TIRs;
|
||||
abi_ulong tir_lo[TIR_NUM];
|
||||
abi_ulong tir_hi[TIR_NUM];
|
||||
abi_ulong trap_cell_addr[MAX_TC_SIZE];
|
||||
abi_ulong trap_cell_val[MAX_TC_SIZE];
|
||||
uint8_t trap_cell_tag[MAX_TC_SIZE];
|
||||
abi_ulong trap_cell_info[MAX_TC_SIZE];
|
||||
|
||||
abi_ulong dam[DAM_ENTRIES_NUM];
|
||||
|
||||
abi_ulong sbbp[SBBP_ENTRIES_NUM];
|
||||
|
||||
abi_ulong mlt[MLT_NUM];
|
||||
|
||||
abi_ulong upsr;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
|
||||
|
||||
void setup_frame(int sig, struct target_sigaction *ka,
|
||||
target_sigset_t *set, CPUE2KState *env)
|
||||
{
|
||||
// TODO: setup_frame
|
||||
qemu_log_mask(LOG_UNIMP, "setup_frame: not implemented\n");
|
||||
}
|
||||
|
||||
void setup_rt_frame(int sig, struct target_sigaction *ka,
|
||||
target_siginfo_t *info,
|
||||
target_sigset_t *set, CPUE2KState *env)
|
||||
{
|
||||
// TODO: setup_rt_frame
|
||||
qemu_log_mask(LOG_UNIMP, "setup_rt_frame: not implemented\n");
|
||||
}
|
||||
|
||||
long do_sigreturn(CPUE2KState *env)
|
||||
{
|
||||
// TODO: do_sigreturn
|
||||
qemu_log_mask(LOG_UNIMP, "do_sigreturn: not implemented\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
long do_rt_sigreturn(CPUE2KState *env)
|
||||
{
|
||||
trace_user_do_rt_sigreturn(env, 0);
|
||||
// TODO: do_rt_sigreturn
|
||||
qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n");
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
|
||||
abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
|
||||
abi_ulong unew_ctx, abi_long ctx_size)
|
||||
{
|
||||
// TODO: do_swapcontext
|
||||
qemu_log_mask(LOG_UNIMP, "do_swapcontext: not implemented\n");
|
||||
return 0;
|
||||
}
|
1
linux-user/e2k/sockbits.h
Normal file
1
linux-user/e2k/sockbits.h
Normal file
@ -0,0 +1 @@
|
||||
#include "../generic/sockbits.h"
|
405
linux-user/e2k/syscall_nr.h
Normal file
405
linux-user/e2k/syscall_nr.h
Normal file
@ -0,0 +1,405 @@
|
||||
/*
|
||||
* This file contains the system call numbers.
|
||||
*/
|
||||
#ifndef E2K_SYSCALL_NR_H
|
||||
#define E2K_SYSCALL_NR_H
|
||||
|
||||
#define TARGET_NR_restart_syscall 0
|
||||
#define TARGET_NR_exit 1
|
||||
#define TARGET_NR_fork 2
|
||||
#define TARGET_NR_read 3
|
||||
#define TARGET_NR_write 4
|
||||
#define TARGET_NR_open 5
|
||||
#define TARGET_NR_close 6
|
||||
#define TARGET_NR_waitpid 7
|
||||
#define TARGET_NR_creat 8
|
||||
#define TARGET_NR_link 9
|
||||
#define TARGET_NR_unlink 10
|
||||
#define TARGET_NR_execve 11
|
||||
#define TARGET_NR_chdir 12
|
||||
#define TARGET_NR_time 13
|
||||
#define TARGET_NR_mknod 14
|
||||
#define TARGET_NR_chmod 15
|
||||
#define TARGET_NR_lchown 16
|
||||
#define TARGET_NR_break 17
|
||||
#define TARGET_NR_oldstat 18
|
||||
#define TARGET_NR_lseek 19
|
||||
#define TARGET_NR_getpid 20
|
||||
#define TARGET_NR_mount 21
|
||||
#define TARGET_NR_umount 22
|
||||
#define TARGET_NR_setuid 23
|
||||
#define TARGET_NR_getuid 24
|
||||
#define TARGET_NR_stime 25
|
||||
#define TARGET_NR_ptrace 26
|
||||
#define TARGET_NR_alarm 27
|
||||
#define TARGET_NR_oldfstat 28
|
||||
#define TARGET_NR_pause 29
|
||||
#define TARGET_NR_utime 30
|
||||
#define TARGET_NR_stty 31
|
||||
#define TARGET_NR_gtty 32
|
||||
#define TARGET_NR_access 33
|
||||
#define TARGET_NR_nice 34
|
||||
#define TARGET_NR_ftime 35
|
||||
#define TARGET_NR_sync 36
|
||||
#define TARGET_NR_kill 37
|
||||
#define TARGET_NR_rename 38
|
||||
#define TARGET_NR_mkdir 39
|
||||
#define TARGET_NR_rmdir 40
|
||||
#define TARGET_NR_dup 41
|
||||
#define TARGET_NR_pipe 42
|
||||
#define TARGET_NR_times 43
|
||||
#define TARGET_NR_prof 44
|
||||
#define TARGET_NR_brk 45
|
||||
#define TARGET_NR_setgid 46
|
||||
#define TARGET_NR_getgid 47
|
||||
#define TARGET_NR_signal 48
|
||||
#define TARGET_NR_geteuid 49
|
||||
#define TARGET_NR_getegid 50
|
||||
#define TARGET_NR_acct 51
|
||||
#define TARGET_NR_umount2 52
|
||||
#define TARGET_NR_lock 53
|
||||
#define TARGET_NR_ioctl 54
|
||||
#define TARGET_NR_fcntl 55
|
||||
#define TARGET_NR_mpx 56
|
||||
#define TARGET_NR_setpgid 57
|
||||
#define TARGET_NR_ulimit 58
|
||||
#define TARGET_NR_oldolduname 59
|
||||
#define TARGET_NR_umask 60
|
||||
#define TARGET_NR_chroot 61
|
||||
#define TARGET_NR_ustat 62
|
||||
#define TARGET_NR_dup2 63
|
||||
#define TARGET_NR_getppid 64
|
||||
#define TARGET_NR_getpgrp 65
|
||||
#define TARGET_NR_setsid 66
|
||||
#define TARGET_NR_sigaction 67
|
||||
#define TARGET_NR_sgetmask 68
|
||||
#define TARGET_NR_ssetmask 69
|
||||
#define TARGET_NR_setreuid 70
|
||||
#define TARGET_NR_setregid 71
|
||||
#define TARGET_NR_sigsuspend 72
|
||||
#define TARGET_NR_sigpending 73
|
||||
#define TARGET_NR_sethostname 74
|
||||
#define TARGET_NR_setrlimit 75
|
||||
#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
|
||||
#define TARGET_NR_getrusage 77
|
||||
#define TARGET_NR_gettimeofday 78
|
||||
#define TARGET_NR_settimeofday 79
|
||||
#define TARGET_NR_getgroups 80
|
||||
#define TARGET_NR_setgroups 81
|
||||
#define TARGET_NR_select 82
|
||||
#define TARGET_NR_symlink 83
|
||||
#define TARGET_NR_oldlstat 84
|
||||
#define TARGET_NR_readlink 85
|
||||
#define TARGET_NR_uselib 86
|
||||
#define TARGET_NR_swapon 87
|
||||
#define TARGET_NR_reboot 88
|
||||
#define TARGET_NR_readdir 89
|
||||
#define TARGET_NR_mmap 90
|
||||
#define TARGET_NR_munmap 91
|
||||
#define TARGET_NR_truncate 92
|
||||
#define TARGET_NR_ftruncate 93
|
||||
#define TARGET_NR_fchmod 94
|
||||
#define TARGET_NR_fchown 95
|
||||
#define TARGET_NR_getpriority 96
|
||||
#define TARGET_NR_setpriority 97
|
||||
#define TARGET_NR_profil 98
|
||||
#define TARGET_NR_statfs 99
|
||||
#define TARGET_NR_fstatfs 100
|
||||
#define TARGET_NR_ioperm 101
|
||||
#define TARGET_NR_socketcall 102
|
||||
#define TARGET_NR_syslog 103
|
||||
#define TARGET_NR_setitimer 104
|
||||
#define TARGET_NR_getitimer 105
|
||||
#define TARGET_NR_stat 106
|
||||
#define TARGET_NR_lstat 107
|
||||
#define TARGET_NR_fstat 108
|
||||
#define TARGET_NR_olduname 109
|
||||
#define TARGET_NR_iopl 110
|
||||
#define TARGET_NR_vhangup 111
|
||||
#define TARGET_NR_idle 112
|
||||
#define TARGET_NR_vm86old 113
|
||||
#define TARGET_NR_wait4 114
|
||||
#define TARGET_NR_swapoff 115
|
||||
#define TARGET_NR_sysinfo 116
|
||||
#define TARGET_NR_ipc 117
|
||||
#define TARGET_NR_fsync 118
|
||||
#define TARGET_NR_sigreturn 119
|
||||
#define TARGET_NR_clone 120
|
||||
#define TARGET_NR_setdomainname 121
|
||||
#define TARGET_NR_uname 122
|
||||
#define TARGET_NR_modify_ldt 123
|
||||
#define TARGET_NR_adjtimex 124
|
||||
#define TARGET_NR_mprotect 125
|
||||
#define TARGET_NR_sigprocmask 126
|
||||
#define TARGET_NR_create_module 127
|
||||
#define TARGET_NR_init_module 128
|
||||
#define TARGET_NR_delete_module 129
|
||||
#define TARGET_NR_get_kernel_syms 130
|
||||
#define TARGET_NR_quotactl 131
|
||||
#define TARGET_NR_getpgid 132
|
||||
#define TARGET_NR_fchdir 133
|
||||
#define TARGET_NR_bdflush 134
|
||||
#define TARGET_NR_sysfs 135
|
||||
#define TARGET_NR_personality 136
|
||||
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
|
||||
#define TARGET_NR_setfsuid 138
|
||||
#define TARGET_NR_setfsgid 139
|
||||
#define TARGET_NR__llseek 140
|
||||
#define TARGET_NR_getdents 141
|
||||
#define TARGET_NR__newselect 142
|
||||
#define TARGET_NR_flock 143
|
||||
#define TARGET_NR_msync 144
|
||||
#define TARGET_NR_readv 145
|
||||
#define TARGET_NR_writev 146
|
||||
#define TARGET_NR_getsid 147
|
||||
#define TARGET_NR_fdatasync 148
|
||||
#define TARGET_NR__sysctl 149
|
||||
#define TARGET_NR_mlock 150
|
||||
#define TARGET_NR_munlock 151
|
||||
#define TARGET_NR_mlockall 152
|
||||
#define TARGET_NR_munlockall 153
|
||||
#define TARGET_NR_sched_setparam 154
|
||||
#define TARGET_NR_sched_getparam 155
|
||||
#define TARGET_NR_sched_setscheduler 156
|
||||
#define TARGET_NR_sched_getscheduler 157
|
||||
#define TARGET_NR_sched_yield 158
|
||||
#define TARGET_NR_sched_get_priority_max 159
|
||||
#define TARGET_NR_sched_get_priority_min 160
|
||||
#define TARGET_NR_sched_rr_get_interval 161
|
||||
#define TARGET_NR_nanosleep 162
|
||||
#define TARGET_NR_mremap 163
|
||||
#define TARGET_NR_setresuid 164
|
||||
#define TARGET_NR_getresuid 165
|
||||
#define TARGET_NR_vm86 166
|
||||
#define TARGET_NR_query_module 167
|
||||
#define TARGET_NR_poll 168
|
||||
#define TARGET_NR_nfsservctl 169
|
||||
#define TARGET_NR_setresgid 170
|
||||
#define TARGET_NR_getresgid 171
|
||||
#define TARGET_NR_prctl 172
|
||||
#define TARGET_NR_rt_sigreturn 173
|
||||
#define TARGET_NR_rt_sigaction 174
|
||||
#define TARGET_NR_rt_sigprocmask 175
|
||||
#define TARGET_NR_rt_sigpending 176
|
||||
#define TARGET_NR_rt_sigtimedwait 177
|
||||
#define TARGET_NR_rt_sigqueueinfo 178
|
||||
#define TARGET_NR_rt_sigsuspend 179
|
||||
#define TARGET_NR_pread 180
|
||||
#define TARGET_NR_pwrite 181
|
||||
#define TARGET_NR_chown 182
|
||||
#define TARGET_NR_getcwd 183
|
||||
#define TARGET_NR_capget 184
|
||||
#define TARGET_NR_capset 185
|
||||
#define TARGET_NR_sigaltstack 186
|
||||
#define TARGET_NR_sendfile 187
|
||||
#define TARGET_NR_getpmsg 188 /* some people actually want streams */
|
||||
#define TARGET_NR_putpmsg 189 /* some people actually want streams */
|
||||
#define TARGET_NR_vfork 190
|
||||
#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
|
||||
#define TARGET_NR_mmap2 192
|
||||
#define TARGET_NR_truncate64 193
|
||||
#define TARGET_NR_ftruncate64 194
|
||||
#define TARGET_NR_stat64 195
|
||||
#define TARGET_NR_lstat64 196
|
||||
#define TARGET_NR_fstat64 197
|
||||
#define TARGET_NR_lchown32 198
|
||||
#define TARGET_NR_getuid32 199
|
||||
#define TARGET_NR_getgid32 200
|
||||
#define TARGET_NR_geteuid32 201
|
||||
#define TARGET_NR_getegid32 202
|
||||
#define TARGET_NR_setreuid32 203
|
||||
#define TARGET_NR_setregid32 204
|
||||
#define TARGET_NR_getgroups32 205
|
||||
#define TARGET_NR_setgroups32 206
|
||||
#define TARGET_NR_fchown32 207
|
||||
#define TARGET_NR_setresuid32 208
|
||||
#define TARGET_NR_getresuid32 209
|
||||
#define TARGET_NR_setresgid32 210
|
||||
#define TARGET_NR_getresgid32 211
|
||||
#define TARGET_NR_chown32 212
|
||||
#define TARGET_NR_setuid32 213
|
||||
#define TARGET_NR_setgid32 214
|
||||
#define TARGET_NR_setfsuid32 215
|
||||
#define TARGET_NR_setfsgid32 216
|
||||
#define TARGET_NR_pivot_root 217
|
||||
#define TARGET_NR_mincore 218
|
||||
#define TARGET_NR_madvise 219
|
||||
#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
|
||||
#define TARGET_NR_getdents64 220
|
||||
#define TARGET_NR_fcntl64 221
|
||||
#define TARGET_NR_core 222 /* for analys kernel core */
|
||||
#define TARGET_NR_macctl 223 /* MCST trust linux */
|
||||
#define TARGET_NR_newfstatat 224
|
||||
#define TARGET_NR_emergency 225
|
||||
#define TARGET_NR_e2k_sigsetjmp 226 /* setjmp e2k specific */
|
||||
#define TARGET_NR_e2k_longjmp 227 /* longjmp e2k specific */
|
||||
#define TARGET_NR_e2k_syswork 228 /* e2k_syswork */
|
||||
#define TARGET_NR_clone2 229
|
||||
#define TARGET_NR_e2k_longjmp2 230 /* Second Edition */
|
||||
#define TARGET_NR_soft_debug 231
|
||||
#define TARGET_NR_setxattr 232
|
||||
#define TARGET_NR_lsetxattr 233
|
||||
#define TARGET_NR_fsetxattr 234
|
||||
#define TARGET_NR_getxattr 235
|
||||
#define TARGET_NR_lgetxattr 236
|
||||
#define TARGET_NR_fgetxattr 237
|
||||
#define TARGET_NR_listxattr 238
|
||||
#define TARGET_NR_llistxattr 239
|
||||
#define TARGET_NR_flistxattr 240
|
||||
#define TARGET_NR_removexattr 241
|
||||
#define TARGET_NR_lremovexattr 242
|
||||
#define TARGET_NR_fremovexattr 243
|
||||
#define TARGET_NR_gettid 244
|
||||
#define TARGET_NR_readahead 245
|
||||
#define TARGET_NR_tkill 246
|
||||
#define TARGET_NR_sendfile64 247
|
||||
#define TARGET_NR_futex 248
|
||||
#define TARGET_NR_sched_setaffinity 249
|
||||
#define TARGET_NR_sched_getaffinity 250
|
||||
#define TARGET_NR_pipe2 251
|
||||
#define TARGET_NR_set_backtrace 252
|
||||
#define TARGET_NR_get_backtrace 253
|
||||
#define TARGET_NR_access_hw_stacks 254
|
||||
#define TARGET_NR_el_posix 255
|
||||
/*
|
||||
* reserved for update of kernel source codes
|
||||
*/
|
||||
#define TARGET_NR_reserved6 256
|
||||
#define TARGET_NR_reserved7 257
|
||||
#define TARGET_NR_reserved8 258
|
||||
|
||||
#define TARGET_NR_set_tid_address 259
|
||||
#define TARGET_NR_el_binary 260
|
||||
#define TARGET_NR_timer_create 261
|
||||
#define TARGET_NR_timer_settime 262
|
||||
#define TARGET_NR_timer_gettime 263
|
||||
#define TARGET_NR_timer_getoverrun 264
|
||||
#define TARGET_NR_timer_delete 265
|
||||
#define TARGET_NR_clock_settime 266
|
||||
#define TARGET_NR_clock_gettime 267
|
||||
#define TARGET_NR_clock_getres 268
|
||||
#define TARGET_NR_clock_nanosleep 269
|
||||
/*
|
||||
* reserved for update of kernel source codes
|
||||
*/
|
||||
#define TARGET_NR_reserved9 270
|
||||
#define TARGET_NR_reserved10 271
|
||||
#define TARGET_NR_reserved11 272
|
||||
#define TARGET_NR_reserved12 273
|
||||
#define TARGET_NR_reserved13 274
|
||||
#define TARGET_NR_reserved14 275
|
||||
#define TARGET_NR_reserved15 276
|
||||
#define TARGET_NR_reserved16 277
|
||||
#define TARGET_NR_reserved17 278
|
||||
#define TARGET_NR_reserved18 279
|
||||
#define TARGET_NR_reserved19 280
|
||||
#define TARGET_NR_reserved20 281
|
||||
#define TARGET_NR_reserved21 282
|
||||
#define TARGET_NR_reserved22 283
|
||||
#define TARGET_NR_reserved23 284
|
||||
#define TARGET_NR_reserved24 285
|
||||
#define TARGET_NR_reserved25 286
|
||||
|
||||
#define TARGET_NR_sched_setattr 287
|
||||
#define TARGET_NR_sched_getattr 288
|
||||
|
||||
#define TARGET_NR_ioprio_set 289
|
||||
#define TARGET_NR_ioprio_get 290
|
||||
#define TARGET_NR_inotify_init 291
|
||||
#define TARGET_NR_inotify_add_watch 292
|
||||
#define TARGET_NR_inotify_rm_watch 293
|
||||
|
||||
#define TARGET_NR_io_setup 294
|
||||
#define TARGET_NR_io_destroy 295
|
||||
#define TARGET_NR_io_getevents 296
|
||||
#define TARGET_NR_io_submit 297
|
||||
#define TARGET_NR_io_cancel 298
|
||||
#define TARGET_NR_fadvise64 299
|
||||
|
||||
#define TARGET_NR_exit_group 300
|
||||
#define TARGET_NR_lookup_dcookie 301
|
||||
#define TARGET_NR_epoll_create 302
|
||||
#define TARGET_NR_epoll_ctl 303
|
||||
#define TARGET_NR_epoll_wait 304
|
||||
#define TARGET_NR_remap_file_pages 305
|
||||
#define TARGET_NR_statfs64 306
|
||||
#define TARGET_NR_fstatfs64 307
|
||||
#define TARGET_NR_tgkill 308
|
||||
#define TARGET_NR_utimes 309
|
||||
#define TARGET_NR_fadvise64_64 310
|
||||
#define TARGET_NR_vserver 311
|
||||
#define TARGET_NR_mbind 312
|
||||
#define TARGET_NR_get_mempolicy 313
|
||||
#define TARGET_NR_set_mempolicy 314
|
||||
#define TARGET_NR_mq_open 315
|
||||
#define TARGET_NR_mq_unlink (TARGET_NR_mq_open+1)
|
||||
#define TARGET_NR_mq_timedsend (TARGET_NR_mq_open+2)
|
||||
#define TARGET_NR_mq_timedreceive (TARGET_NR_mq_open+3)
|
||||
#define TARGET_NR_mq_notify (TARGET_NR_mq_open+4)
|
||||
#define TARGET_NR_mq_getsetattr (TARGET_NR_mq_open+5)
|
||||
#define TARGET_NR_kexec_load 321
|
||||
#define TARGET_NR_waitid 322
|
||||
#define TARGET_NR_add_key 323
|
||||
#define TARGET_NR_request_key 324
|
||||
#define TARGET_NR_keyctl 325
|
||||
#define TARGET_NR_mcst_rt 326
|
||||
#define TARGET_NR_getcpu 327
|
||||
#define TARGET_NR_move_pages 328
|
||||
#define TARGET_NR_splice 329
|
||||
#define TARGET_NR_vmsplice 330
|
||||
#define TARGET_NR_tee 331
|
||||
#define TARGET_NR_migrate_pages 332
|
||||
#define TARGET_NR_utimensat 333
|
||||
#define TARGET_NR_rt_tgsigqueueinfo 334
|
||||
#define TARGET_NR_openat 335
|
||||
#define TARGET_NR_mkdirat 336
|
||||
#define TARGET_NR_mknodat 337
|
||||
#define TARGET_NR_fchownat 338
|
||||
#define TARGET_NR_unlinkat 339
|
||||
#define TARGET_NR_renameat 340
|
||||
#define TARGET_NR_linkat 341
|
||||
#define TARGET_NR_symlinkat 342
|
||||
#define TARGET_NR_readlinkat 343
|
||||
#define TARGET_NR_fchmodat 344
|
||||
#define TARGET_NR_faccessat 345
|
||||
#define TARGET_NR_epoll_pwait 346
|
||||
#define TARGET_NR_signalfd4 347
|
||||
#define TARGET_NR_eventfd2 348
|
||||
#define TARGET_NR_recvmmsg 349
|
||||
#define TARGET_NR_cnt_point 350
|
||||
#define TARGET_NR_timerfd_create 351
|
||||
#define TARGET_NR_timerfd_settime 352
|
||||
#define TARGET_NR_timerfd_gettime 353
|
||||
#define TARGET_NR_preadv 354
|
||||
#define TARGET_NR_pwritev 355
|
||||
#define TARGET_NR_fallocate 356
|
||||
#define TARGET_NR_sync_file_range 357
|
||||
#define TARGET_NR_dup3 358
|
||||
#define TARGET_NR_inotify_init1 359
|
||||
#define TARGET_NR_epoll_create1 360
|
||||
#define TARGET_NR_fstatat64 361
|
||||
#define TARGET_NR_futimesat 362
|
||||
#define TARGET_NR_perf_event_open 363
|
||||
#define TARGET_NR_unshare 364
|
||||
#define TARGET_NR_get_robust_list 365
|
||||
#define TARGET_NR_set_robust_list 366
|
||||
#define TARGET_NR_pselect6 367
|
||||
#define TARGET_NR_ppoll 368
|
||||
#define TARGET_NR_setcontext 369
|
||||
#define TARGET_NR_makecontext 370
|
||||
#define TARGET_NR_swapcontext 371
|
||||
#define TARGET_NR_freecontext 372
|
||||
#define TARGET_NR_fanotify_init 373
|
||||
#define TARGET_NR_fanotify_mark 374
|
||||
#define TARGET_NR_prlimit64 375
|
||||
#define TARGET_NR_clock_adjtime 376
|
||||
#define TARGET_NR_syncfs 377
|
||||
#define TARGET_NR_sendmmsg 378
|
||||
#define TARGET_NR_setns 379
|
||||
#define TARGET_NR_process_vm_readv 380
|
||||
#define TARGET_NR_process_vm_writev 381
|
||||
#define TARGET_NR_kcmp 382
|
||||
#define TARGET_NR_finit_module 383
|
||||
#define TARGET_NR_syscalls 384
|
||||
|
||||
#endif /* E2K_SYSCALL_NR_H */
|
42
linux-user/e2k/target_cpu.h
Normal file
42
linux-user/e2k/target_cpu.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef E2K_TARGET_CPU_H
|
||||
#define E2K_TARGET_CPU_H
|
||||
|
||||
#include "qemu/log.h"
|
||||
|
||||
static inline void cpu_clone_regs_child(CPUE2KState *env, target_ulong newsp,
|
||||
unsigned flags)
|
||||
{
|
||||
if (newsp) {
|
||||
// FIXME: what size must be?
|
||||
env->usd.size = 0x20000;
|
||||
env->usd.base = newsp;
|
||||
env->usd.read = 1;
|
||||
env->usd.write = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cpu_clone_regs_parent(CPUE2KState *env, unsigned flags)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "cpu_clone_regs_parent: unimplemented\n");
|
||||
// TODO: cpu_clone_regs_parent
|
||||
}
|
||||
|
||||
static inline void cpu_set_tls(CPUE2KState *env, target_ulong newtls)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "cpu_set_tls: unimplemented\n");
|
||||
// TODO: cpu_set_tls
|
||||
}
|
||||
|
||||
static inline target_ulong cpu_get_tls(CPUE2KState *env)
|
||||
{
|
||||
// TODO: cpu_get_tls
|
||||
qemu_log_mask(LOG_UNIMP, "cpu_get_tls: unimplemented\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline abi_ulong get_sp_from_cpustate(CPUE2KState *env)
|
||||
{
|
||||
return env->usd.base;
|
||||
}
|
||||
|
||||
#endif /* E2K_TARGET_CPU_H */
|
7
linux-user/e2k/target_elf.h
Normal file
7
linux-user/e2k/target_elf.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef E2K_TARGET_ELF_H
|
||||
#define E2K_TARGET_ELF_H
|
||||
static inline const char *cpu_get_model(uint32_t eflags)
|
||||
{
|
||||
return "any";
|
||||
}
|
||||
#endif /* E2K_TARGET_ELF_H */
|
4
linux-user/e2k/target_fcntl.h
Normal file
4
linux-user/e2k/target_fcntl.h
Normal file
@ -0,0 +1,4 @@
|
||||
#ifndef E2K_TARGET_FCNTL_H
|
||||
#define E2K_TARGET_FCNTL_H
|
||||
#include "../generic/fcntl.h"
|
||||
#endif
|
27
linux-user/e2k/target_signal.h
Normal file
27
linux-user/e2k/target_signal.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef TARGET_SIGNAL_H
|
||||
#define TARGET_SIGNAL_H
|
||||
|
||||
/*
|
||||
* sigaltstack controls
|
||||
*/
|
||||
#define TARGET_SS_ONSTACK 1
|
||||
#define TARGET_SS_DISABLE 2
|
||||
|
||||
#define TARGET_MINSIGSTKSZ 4096
|
||||
#define TARGET_SIGSTKSZ 8192
|
||||
#define TARGET_MCL_CURRENT 1
|
||||
#define TARGET_MCL_FUTURE 2
|
||||
// TODO: check
|
||||
#define TARGET_MCL_ONFAULT 4
|
||||
|
||||
#define TARGET_ARCH_HAS_SETUP_FRAME
|
||||
|
||||
typedef struct target_sigaltstack {
|
||||
abi_ulong ss_sp;
|
||||
abi_int ss_flags;
|
||||
abi_ulong ss_size;
|
||||
} target_stack_t;
|
||||
|
||||
#include "../generic/signal.h"
|
||||
|
||||
#endif /* TARGET_SIGNAL_H */
|
28
linux-user/e2k/target_structs.h
Normal file
28
linux-user/e2k/target_structs.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef E2K_TARGET_STRUCTS_H
|
||||
#define E2K_TARGET_STRUCTS_H
|
||||
|
||||
struct target_ipc_perm {
|
||||
abi_int __key;
|
||||
abi_uint uid;
|
||||
abi_uint gid;
|
||||
abi_uint cuid;
|
||||
abi_uint cgid;
|
||||
abi_uint mode;
|
||||
abi_ushort __seq;
|
||||
};
|
||||
|
||||
struct target_shmid_ds {
|
||||
struct target_ipc_perm shm_perm;
|
||||
abi_int shm_segsz;
|
||||
abi_long shm_atime;
|
||||
abi_long shm_dtime;
|
||||
abi_long shm_ctime;
|
||||
abi_int shm_cpid;
|
||||
abi_int shm_lpid;
|
||||
abi_ushort shm_nattch;
|
||||
abi_ushort shm_unused;
|
||||
void *shm_unused2;
|
||||
void *shm_unused3;
|
||||
};
|
||||
|
||||
#endif
|
66
linux-user/e2k/target_syscall.h
Normal file
66
linux-user/e2k/target_syscall.h
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef E2K_TARGET_SYSCALL_H
|
||||
#define E2K_TARGET_SYSCALL_H
|
||||
|
||||
#define UNAME_MACHINE "e2k"
|
||||
#define UNAME_MINIMUM_RELEASE "2.6.32"
|
||||
|
||||
#define E2K_MAXNR 128 /* The total number of */
|
||||
/* quad-NRs */
|
||||
#define E2K_MAXGR 16 /* The total number of global */
|
||||
/* quad-NRs */
|
||||
#define E2K_MAXSR (E2K_MAXNR - E2K_MAXGR) /* The total number of stack */
|
||||
/* quad-NRs */
|
||||
#define E2K_MAXNR_d (E2K_MAXNR * 2) /* The total number of */
|
||||
/* double-NRs */
|
||||
#define E2K_MAXGR_d (E2K_MAXGR * 2) /* The total number of global */
|
||||
/* double-NRs */
|
||||
#define E2K_MAXSR_d (E2K_MAXSR * 2) /* The total number of stack */
|
||||
/* double-NRs */
|
||||
|
||||
typedef uint64_t e2k_greg_t; // double word
|
||||
|
||||
struct target_pt_regs {
|
||||
/* special registers */
|
||||
uint64_t wd; // Current window descriptor (WD)
|
||||
|
||||
uint64_t sbr; // User Stack Base Register (USBR/SBR)
|
||||
// SBR - contains the base (top) virtual address of the current User Stack area.
|
||||
|
||||
// uint64_t tr; // current type register
|
||||
|
||||
E2KPcsState pcsp;
|
||||
E2KPsState psp;
|
||||
|
||||
uint32_t psr; // Processor State Register (PSR)
|
||||
uint32_t upsr; // User processor status register (UPSR)
|
||||
uint64_t ip; // instruction pointer
|
||||
uint64_t nip; // next instruction pointer
|
||||
|
||||
uint64_t ctpr1; // Control Transfer Preparation Register (CTPR)
|
||||
uint64_t ctpr2;
|
||||
uint64_t ctpr3;
|
||||
|
||||
uint32_t pfpfr; // Packed Floating Point Flag Register (PFPFR)
|
||||
uint32_t fpcr; // Floating point control register (FPCR)
|
||||
uint32_t fpsr; // Floating point state register (FPSR)
|
||||
|
||||
// borrowed from Embox OS
|
||||
uint64_t lsr; // Loop status register (LSR)
|
||||
uint64_t ilcr; // Loop counter register (ILCR)
|
||||
|
||||
uint64_t dr0;
|
||||
|
||||
uint64_t cr0_hi;
|
||||
uint64_t cr1_lo;
|
||||
uint64_t cr1_hi;
|
||||
uint64_t pcsp_hi;
|
||||
uint64_t pcsp_lo;
|
||||
uint64_t usd_lo; // User data
|
||||
uint64_t usd_hi;
|
||||
|
||||
uint64_t gbase[32];
|
||||
uint16_t gext[32];
|
||||
};
|
||||
|
||||
|
||||
#endif /* E2K_TARGET_SYSCALL_H */
|
6
linux-user/e2k/termbits.h
Normal file
6
linux-user/e2k/termbits.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef _E2K_TERMBITS_H_
|
||||
#define _E2K_TERMBITS_H_
|
||||
|
||||
#include "../generic/termbits.h"
|
||||
|
||||
#endif /* _E2K_TERMBITS_H_ */
|
@ -2,6 +2,8 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <linux/mman.h>
|
||||
|
||||
#include <sys/resource.h>
|
||||
#include <sys/shm.h>
|
||||
|
||||
@ -1485,6 +1487,73 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
|
||||
|
||||
#endif /* TARGET_XTENSA */
|
||||
|
||||
#ifdef TARGET_E2K
|
||||
|
||||
#define elf_check_arch(x) ((x) == EM_MCST_ELBRUS || (x) == EM_E2K_OLD)
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
#define ELF_CLASS ELFCLASS64
|
||||
#define ELF_ARCH EM_MCST_ELBRUS
|
||||
#define ELF_EXEC_PAGESIZE 4096
|
||||
#define ELF_NREG 256
|
||||
typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
|
||||
#define USE_ELF_CORE_DUMP
|
||||
|
||||
static inline abi_ulong e2k_mmap(abi_ulong size)
|
||||
{
|
||||
abi_ulong addr;
|
||||
abi_ulong guard = TARGET_PAGE_SIZE;
|
||||
|
||||
if (size < TARGET_PAGE_SIZE) {
|
||||
size = TARGET_PAGE_SIZE;
|
||||
}
|
||||
if (guard < qemu_real_host_page_size) {
|
||||
guard = qemu_real_host_page_size;
|
||||
}
|
||||
|
||||
addr = target_mmap(0, size + guard, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (addr == -1) {
|
||||
perror("mmap e2k stack");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
target_mprotect(addr + size, guard, PROT_NONE);
|
||||
return addr;
|
||||
}
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
abi_ulong start_stack = infop->start_stack & ~0xf;
|
||||
|
||||
regs->ip = infop->entry;
|
||||
|
||||
// FIXME: set real start stack address
|
||||
regs->sbr = infop->arg_strings & ~0xf;
|
||||
regs->usd_lo = (0x1800UL << 48) | start_stack;
|
||||
regs->usd_hi = (regs->sbr - start_stack) << 32;
|
||||
|
||||
regs->pcsp.is_readable = true;
|
||||
regs->pcsp.is_writable = true;
|
||||
regs->pcsp.index = 0;
|
||||
regs->pcsp.size = TARGET_PAGE_SIZE;
|
||||
regs->pcsp.base = e2k_mmap(regs->pcsp.size);
|
||||
|
||||
regs->psp.is_readable = true;
|
||||
regs->psp.is_writable = true;
|
||||
regs->psp.index = 0;
|
||||
regs->psp.size = TARGET_PAGE_SIZE * 8;
|
||||
regs->psp.base = e2k_mmap(regs->psp.size);
|
||||
regs->psp.base_tag = e2k_mmap(regs->psp.size / 8);
|
||||
}
|
||||
|
||||
static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUE2KState *env)
|
||||
{
|
||||
/* TODO */
|
||||
qemu_log_mask(LOG_UNIMP, "elf_core_copy_regs: not implemented\n");
|
||||
}
|
||||
|
||||
#endif /* TARGET_E2K */
|
||||
|
||||
#ifndef ELF_PLATFORM
|
||||
#define ELF_PLATFORM (NULL)
|
||||
#endif
|
||||
@ -2379,7 +2448,7 @@ void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
|
||||
abi_ulong guest_hiaddr)
|
||||
{
|
||||
/* In order to use host shmat, we must be able to honor SHMLBA. */
|
||||
uintptr_t align = MAX(SHMLBA, qemu_host_page_size);
|
||||
uintptr_t align = MAX(/* SHMLBA */ getpagesize(), qemu_host_page_size);
|
||||
|
||||
if (have_guest_base) {
|
||||
pgb_have_guest_base(image_name, guest_loaddr, guest_hiaddr, align);
|
||||
|
@ -35,6 +35,8 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include <linux/mman.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "flat.h"
|
||||
#include "target_flat.h"
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include "qemu.h"
|
||||
#include "cpu_loop-common.h"
|
||||
|
||||
#include <linux/mman.h>
|
||||
|
||||
/***********************************************************/
|
||||
/* CPUX86 core interface */
|
||||
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "exec/log.h"
|
||||
#include "qemu.h"
|
||||
|
||||
#include <linux/mman.h>
|
||||
|
||||
static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static __thread int mmap_lock_count;
|
||||
|
||||
|
@ -41,7 +41,7 @@ struct target_ucontext {
|
||||
struct target_ucontext *uc_link;
|
||||
target_stack_t uc_stack;
|
||||
target_sigset_t uc_sigmask;
|
||||
uint8_t __unused[1024 / 8 - sizeof(target_sigset_t)];
|
||||
uint8_t __qemu_unused[1024 / 8 - sizeof(target_sigset_t)];
|
||||
struct target_sigcontext uc_mcontext QEMU_ALIGNED(16);
|
||||
};
|
||||
|
||||
|
@ -198,6 +198,27 @@ int block_signals(void)
|
||||
return qatomic_xchg(&ts->signal_pending, 1);
|
||||
}
|
||||
|
||||
#ifdef _NSIG_WORDS
|
||||
static int sigorset(sigset_t *dest, const sigset_t *a, const sigset_t *b)
|
||||
{
|
||||
int i;
|
||||
if (!dest || !a || !b)
|
||||
return -1;
|
||||
for (i = 0; i < _NSIG_WORDS; i++)
|
||||
dest->sig[i] = a->sig[i] | b->sig[i];
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int sigorset(sigset_t *dest, const sigset_t *a, const sigset_t *b)
|
||||
{
|
||||
int i;
|
||||
if (!dest || !a || !b)
|
||||
return -1;
|
||||
*dest = *a | *b;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Wrapper for sigprocmask function
|
||||
* Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
|
||||
* are host signal set, not guest ones. Returns -TARGET_ERESTARTSYS if
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <sys/sem.h>
|
||||
#include <linux/sem.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/mount.h>
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <sys/resource.h>
|
||||
#include <sys/swap.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/mman.h>
|
||||
#include <sched.h>
|
||||
#include <sys/timex.h>
|
||||
#include <sys/socket.h>
|
||||
@ -45,7 +46,7 @@
|
||||
#include <poll.h>
|
||||
#include <sys/times.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/sem.h>
|
||||
#include <linux/sem.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <utime.h>
|
||||
#include <sys/sysinfo.h>
|
||||
@ -78,12 +79,17 @@
|
||||
#endif
|
||||
|
||||
#define termios host_termios
|
||||
#define termios2 host_termios2
|
||||
#define ktermios host_ktermios
|
||||
#define winsize host_winsize
|
||||
#define termio host_termio
|
||||
#define sgttyb host_sgttyb /* same as target */
|
||||
#define tchars host_tchars /* same as target */
|
||||
#define ltchars host_ltchars /* same as target */
|
||||
|
||||
#undef __ASM_GENERIC_TERMBITS_H
|
||||
#include <asm/termbits.h>
|
||||
|
||||
#include <linux/termios.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/cdrom.h>
|
||||
@ -268,6 +274,59 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
|
||||
#define __NR__llseek __NR_lseek
|
||||
#endif
|
||||
|
||||
_syscall0(int, vhangup)
|
||||
#ifdef __NR_msgctl
|
||||
_syscall3(int, msgctl, int, msqid, int, cmd, struct msqid_ds *, buf)
|
||||
#else
|
||||
static int
|
||||
msgctl (int msqid, int cmd, struct msqid_ds *buf)
|
||||
{
|
||||
return syscall (__NR_ipc, IPCOP_msgctl, msqid, cmd | 0x100, 0, buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __NR_semget
|
||||
_syscall3(int, semget, key_t, key, int, nsems, int, semflg)
|
||||
#else
|
||||
static int
|
||||
semget (key_t key, int nsems, int semflg)
|
||||
{
|
||||
return syscall (__NR_ipc, IPCOP_semget, key, nsems, semflg, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
_syscall2(int, setdomainname, const char *, name, size_t, len)
|
||||
#ifdef __NR_msgget
|
||||
_syscall2(int, msgget, key_t, key, int, msgflg)
|
||||
#else
|
||||
static int
|
||||
msgget (key_t key, int msgflg)
|
||||
{
|
||||
return syscall(__NR_ipc, 5, IPCOP_msgget, key, msgflg, 0, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _NSIG_WORDS
|
||||
static int sigorset(sigset_t *dest, const sigset_t *a, const sigset_t *b)
|
||||
{
|
||||
int i;
|
||||
if (!dest || !a || !b)
|
||||
return -1;
|
||||
for (i = 0; i < _NSIG_WORDS; i++)
|
||||
dest->sig[i] = a->sig[i] | b->sig[i];
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int sigorset(sigset_t *dest, const sigset_t *a, const sigset_t *b)
|
||||
{
|
||||
int i;
|
||||
if (!dest || !a || !b)
|
||||
return -1;
|
||||
*dest = *a | *b;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Newer kernel ports have llseek() instead of _llseek() */
|
||||
#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
|
||||
#define TARGET_NR__llseek TARGET_NR_llseek
|
||||
@ -812,6 +871,9 @@ safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
|
||||
defined(TARGET_NR_mq_timedreceive_time64)
|
||||
safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
|
||||
size_t, len, unsigned *, prio, const struct timespec *, timeout)
|
||||
_syscall1(int, mq_unlink, const char *, name)
|
||||
_syscall4(__kernel_mqd_t, mq_open, const char *, name, int, oflag, mode_t, mode,
|
||||
struct mq_attr *, attr)
|
||||
#endif
|
||||
/* We do ioctl like this rather than via safe_syscall3 to preserve the
|
||||
* "third argument might be integer or pointer or not present" behaviour of
|
||||
@ -1336,7 +1398,7 @@ static inline abi_long copy_from_user_timezone(struct timezone *tz,
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
|
||||
#include <mqueue.h>
|
||||
#include <linux/mqueue.h>
|
||||
|
||||
static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
|
||||
abi_ulong target_mq_attr_addr)
|
||||
@ -3871,6 +3933,8 @@ static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define semid_ds __kernel_legacy_semid_ds
|
||||
|
||||
static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
|
||||
abi_ulong target_addr)
|
||||
{
|
||||
@ -3950,6 +4014,16 @@ union target_semun {
|
||||
abi_ulong __buf;
|
||||
};
|
||||
|
||||
#ifdef __NR_semctl
|
||||
_syscall4(int, semctl, int, semid, int, semnum, int, cmd, union semun, arg4)
|
||||
#else
|
||||
static int semctl(int semid, int semnum, int cmd, union semun arg4)
|
||||
{
|
||||
return syscall(__NR_ipc, IPCOP_semctl, semid, semnum, cmd | 0x100,
|
||||
arg4.__buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
|
||||
abi_ulong target_addr)
|
||||
{
|
||||
@ -4080,7 +4154,7 @@ static inline abi_long do_semctl(int semid, int semnum, int cmd,
|
||||
case GETPID:
|
||||
case GETNCNT:
|
||||
case GETZCNT:
|
||||
ret = get_errno(semctl(semid, semnum, cmd, NULL));
|
||||
ret = get_errno(semctl(semid, semnum, cmd, (union semun) {.buf = NULL}));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4215,7 +4289,7 @@ static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
|
||||
host_md->msg_stime = tswapal(target_md->msg_stime);
|
||||
host_md->msg_rtime = tswapal(target_md->msg_rtime);
|
||||
host_md->msg_ctime = tswapal(target_md->msg_ctime);
|
||||
host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
|
||||
host_md->msg_cbytes = tswapal(target_md->__msg_cbytes);
|
||||
host_md->msg_qnum = tswapal(target_md->msg_qnum);
|
||||
host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
|
||||
host_md->msg_lspid = tswapal(target_md->msg_lspid);
|
||||
@ -4236,7 +4310,7 @@ static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
|
||||
target_md->msg_stime = tswapal(host_md->msg_stime);
|
||||
target_md->msg_rtime = tswapal(host_md->msg_rtime);
|
||||
target_md->msg_ctime = tswapal(host_md->msg_ctime);
|
||||
target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
|
||||
target_md->__msg_cbytes = tswapal(host_md->msg_cbytes);
|
||||
target_md->msg_qnum = tswapal(host_md->msg_qnum);
|
||||
target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
|
||||
target_md->msg_lspid = tswapal(host_md->msg_lspid);
|
||||
@ -4602,7 +4676,7 @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
|
||||
abi_ulong mmap_start;
|
||||
|
||||
/* In order to use the host shmat, we need to honor host SHMLBA. */
|
||||
mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(SHMLBA, shmlba));
|
||||
mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(/* SHMLBA */ getpagesize(), shmlba));
|
||||
|
||||
if (mmap_start == -1) {
|
||||
errno = ENOMEM;
|
||||
@ -5703,6 +5777,9 @@ static abi_long do_ioctl_drm_i915(const IOCTLEntry *ie, uint8_t *buf_temp,
|
||||
|
||||
#endif
|
||||
|
||||
#undef winsize
|
||||
#undef termio
|
||||
|
||||
IOCTLEntry ioctl_entries[] = {
|
||||
#define IOCTL(cmd, access, ...) \
|
||||
{ TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
|
||||
@ -8045,7 +8122,7 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags,
|
||||
/* create temporary file to map stat to */
|
||||
tmpdir = getenv("TMPDIR");
|
||||
if (!tmpdir)
|
||||
tmpdir = "/tmp";
|
||||
tmpdir = "@TERMUX_PREFIX@/tmp";
|
||||
snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
|
||||
fd = mkstemp(filename);
|
||||
if (fd < 0) {
|
||||
@ -8599,7 +8676,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
||||
unlock_user(p, arg1, 0);
|
||||
return ret;
|
||||
#endif
|
||||
#ifdef TARGET_NR_stime /* not on alpha */
|
||||
#if 0 //def TARGET_NR_stime /* not on alpha */
|
||||
case TARGET_NR_stime:
|
||||
{
|
||||
struct timespec ts;
|
||||
@ -8663,7 +8740,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
#if defined(TARGET_NR_futimesat)
|
||||
#if 0 && defined(TARGET_NR_futimesat)
|
||||
case TARGET_NR_futimesat:
|
||||
{
|
||||
struct timeval *tvp, tv[2];
|
||||
@ -12424,7 +12501,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
||||
/* Not implemented for now... */
|
||||
/* case TARGET_NR_mq_notify: */
|
||||
/* break; */
|
||||
|
||||
#if 0
|
||||
case TARGET_NR_mq_getsetattr:
|
||||
{
|
||||
struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
|
||||
@ -12442,6 +12519,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPLICE
|
||||
#ifdef TARGET_NR_tee
|
||||
|
@ -86,7 +86,7 @@
|
||||
|
||||
#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
|
||||
defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) || \
|
||||
defined(TARGET_MIPS)
|
||||
defined(TARGET_MIPS) || defined(TARGET_E2K)
|
||||
|
||||
#define TARGET_IOC_SIZEBITS 13
|
||||
#define TARGET_IOC_DIRBITS 3
|
||||
@ -1576,6 +1576,55 @@ struct target_stat64 {
|
||||
unsigned int __unused2;
|
||||
};
|
||||
|
||||
#elif defined(TARGET_E2K)
|
||||
#define TARGET_STAT_HAVE_NSEC
|
||||
struct target_stat {
|
||||
unsigned long st_dev;
|
||||
unsigned long st_ino;
|
||||
unsigned int st_mode;
|
||||
unsigned int st_nlink;
|
||||
unsigned int st_uid;
|
||||
unsigned int st_gid;
|
||||
unsigned long st_rdev;
|
||||
unsigned long __pad1;
|
||||
long st_size;
|
||||
int st_blksize;
|
||||
int __pad2;
|
||||
long st_blocks;
|
||||
int target_st_atime;
|
||||
unsigned int target_st_atime_nsec;
|
||||
int target_st_mtime;
|
||||
unsigned int target_st_mtime_nsec;
|
||||
int target_st_ctime;
|
||||
unsigned int target_st_ctime_nsec;
|
||||
unsigned int __unused4;
|
||||
unsigned int __unused5;
|
||||
};
|
||||
|
||||
#define TARGET_HAS_STRUCT_STAT64
|
||||
struct target_stat64 {
|
||||
unsigned long long st_dev;
|
||||
unsigned long long st_ino;
|
||||
unsigned int st_mode;
|
||||
unsigned int st_nlink;
|
||||
unsigned int st_uid;
|
||||
unsigned int st_gid;
|
||||
unsigned long long st_rdev;
|
||||
unsigned long long __pad0;
|
||||
long long st_size;
|
||||
int st_blksize;
|
||||
int __pad1;
|
||||
long long st_blocks;
|
||||
int target_st_atime;
|
||||
unsigned int target_st_atime_nsec;
|
||||
int target_st_mtime;
|
||||
unsigned int target_st_mtime_nsec;
|
||||
int target_st_ctime;
|
||||
unsigned int target_st_ctime_nsec;
|
||||
unsigned int __unused4;
|
||||
unsigned int __unused5;
|
||||
};
|
||||
|
||||
#elif defined(TARGET_PPC)
|
||||
|
||||
#define TARGET_STAT_HAVE_NSEC
|
||||
@ -1929,7 +1978,7 @@ struct target_stat64 {
|
||||
abi_ulong target_st_mtime_nsec;
|
||||
abi_ulong target_st_ctime;
|
||||
abi_ulong target_st_ctime_nsec;
|
||||
abi_long __unused[3];
|
||||
abi_long __qemu_unused[3];
|
||||
};
|
||||
|
||||
#elif defined(TARGET_SH4)
|
||||
@ -2016,7 +2065,7 @@ struct target_stat {
|
||||
abi_ulong target_st_ctime;
|
||||
abi_ulong target_st_ctime_nsec;
|
||||
|
||||
abi_long __unused[3];
|
||||
abi_long __qemu_unused[3];
|
||||
};
|
||||
#elif defined(TARGET_S390X)
|
||||
struct target_stat {
|
||||
@ -2037,7 +2086,7 @@ struct target_stat {
|
||||
abi_ulong target_st_ctime_nsec;
|
||||
abi_ulong st_blksize;
|
||||
abi_long st_blocks;
|
||||
abi_ulong __unused[3];
|
||||
abi_ulong __qemu_unused[3];
|
||||
};
|
||||
#elif defined(TARGET_AARCH64)
|
||||
#define TARGET_STAT_HAVE_NSEC
|
||||
@ -2060,7 +2109,7 @@ struct target_stat {
|
||||
abi_ulong target_st_mtime_nsec;
|
||||
abi_long target_st_ctime;
|
||||
abi_ulong target_st_ctime_nsec;
|
||||
unsigned int __unused[2];
|
||||
unsigned int __qemu_unused[2];
|
||||
};
|
||||
#elif defined(TARGET_XTENSA)
|
||||
#define TARGET_STAT_HAVE_NSEC
|
||||
|
15
meson.build
15
meson.build
@ -94,11 +94,11 @@ endif
|
||||
|
||||
# Specify linker-script with add_project_link_arguments so that it is not placed
|
||||
# within a linker --start-group/--end-group pair
|
||||
if 'CONFIG_FUZZ' in config_host
|
||||
add_project_link_arguments(['-Wl,-T,',
|
||||
(meson.current_source_dir() / 'tests/qtest/fuzz/fork_fuzz.ld')],
|
||||
native: false, language: ['c', 'cpp', 'objc'])
|
||||
endif
|
||||
#if 'CONFIG_FUZZ' in config_host
|
||||
# add_project_link_arguments(['-Wl,-T,',
|
||||
# (meson.current_source_dir() / 'tests/qtest/fuzz/fork_fuzz.ld')],
|
||||
# native: false, language: ['c', 'cpp', 'objc'])
|
||||
#endif
|
||||
|
||||
add_project_arguments(config_host['QEMU_CFLAGS'].split(),
|
||||
native: false, language: ['c', 'objc'])
|
||||
@ -884,6 +884,7 @@ disassemblers = {
|
||||
'arm' : ['CONFIG_ARM_DIS'],
|
||||
'avr' : ['CONFIG_AVR_DIS'],
|
||||
'cris' : ['CONFIG_CRIS_DIS'],
|
||||
'e2k' : ['CONFIG_E2K_DIS'],
|
||||
'hppa' : ['CONFIG_HPPA_DIS'],
|
||||
'i386' : ['CONFIG_I386_DIS'],
|
||||
'x86_64' : ['CONFIG_I386_DIS'],
|
||||
@ -1611,8 +1612,8 @@ linux_user_ss.add(files('gdbstub.c', 'thunk.c'))
|
||||
specific_ss.add_all(when: 'CONFIG_LINUX_USER', if_true: linux_user_ss)
|
||||
|
||||
# needed for fuzzing binaries
|
||||
subdir('tests/qtest/libqos')
|
||||
subdir('tests/qtest/fuzz')
|
||||
#subdir('tests/qtest/libqos')
|
||||
#subdir('tests/qtest/fuzz')
|
||||
|
||||
########################
|
||||
# Library dependencies #
|
||||
|
@ -28,7 +28,7 @@
|
||||
void exec_start_outgoing_migration(MigrationState *s, const char *command, Error **errp)
|
||||
{
|
||||
QIOChannel *ioc;
|
||||
const char *argv[] = { "/bin/sh", "-c", command, NULL };
|
||||
const char *argv[] = { "@TERMUX_PREFIX@/bin/sh", "-c", command, NULL };
|
||||
|
||||
trace_migration_exec_outgoing(command);
|
||||
ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv,
|
||||
@ -55,7 +55,7 @@ static gboolean exec_accept_incoming_migration(QIOChannel *ioc,
|
||||
void exec_start_incoming_migration(const char *command, Error **errp)
|
||||
{
|
||||
QIOChannel *ioc;
|
||||
const char *argv[] = { "/bin/sh", "-c", command, NULL };
|
||||
const char *argv[] = { "@TERMUX_PREFIX@/bin/sh", "-c", command, NULL };
|
||||
|
||||
trace_migration_exec_incoming(command);
|
||||
ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv,
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include "trace.h"
|
||||
#include "hw/boards.h"
|
||||
|
||||
#include <linux/mman.h>
|
||||
|
||||
/* Arbitrary limit on size of each discard command,
|
||||
* keeps them around ~200 bytes
|
||||
*/
|
||||
|
@ -533,7 +533,7 @@ static int net_bridge_run_helper(const char *helper, const char *bridge,
|
||||
*parg++ = helper_cmd;
|
||||
*parg++ = NULL;
|
||||
|
||||
execv("/bin/sh", args);
|
||||
execv("@TERMUX_PREFIX@/bin/sh", args);
|
||||
g_free(helper_cmd);
|
||||
} else {
|
||||
/* assume helper is just the executable path name */
|
||||
|
@ -52,7 +52,6 @@
|
||||
#define HAVE_NBD_DEVICE 0
|
||||
#endif
|
||||
|
||||
#define SOCKET_PATH "/var/lock/qemu-nbd-%s"
|
||||
#define QEMU_NBD_OPT_CACHE 256
|
||||
#define QEMU_NBD_OPT_AIO 257
|
||||
#define QEMU_NBD_OPT_DISCARD 258
|
||||
@ -91,7 +90,7 @@ static void usage(const char *name)
|
||||
" -p, --port=PORT port to listen on (default `%d')\n"
|
||||
" -b, --bind=IFACE interface to bind to (default `0.0.0.0')\n"
|
||||
" -k, --socket=PATH path to the unix socket\n"
|
||||
" (default '"SOCKET_PATH"')\n"
|
||||
" (default '@TERMUX_PREFIX@/tmp/nbd-%s')\n"
|
||||
" -e, --shared=NUM device can be shared by NUM clients (default '1')\n"
|
||||
" -t, --persistent don't exit on the last connection\n"
|
||||
" -v, --verbose display extra debugging information\n"
|
||||
@ -964,7 +963,7 @@ int main(int argc, char **argv)
|
||||
|
||||
if (device != NULL && sockpath == NULL) {
|
||||
sockpath = g_malloc(128);
|
||||
snprintf(sockpath, 128, SOCKET_PATH, basename(device));
|
||||
snprintf(sockpath, 128, "@TERMUX_PREFIX@/tmp/nbd-%s", basename(device));
|
||||
}
|
||||
|
||||
server = qio_net_listener_new();
|
||||
|
@ -4,7 +4,7 @@
|
||||
qemu_target_list="i386 i486 alpha arm armeb sparc sparc32plus sparc64 \
|
||||
ppc ppc64 ppc64le m68k mips mipsel mipsn32 mipsn32el mips64 mips64el \
|
||||
sh4 sh4eb s390x aarch64 aarch64_be hppa riscv32 riscv64 xtensa xtensaeb \
|
||||
microblaze microblazeel or1k x86_64"
|
||||
microblaze microblazeel or1k x86_64 e2k"
|
||||
|
||||
i386_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00'
|
||||
i386_mask='\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
|
||||
@ -136,6 +136,10 @@ or1k_magic='\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\
|
||||
or1k_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
|
||||
or1k_family=or1k
|
||||
|
||||
e2k_magic='\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xaf\x00'
|
||||
e2k_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
|
||||
e2k_family=e2k
|
||||
|
||||
qemu_get_family() {
|
||||
cpu=${HOST_ARCH:-$(uname -m)}
|
||||
case "$cpu" in
|
||||
|
@ -92,6 +92,8 @@ int graphic_depth = 32;
|
||||
#define QEMU_ARCH QEMU_ARCH_XTENSA
|
||||
#elif defined(TARGET_AVR)
|
||||
#define QEMU_ARCH QEMU_ARCH_AVR
|
||||
#elif defined(TARGET_E2K)
|
||||
#define QEMU_ARCH QEMU_ARCH_E2K
|
||||
#endif
|
||||
|
||||
const uint32_t arch_type = QEMU_ARCH;
|
||||
|
@ -17,6 +17,8 @@
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/mman.h>
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <endian.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
16
target/e2k/cpu-param.h
Normal file
16
target/e2k/cpu-param.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* E2K cpu parameters for qemu.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef E2K_CPU_PARAM_H
|
||||
#define E2K_CPU_PARAM_H 1
|
||||
|
||||
# define TARGET_LONG_BITS 64
|
||||
# define TARGET_PAGE_BITS 12 /* 4k */
|
||||
# define TARGET_PHYS_ADDR_SPACE_BITS 40
|
||||
# define TARGET_VIRT_ADDR_SPACE_BITS 48
|
||||
# define NB_MMU_MODES 4
|
||||
|
||||
#endif
|
50
target/e2k/cpu-qom.h
Normal file
50
target/e2k/cpu-qom.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* QEMU E2K CPU
|
||||
*
|
||||
* Copyright (c) 2012 SUSE LINUX Products GmbH
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see
|
||||
* <http://www.gnu.org/licenses/lgpl-2.1.html>
|
||||
*/
|
||||
#ifndef QEMU_E2K_CPU_QOM_H
|
||||
#define QEMU_E2K_CPU_QOM_H
|
||||
|
||||
#include "hw/core/cpu.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_E2K_CPU "e2k-cpu"
|
||||
|
||||
OBJECT_DECLARE_TYPE(E2KCPU, E2KCPUClass,
|
||||
E2K_CPU)
|
||||
|
||||
typedef struct e2k_def_t e2k_def_t;
|
||||
/**
|
||||
* E2KCPUClass:
|
||||
* @parent_realize: The parent class' realize handler.
|
||||
* @parent_reset: The parent class' reset handler.
|
||||
*
|
||||
* A E2K CPU model.
|
||||
*/
|
||||
struct E2KCPUClass {
|
||||
/*< private >*/
|
||||
CPUClass parent_class;
|
||||
/*< public >*/
|
||||
|
||||
DeviceRealize parent_realize;
|
||||
DeviceReset parent_reset;
|
||||
e2k_def_t *cpu_def;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
348
target/e2k/cpu.c
Normal file
348
target/e2k/cpu.c
Normal file
@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Sparc CPU init helpers
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "cpu.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/visitor.h"
|
||||
|
||||
//#define DEBUG_FEATURES
|
||||
|
||||
void cpu_e2k_set_id(CPUE2KState *env, unsigned int cpu);
|
||||
void e2k_cpu_dump_state(CPUState *cs, FILE *f, int flags);
|
||||
|
||||
static void e2k_cpu_reset(DeviceState *dev)
|
||||
{
|
||||
CPUState *cs = CPU(dev);
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
E2KCPUClass *ecc = E2K_CPU_GET_CLASS(cpu);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
|
||||
ecc->parent_reset(dev);
|
||||
|
||||
memset(env, 0, offsetof(CPUE2KState, end_reset_fields));
|
||||
|
||||
env->cr1.wpsz = 4;
|
||||
env->cr1.wbs = 4;
|
||||
env->wd.base = 0;
|
||||
env->wd.size = 16;
|
||||
env->wd.psize = 8;
|
||||
env->bn.base = 8;
|
||||
env->bn.size = 8;
|
||||
env->bn.cur = 0;
|
||||
env->aau.incrs[0] = 1; /* always one */
|
||||
env->fpcr._one = 1;
|
||||
|
||||
// FIXME: testing
|
||||
env->idr = 0x3a207; // mimic 8c
|
||||
}
|
||||
|
||||
static bool e2k_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "e2k_cpu_exec_interrupt: not implemented\n");
|
||||
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
||||
e2k_cpu_do_interrupt(cs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void e2k_cpu_do_interrupt(CPUState *cs)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "e2k_cpu_do_interrupt: not implemented\n");
|
||||
cs->exception_index = -1;
|
||||
}
|
||||
|
||||
static void cpu_e2k_disas_set_info(CPUState *cs, disassemble_info *info)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
|
||||
info->mach = env->version * 3;
|
||||
info->print_insn = print_insn_e2k;
|
||||
}
|
||||
|
||||
|
||||
void cpu_e2k_set_id(CPUE2KState *env, unsigned int cpu)
|
||||
{
|
||||
// TODO: cpu_e2k_set_id
|
||||
qemu_log_mask(LOG_UNIMP, "cpu_e2k_set_id: not implemented\n");
|
||||
}
|
||||
|
||||
/* https://www.altlinux.org/Модели_процессоров_Эльбрус */
|
||||
#define DEFAULT_CPU_MODEL "e8c"
|
||||
static const struct e2k_def_t e2k_defs[] = {
|
||||
{
|
||||
.name = "e8c", // default choice
|
||||
.canonical_name = "MCST Elbrus 8C",
|
||||
.gdb_arch = "elbrus-8c",
|
||||
.isa_version = 4,
|
||||
},
|
||||
{
|
||||
.name = "e2c+", // however it works better
|
||||
.canonical_name = "MCST Elbrus 2C+ (Monocube)",
|
||||
.gdb_arch = "elbrus-v2",
|
||||
.isa_version = 2,
|
||||
},
|
||||
#if 0 /* for reference, never tested */
|
||||
{
|
||||
.name = "e2s",
|
||||
.canonical_name = "MCST Elbrus 4C",
|
||||
.gdb_arch = "elbrus-v3",
|
||||
.isa_version = 3,
|
||||
},
|
||||
{
|
||||
.name = "e8c2",
|
||||
.canonical_name = "MCST Elbrus 8CB",
|
||||
.gdb_arch = "elbrus-v5",
|
||||
.isa_version = 5,
|
||||
},
|
||||
{
|
||||
.name = "e16c",
|
||||
.canonical_name = "MCST Elbrus 16C",
|
||||
.gdb_arch = "elbrus-v6",
|
||||
.isa_version = 6,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline void cpu_dump_state_br(CPUE2KState *env, FILE *f, int flags)
|
||||
{
|
||||
uint32_t br = e2k_state_br(env);
|
||||
E2KBnState *bn = &env->bn;
|
||||
E2KBpState *bp = &env->bp;
|
||||
|
||||
qemu_fprintf(f, "br 0x%x\n", br);
|
||||
qemu_fprintf(f, " rbs %d\n", bn->base / 2);
|
||||
qemu_fprintf(f, " rsz %d\n", bn->size / 2 - 1);
|
||||
qemu_fprintf(f, " rcur %d\n", bn->cur / 2);
|
||||
qemu_fprintf(f, " psz %d\n", bp->size);
|
||||
qemu_fprintf(f, " pcur %d\n", bp->cur);
|
||||
}
|
||||
|
||||
void e2k_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
unsigned int i;
|
||||
|
||||
qemu_fprintf(f, " ip = 0x%016lx\n", env->ip);
|
||||
qemu_fprintf(f, " pregs = 0x%016lx\n", env->pregs);
|
||||
qemu_fprintf(f, " cr0_lo = 0x%016lx\n", env->cr0_lo);
|
||||
qemu_fprintf(f, " cr0_hi = 0x%016lx\n", env->cr0_hi);
|
||||
qemu_fprintf(f, " cr1_lo = 0x%016lx\n", env->cr1.lo);
|
||||
qemu_fprintf(f, " cr1_hi = 0x%016lx\n", env->cr1.hi);
|
||||
qemu_fprintf(f, " pcsp_lo = 0x%016lx\n", e2k_state_pcsp_lo(env));
|
||||
qemu_fprintf(f, " pcsp_hi = 0x%016lx\n", e2k_state_pcsp_hi(env));
|
||||
qemu_fprintf(f, " psp_lo = 0x%016lx\n", e2k_state_psp_lo(env));
|
||||
qemu_fprintf(f, " psp_hi = 0x%016lx\n", e2k_state_psp_hi(env));
|
||||
qemu_fprintf(f, " usd_lo = 0x%016lx\n", env->usd.lo);
|
||||
qemu_fprintf(f, " usd_hi = 0x%016lx\n", env->usd.hi);
|
||||
qemu_fprintf(f, " lsr = 0x%016lx\n", env->lsr);
|
||||
cpu_dump_state_br(env, f, flags);
|
||||
|
||||
for (i = 0; i < E2K_REG_COUNT; i++) {
|
||||
char name = i < E2K_NR_COUNT ? 'r' : 'g';
|
||||
int tag = env->tags[i];
|
||||
qemu_fprintf(f, "%%%c%d\t<%d%d> 0x%lx\n", name, i, tag >> 2, tag & 3,
|
||||
env->regs[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
int preg = (env->pregs >> (i * 2)) & 3;
|
||||
qemu_fprintf(f, "pred%d\t<%d> %s\n", i, preg >> 1,
|
||||
preg & 1 ? "true" : "false");
|
||||
}
|
||||
}
|
||||
|
||||
static void e2k_cpu_set_pc(CPUState *cs, vaddr value)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
|
||||
qemu_log_mask(LOG_UNIMP, "e2k_cpu_synchronize_from_tb: not implemented\n");
|
||||
|
||||
cpu->env.ip = value;
|
||||
}
|
||||
|
||||
static void e2k_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
|
||||
qemu_log_mask(LOG_UNIMP, "e2k_cpu_synchronize_from_tb: not implemented\n");
|
||||
|
||||
cpu->env.ip = tb->pc;
|
||||
}
|
||||
|
||||
static bool e2k_cpu_has_work(CPUState *cs)
|
||||
{
|
||||
// TODO: e2k_cpu_has_work
|
||||
qemu_log_mask(LOG_UNIMP, "e2k_cpu_has_work: not implemented\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static char *e2k_cpu_type_name(const char *cpu_model)
|
||||
{
|
||||
return g_strdup(cpu_model);
|
||||
}
|
||||
|
||||
static ObjectClass *e2k_cpu_class_by_name(const char *cpu_model)
|
||||
{
|
||||
ObjectClass *oc;
|
||||
char *typename;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
if (!strcasecmp(cpu_model, "any")) {
|
||||
cpu_model = DEFAULT_CPU_MODEL;
|
||||
}
|
||||
#endif // CONFIG_USER_ONLY
|
||||
|
||||
typename = e2k_cpu_type_name(cpu_model);
|
||||
oc = object_class_by_name(typename);
|
||||
g_free(typename);
|
||||
return oc;
|
||||
}
|
||||
|
||||
static void e2k_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
{
|
||||
CPUState *cs = CPU(dev);
|
||||
E2KCPUClass *ecc = E2K_CPU_GET_CLASS(dev);
|
||||
Error *local_err = NULL;
|
||||
E2KCPU *cpu = E2K_CPU(dev);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
|
||||
env->version = env->def.isa_version;
|
||||
|
||||
cpu_exec_realizefn(cs, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_init_vcpu(cs);
|
||||
|
||||
ecc->parent_realize(dev, errp);
|
||||
}
|
||||
|
||||
static void e2k_cpu_initfn(Object* obj)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(obj);
|
||||
E2KCPUClass *ecc = E2K_CPU_GET_CLASS(obj);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
|
||||
cpu_set_cpustate_pointers(cpu);
|
||||
|
||||
if (ecc->cpu_def) {
|
||||
env->def = *ecc->cpu_def;
|
||||
}
|
||||
}
|
||||
|
||||
static gchar* e2k_cpu_gdb_arch_name(CPUState *cs)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
|
||||
return g_strdup_printf("%s:%d", env->def.gdb_arch, TARGET_LONG_BITS);
|
||||
}
|
||||
|
||||
static void e2k_cpu_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
E2KCPUClass *ecc = E2K_CPU_CLASS(oc);
|
||||
CPUClass *cc = CPU_CLASS(oc);
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
device_class_set_parent_realize(dc, e2k_cpu_realizefn,
|
||||
&ecc->parent_realize);
|
||||
|
||||
device_class_set_parent_reset(dc, e2k_cpu_reset, &ecc->parent_reset);
|
||||
|
||||
cc->has_work = e2k_cpu_has_work;
|
||||
cc->dump_state = e2k_cpu_dump_state;
|
||||
cc->set_pc = e2k_cpu_set_pc;
|
||||
cc->do_interrupt = e2k_cpu_do_interrupt;
|
||||
cc->cpu_exec_interrupt = e2k_cpu_exec_interrupt;
|
||||
cc->synchronize_from_tb = e2k_cpu_synchronize_from_tb;
|
||||
cc->class_by_name = e2k_cpu_class_by_name;
|
||||
cc->disas_set_info = cpu_e2k_disas_set_info;
|
||||
cc->tcg_initialize = e2k_tcg_initialize;
|
||||
cc->tlb_fill = e2k_cpu_tlb_fill;
|
||||
|
||||
cc->gdb_arch_name = e2k_cpu_gdb_arch_name;
|
||||
cc->gdb_read_register = e2k_cpu_gdb_read_register;
|
||||
cc->gdb_write_register = e2k_cpu_gdb_write_register;
|
||||
cc->gdb_num_core_regs = 574;
|
||||
}
|
||||
|
||||
static const TypeInfo e2k_cpu_type_info = {
|
||||
.name = TYPE_E2K_CPU,
|
||||
.parent = TYPE_CPU,
|
||||
.instance_size = sizeof(E2KCPU),
|
||||
.instance_init = e2k_cpu_initfn,
|
||||
.abstract = true,
|
||||
.class_size = sizeof(E2KCPUClass),
|
||||
.class_init = e2k_cpu_class_init,
|
||||
};
|
||||
|
||||
static void e2k_cpu_cpudef_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
E2KCPUClass *ecc = E2K_CPU_CLASS(oc);
|
||||
ecc->cpu_def = data;
|
||||
}
|
||||
|
||||
static void e2k_register_cpudef_type(const struct e2k_def_t *def)
|
||||
{
|
||||
char *typename = e2k_cpu_type_name(def->name);
|
||||
TypeInfo ti = {
|
||||
.name = typename,
|
||||
.parent = TYPE_E2K_CPU,
|
||||
.class_init = e2k_cpu_cpudef_class_init,
|
||||
.class_data = (void *)def,
|
||||
};
|
||||
|
||||
type_register(&ti);
|
||||
g_free(typename);
|
||||
}
|
||||
|
||||
static void e2k_cpu_register_types(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
type_register_static(&e2k_cpu_type_info);
|
||||
for (i = 0; i < ARRAY_SIZE(e2k_defs); i++) {
|
||||
e2k_register_cpudef_type(&e2k_defs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
type_init(e2k_cpu_register_types)
|
||||
|
||||
void e2k_cpu_list(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(e2k_defs); i++) {
|
||||
qemu_printf("%6s (%-30s) ISA version: v%d\n",
|
||||
e2k_defs[i].name,
|
||||
e2k_defs[i].canonical_name,
|
||||
e2k_defs[i].isa_version
|
||||
);
|
||||
}
|
||||
}
|
777
target/e2k/cpu.h
Normal file
777
target/e2k/cpu.h
Normal file
@ -0,0 +1,777 @@
|
||||
#ifndef E2K_CPU_H
|
||||
#define E2K_CPU_H
|
||||
|
||||
#include "qemu/bswap.h"
|
||||
#include "cpu-qom.h"
|
||||
#include "exec/cpu-defs.h"
|
||||
#include "fpu/softfloat.h"
|
||||
|
||||
void e2k_tcg_initialize(void);
|
||||
|
||||
#define GEN_MASK(start, len) (((1UL << (len)) - 1) << (start))
|
||||
#define GET_BIT(v, index) (((v) >> (index)) & 1)
|
||||
#define GET_FIELD(v, s, l) (((v) >> (s)) & GEN_MASK(0, l))
|
||||
#define SET_FIELD(v, f, s, l) \
|
||||
( \
|
||||
((v) & ~GEN_MASK((s), (l))) | \
|
||||
((((typeof((v))) (f)) << (s)) & GEN_MASK((s), (l))) \
|
||||
)
|
||||
|
||||
#define MMU_USER_IDX 1
|
||||
#define CPU_RESOLVING_TYPE TYPE_E2K_CPU
|
||||
|
||||
#define E2K_TAG_SIZE 2 /* 2-bit tag for 32-bit value */
|
||||
#define E2K_REG_LEN sizeof(uint64_t)
|
||||
#define E2K_REG_SIZE (E2K_REG_LEN * 8)
|
||||
#define E2K_REG_TAGS_SIZE (E2K_TAG_SIZE * 2) /* two tags for 32-bit halves */
|
||||
|
||||
#define E2K_WR_COUNT 64 /* %rN [0, 64) */
|
||||
#define E2K_BR_COUNT 128 /* %b[N] [0, 128) */
|
||||
#define E2K_NR_COUNT (E2K_WR_COUNT + E2K_BR_COUNT)
|
||||
#define E2K_GR_COUNT 32 /* %gN [0, 32) */
|
||||
#define E2K_BGR_COUNT 8 /* %gN [24, 32) */
|
||||
#define E2K_REG_COUNT (E2K_NR_COUNT + E2K_GR_COUNT)
|
||||
|
||||
#define E2K_PR_COUNT 32 /* %predN [0, 32) */
|
||||
|
||||
typedef enum {
|
||||
E2K_TAG_NUMBER32 = 0,
|
||||
E2K_TAG_NUMBER64 = 0,
|
||||
E2K_TAG_NON_NUMBER32 = 1,
|
||||
E2K_TAG_NON_NUMBER64 = 5,
|
||||
} E2kRegisterTag;
|
||||
|
||||
#define CTPR_BASE_OFF 0
|
||||
#define CTPR_BASE_END 47
|
||||
#define CTPR_BASE_LEN (CTPR_BASE_END - CTPR_BASE_OFF + 1)
|
||||
#define CTPR_TAG_OFF 54
|
||||
#define CTPR_TAG_END 56
|
||||
#define CTPR_TAG_LEN (CTPR_TAG_END - CTPR_TAG_OFF + 1)
|
||||
#define CTPR_OPC_OFF 57
|
||||
#define CTPR_OPC_END 58
|
||||
#define CTPR_OPC_LEN (CTPR_OPC_END - CTPR_OPC_OFF + 1)
|
||||
#define CTPR_IPD_OFF 59
|
||||
#define CTPR_IPD_END 60
|
||||
#define CTPR_IPD_LEN (CTPR_IPD_END - CTPR_IPD_OFF + 1)
|
||||
|
||||
typedef enum {
|
||||
CTPR_TAG_NONE = 0x0,
|
||||
CTPR_TAG_RETURN = 0x2,
|
||||
CTPR_TAG_DISP = 0x3,
|
||||
CTPR_TAG_SDISP = 0x5,
|
||||
} CtprTag;
|
||||
|
||||
typedef enum {
|
||||
CTPR_OPC_LDISP = 0x1,
|
||||
} CtprOpc;
|
||||
|
||||
#define WD_BASE_OFF 0
|
||||
#define WD_BASE_END 10
|
||||
#define WD_BASE_LEN (WD_BASE_END - WD_BASE_OFF + 1)
|
||||
#define WD_SIZE_OFF 16
|
||||
#define WD_SIZE_END 26
|
||||
#define WD_SIZE_LEN (WD_SIZE_END - WD_SIZE_OFF + 1)
|
||||
#define WD_PSIZE_OFF 32
|
||||
#define WD_PSIZE_END 42
|
||||
#define WD_PSIZE_LEN (WD_PSIZE_END - WD_PSIZE_OFF + 1)
|
||||
#define WD_FX_OFF 48
|
||||
#define WD_FX_BIT (1UL << WD_FX_OFF)
|
||||
|
||||
#define DESC_HI_IND_OFF 0 /* index for SPILL */
|
||||
#define DESC_HI_IND_END 31
|
||||
#define DESC_HI_IND_LEN (DESC_HI_IND_END - DESC_HI_IND_OFF + 1)
|
||||
#define DESC_HI_SIZE_OFF 32 /* stack size */
|
||||
#define DESC_HI_SIZE_END 63
|
||||
#define DESC_HI_SIZE_LEN (DESC_HI_SIZE_END - DESC_HI_SIZE_OFF + 1)
|
||||
|
||||
#define DESC_LO_BASE_OFF 0 /* stack address */
|
||||
#define DESC_LO_BASE_END 47
|
||||
#define DESC_LO_BASE_LEN (DESC_LO_BASE_END - DESC_LO_BASE_OFF + 1)
|
||||
#define DESC_LO_READ_OFF 59
|
||||
#define DESC_LO_READ_BIT (1UL << DESC_LO_READ_OFF)
|
||||
#define DESC_LO_WRITE_OFF 60
|
||||
#define DESC_LO_WRITE_BIT (1UL << DESC_LO_WRITE_OFF)
|
||||
|
||||
#define PSHTP_IND_OFF 0
|
||||
#define PSHTP_IND_END 11
|
||||
#define PSHTP_IND_LEN (PSHTP_IND_END - PSHTP_IND_OFF + 1)
|
||||
#define PSHTP_FXIND_OFF 16
|
||||
#define PSHTP_FXIND_END 26
|
||||
#define PSHTP_FXIND_LEN (PSHTP_FXIND_END - PSHTP_FXIND_OFF + 1)
|
||||
#define PSHTP_TIND_OFF 32
|
||||
#define PSHTP_TIND_END 42
|
||||
#define PSHTP_TIND_LEN (PSHTP_TIND_END - PSHTP_TIND_OFF + 1)
|
||||
#define PSHTP_FX_OFF 48
|
||||
#define PSHTP_FX_BIT (1UL << PSHTP_FX_OFF)
|
||||
|
||||
#define USD_LO_BASE_OFF 0
|
||||
#define USD_LO_BASE_END 47
|
||||
#define USD_LO_BASE_LEN (USD_LO_BASE_END - USD_LO_BASE_OFF + 1)
|
||||
#define USD_LO_PROTECTED_OFF 58
|
||||
#define USD_LO_PROTECTED_BIT (1UL << USD_LO_PROTECTED_OFF)
|
||||
#define USD_LO_READ_OFF 59
|
||||
#define USD_LO_READ_BIT (1UL << USD_LO_READ_OFF)
|
||||
#define USD_LO_WRITE_OFF 60
|
||||
#define USD_LO_WRITE_BIT (1UL << USD_LO_WRITE_OFF)
|
||||
|
||||
#define USD_HI_CURPTR_OFF 0
|
||||
#define USD_HI_CURPTR_END 31
|
||||
#define USD_HI_CURPTR_LEN (USD_HI_CURPTR_END - USD_HI_CURPTR_OFF + 1)
|
||||
#define USD_HI_SIZE_OFF 32
|
||||
#define USD_HI_SIZE_END 63
|
||||
#define USD_HI_SIZE_LEN (USD_HI_SIZE_END - USD_HI_SIZE_OFF + 1)
|
||||
|
||||
#define CR1_HI_BR_OFF 0
|
||||
#define CR1_HI_BR_END 27
|
||||
#define CR1_HI_BR_LEN (CR1_HI_BR_END - CR1_HI_BR_OFF + 1)
|
||||
#define CR1_HI_WDBL_OFF 35
|
||||
#define CR1_HI_WDBL_BIT (1UL << CR1_HI_WDBL_OFF)
|
||||
#define CR1_HI_USSZ_OFF 36
|
||||
#define CR1_HI_USSZ_END 63
|
||||
#define CR1_HI_USSZ_LEN (CR1_HI_USSZ_END - CR1_HI_USSZ_OFF + 1)
|
||||
|
||||
#define CR1_LO_TR_OFF 0
|
||||
#define CR1_LO_TR_END 14
|
||||
#define CR1_LO_TR_LEN (CR1_LO_TR_END - CR1_LO_TR_OFF + 1)
|
||||
#define CR1_LO_EIN_OFF 16
|
||||
#define CR1_LO_EIN_END 23
|
||||
#define CR1_LO_EIN_LEN (CR1_LO_EIN_END - CR1_LO_EIN_OFF + 1)
|
||||
#define CR1_LO_SS_OFF 24
|
||||
#define CR1_LO_SS_BIT (1UL << CR1_LO_SS_OFF)
|
||||
#define CR1_LO_WFX_OFF 25
|
||||
#define CR1_LO_WFX_BIT (1UL << CR1_LO_WFX_OFF)
|
||||
#define CR1_LO_WPSZ_OFF 26
|
||||
#define CR1_LO_WPSZ_END 32
|
||||
#define CR1_LO_WPSZ_LEN (CR1_LO_WPSZ_END - CR1_LO_WPSZ_OFF + 1)
|
||||
#define CR1_LO_WBS_OFF 33
|
||||
#define CR1_LO_WBS_END 39
|
||||
#define CR1_LO_WBS_LEN (CR1_LO_WBS_END - CR1_LO_WBS_OFF + 1)
|
||||
#define CR1_LO_CUIR_OFF 40
|
||||
#define CR1_LO_CUIR_END 56
|
||||
#define CR1_LO_CUIR_LEN (CR1_LO_CUIR_END - CR1_LO_CUIR_OFF + 1)
|
||||
#define CR1_LO_PSR_OFF 57
|
||||
#define CR1_LO_PSR_END 63
|
||||
#define CR1_LO_PSR_LEN (CR1_LO_PSR_END - CR1_LO_PSR_OFF + 1)
|
||||
|
||||
#define BR_RBS_OFF 0 /* based regs window offset */
|
||||
#define BR_RBS_END 5
|
||||
#define BR_RBS_LEN (BR_RBS_END - BR_RBS_OFF + 1)
|
||||
#define BR_RSZ_OFF 6 /* based regs window size */
|
||||
#define BR_RSZ_END 11
|
||||
#define BR_RSZ_LEN (BR_RSZ_END - BR_RSZ_OFF + 1)
|
||||
#define BR_RCUR_OFF 12 /* based regs current index */
|
||||
#define BR_RCUR_END 17
|
||||
#define BR_RCUR_LEN (BR_RCUR_END - BR_RCUR_OFF + 1)
|
||||
#define BR_BN_OFF BR_RBS_OFF
|
||||
#define BR_BN_END BR_RCUR_END
|
||||
#define BR_BN_LEN (BR_BN_END - BR_BN_OFF + 1)
|
||||
#define BR_PSZ_OFF 18 /* based pregs window size */
|
||||
#define BR_PSZ_END 22
|
||||
#define BR_PSZ_LEN (BR_PSZ_END - BR_PSZ_OFF + 1)
|
||||
#define BR_PCUR_OFF 23 /* based pregs current index */
|
||||
#define BR_PCUR_END 27
|
||||
#define BR_PCUR_LEN (BR_PCUR_END - BR_PCUR_OFF + 1)
|
||||
#define BR_BP_OFF BR_PSZ_OFF
|
||||
#define BR_BP_END BR_PCUR_END
|
||||
#define BR_BP_LEN (BR_BP_END - BR_BP_OFF + 1)
|
||||
|
||||
#define LSR_LCNT_OFF 0 /* loop counter */
|
||||
#define LSR_LCNT_END 31
|
||||
#define LSR_LCNT_LEN (LSR_LCNT_END - LSR_LCNT_OFF + 1)
|
||||
#define LSR_ECNT_OFF 32 /* epilogue counter */
|
||||
#define LSR_ECNT_END 36
|
||||
#define LSR_ECNT_LEN (LSR_ECNT_END - LSR_ECNT_OFF + 1)
|
||||
#define LSR_VLC_OFF 37 /* loop count valid bit */
|
||||
#define LSR_VLC_BIT (1UL << LSR_VLC_OFF)
|
||||
#define LSR_OVER_OFF 38 /* loop count overflow */
|
||||
#define LSR_LDMC_OFF 39 /* loads manual control */
|
||||
#define LSR_LDOVL_OFF 40 /* load overlap */
|
||||
#define LSR_LDOVL_END 47
|
||||
#define LSR_LDOVL_SIZE (LSR_LDOVL_END - LSR_LDOVL_OFF + 1)
|
||||
#define LSR_PCNT_OFF 48 /* prologue counter */
|
||||
#define LSR_PCNT_END 52
|
||||
#define LSR_PCNT_LEN (LSR_PCNT_END - LSR_PCNT_OFF + 1)
|
||||
#define LSR_STRMD_OFF 53 /* store remainder counter */
|
||||
#define LSR_STRMD_END 59
|
||||
#define LSR_STRMD_LEN (LSR_STRMD_END - LSR_STRMD_OFF + 1)
|
||||
#define LSR_SEMC_OFF /* side effects manual control */
|
||||
#define LSR_ILCR_MASK 0x1f001fffffffffUL
|
||||
|
||||
#define UPSR_FE_OFF 0 /* floating point enable */
|
||||
#define UPSR_FE_BIT 1
|
||||
#define UPSR_SE_OFF 1 /* supervisor mode enable (only for Intel) */
|
||||
#define UPSR_SE_BIT (1 << UPSR_SE_OFF)
|
||||
#define UPSR_AC_OFF 2 /* not-aligned access control */
|
||||
#define UPSR_AC_BIT (1 << UPSR_AC_OFF)
|
||||
#define UPSR_DI_OFF 3 /* delayed interrupt (only for Intel) */
|
||||
#define UPSR_DI_BIT (1 << UPSR_DI_OFF)
|
||||
#define UPSR_WP_OFF 4 /* write protection (only for Intel) */
|
||||
#define UPSR_WP_BIT (1 << UPSR_WP_OFF)
|
||||
#define UPSR_IE_OFF 5 /* interrupt enable */
|
||||
#define UPSR_IE_BIT (1 << UPSR_IE_OFF)
|
||||
#define UPSR_A20_OFF 6 /* emulation of 1 Mb memory (only for Intel) */
|
||||
#define UPSR_A20_BIT (1 << UPSR_A20_OFF)
|
||||
#define UPSR_NMIE_OFF 7 /* not masked interrupt enable */
|
||||
#define UPSR_NMIE_BIT (1 << UPSR_NMIE_OFF)
|
||||
/* next field of register exist only on E3S/ES2/E2S/E8C/E1C+ CPUs */
|
||||
#define UPSR_FSM_OFF 8 /* floating comparison mode flag */
|
||||
/* 1 - compatible with x86/x87 */
|
||||
#define UPSR_FSM_BIT (1 << UPSR_FSM_OFF)
|
||||
#define UPSR_IMPT_OFF 9 /* ignore Memory Protection Table flag */
|
||||
#define UPSR_IMPT_BIT (1 << UPSR_IMPT_OFF)
|
||||
#define UPSR_IUC_OFF 10 /* ignore access right for uncached pages */
|
||||
#define UPSR_IUC_BIT (1 << UPSR_IUC_OFF)
|
||||
|
||||
#define IDR_MDL_OFF 0 /* CPU model number */
|
||||
#define IDR_MDL_END 7
|
||||
#define IDR_MDL_LEN (IDR_MDL_END - IDR_MDL_OFF + 1)
|
||||
#define IDR_REV_OFF 8 /* revision number */
|
||||
#define IDR_REV_END 11
|
||||
#define IDR_REV_LEN (IDR_REV_END - IDR_REV_OFF + 1)
|
||||
#define IDR_WBL_OFF 12 /* write-back length of L2 */
|
||||
#define IDR_WBL_END 14
|
||||
#define IDR_WBL_LEN (IDR_WBL_END - IDR_WBL_OFF + 1)
|
||||
#define IDR_MS_OFF 15 /* model specific info */
|
||||
#define IDR_MS_END 63
|
||||
#define IDR_MS_LEN (IDR_MS_END - IDR_MS_OFF + 1)
|
||||
|
||||
/* Cache write-back length */
|
||||
#define IDR_WBL_0 0x0 /* none CPU internal cache */
|
||||
#define IDR_WBL_32 0x1
|
||||
#define IDR_WBL_64 0x2
|
||||
#define IDR_WBL_128 0x3
|
||||
#define IDR_WBL_256 0x4
|
||||
#define IDR_WBL_TO_BYTES(wbl) ((wbl) ? (1 << ((wbs) + 4)) : 1)
|
||||
|
||||
typedef enum {
|
||||
E2K_EXCP_SYSCALL = 0x02,
|
||||
E2K_EXCP_ILLOPC = 0x03,
|
||||
E2K_EXCP_ILLOPN = 0x04,
|
||||
E2K_EXCP_MAPERR = 0x05,
|
||||
} Exception;
|
||||
|
||||
struct e2k_def_t {
|
||||
const char *name;
|
||||
const char *canonical_name;
|
||||
const char *gdb_arch;
|
||||
uint32_t isa_version;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t base;
|
||||
uint32_t size;
|
||||
uint32_t cur;
|
||||
} E2KBnState;
|
||||
|
||||
typedef struct {
|
||||
uint32_t size;
|
||||
uint32_t cur;
|
||||
} E2KBpState;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint64_t tr: 15;
|
||||
uint64_t unused1: 1;
|
||||
uint64_t ein: 8;
|
||||
uint64_t ss: 1;
|
||||
uint64_t wfx: 1;
|
||||
uint64_t wpsz: 7;
|
||||
uint64_t wbs: 7;
|
||||
uint64_t cuir: 17;
|
||||
uint64_t psr: 7;
|
||||
};
|
||||
struct {
|
||||
uint64_t unused2: 40;
|
||||
uint64_t cui: 16;
|
||||
uint64_t ic: 1;
|
||||
uint64_t pm: 1;
|
||||
uint64_t ie: 1;
|
||||
uint64_t sge: 1;
|
||||
uint64_t lw: 1;
|
||||
uint64_t uie: 1;
|
||||
uint64_t nmie: 1;
|
||||
uint64_t unmie: 1;
|
||||
};
|
||||
uint64_t lo;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
uint64_t br: 28;
|
||||
uint64_t unused3: 7;
|
||||
uint64_t wdbl: 1;
|
||||
/* user stack size */
|
||||
uint64_t ussz: 28;
|
||||
};
|
||||
struct {
|
||||
uint64_t rbs: 6;
|
||||
uint64_t rsz: 6;
|
||||
uint64_t rcur: 6;
|
||||
uint64_t psz: 5;
|
||||
uint64_t pcur: 5;
|
||||
uint64_t unused4: 36;
|
||||
};
|
||||
uint64_t hi;
|
||||
};
|
||||
} E2KCr1State;
|
||||
|
||||
typedef struct {
|
||||
target_ulong base;
|
||||
target_ulong base_tag;
|
||||
uint32_t index;
|
||||
uint32_t size;
|
||||
bool is_readable;
|
||||
bool is_writable;
|
||||
} E2KStackState, E2KPsState, E2KPcsState;
|
||||
|
||||
typedef struct {
|
||||
int16_t index;
|
||||
uint16_t fx_index;
|
||||
uint16_t t_index;
|
||||
bool fx;
|
||||
} E2KPshtpState;
|
||||
|
||||
typedef struct {
|
||||
int32_t base;
|
||||
uint32_t size;
|
||||
uint32_t psize;
|
||||
bool fx;
|
||||
} E2KWdState;
|
||||
|
||||
typedef enum {
|
||||
AASR_NULL = 0,
|
||||
AASR_READY = 1,
|
||||
AASR_ACTIVE = 3,
|
||||
AASR_STOPPED = 5,
|
||||
} E2KAasrState;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t unused : 5;
|
||||
uint32_t stb : 1;
|
||||
uint32_t iab : 1;
|
||||
uint32_t lds : 3;
|
||||
};
|
||||
uint32_t raw;
|
||||
} E2KAasr;
|
||||
|
||||
typedef enum {
|
||||
AAD_TAG_UNV = 0,
|
||||
AAD_TAG_UDT = 1,
|
||||
AAD_TAG_UET = 2,
|
||||
AAD_TAG_UAP = 4,
|
||||
AAD_TAG_USAP = 5,
|
||||
AAD_TAG_UDS = 6,
|
||||
} E2KAadTag;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint64_t base : 48; /* 48:0 */
|
||||
uint64_t unused1 : 6; /* 53:48 */
|
||||
uint64_t tag : 3; /* 56:54 */
|
||||
uint64_t mb : 1; /* 57 */
|
||||
uint64_t ed : 1; /* 58 */
|
||||
uint64_t rw : 2; /* 60:59 */
|
||||
uint64_t unused2 : 3; /* 63:60 */
|
||||
};
|
||||
uint64_t lo;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
uint64_t unused3 : 32;
|
||||
uint64_t size : 32;
|
||||
};
|
||||
uint64_t hi;
|
||||
};
|
||||
} E2KAad;
|
||||
|
||||
typedef enum {
|
||||
AALDA_EXC_EIO = 1,
|
||||
AALDA_EXC_EPM = 2,
|
||||
AALDA_EXC_EPMSI = 3,
|
||||
} E2KAaldaExc;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t exc: 2;
|
||||
uint8_t cincr: 1;
|
||||
uint8_t unused1: 1;
|
||||
uint8_t root: 1;
|
||||
uint8_t unused2: 3;
|
||||
};
|
||||
uint8_t raw;
|
||||
} E2KAalda;
|
||||
|
||||
/* AAU prefetch instruction */
|
||||
typedef union {
|
||||
struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t abs: 5;
|
||||
uint32_t asz: 3;
|
||||
|
||||
/* version >= 2 || si == 0 */
|
||||
uint32_t ind: 4;
|
||||
uint32_t incr: 3;
|
||||
|
||||
uint32_t aad: 5;
|
||||
uint32_t mrng: 5;
|
||||
uint32_t fmt: 3;
|
||||
uint32_t dcd: 2;
|
||||
uint32_t si: 1;
|
||||
uint32_t ct: 1;
|
||||
};
|
||||
struct {
|
||||
uint32_t unused1: 8;
|
||||
|
||||
/* version <= 1 && si == 1 */
|
||||
uint32_t area: 5;
|
||||
uint32_t am: 1;
|
||||
uint32_t be: 1;
|
||||
|
||||
uint32_t unused2: 16;
|
||||
uint32_t dpl: 1;
|
||||
};
|
||||
uint32_t lo;
|
||||
};
|
||||
union {
|
||||
uint32_t disp;
|
||||
uint32_t hi;
|
||||
};
|
||||
};
|
||||
uint64_t raw;
|
||||
} E2KAauPrefInstr;
|
||||
|
||||
typedef struct {
|
||||
E2KAauPrefInstr pi; /* prefetch instr */
|
||||
uint32_t cdi; /* current data index */
|
||||
uint32_t ldi; /* loaded data index */
|
||||
} E2KAauAreaState;
|
||||
|
||||
typedef struct {
|
||||
E2KAauAreaState area[32];
|
||||
} E2KAauPrefState;
|
||||
|
||||
typedef struct {
|
||||
E2KAasr sr;
|
||||
uint32_t fstr;
|
||||
uint64_t ldm;
|
||||
uint64_t ldv;
|
||||
uint32_t stis[16];
|
||||
uint32_t sti_tags;
|
||||
uint32_t incrs[8];
|
||||
uint32_t incr_tags;
|
||||
uint32_t inds[16];
|
||||
uint32_t ind_tags;
|
||||
E2KAad ds[32];
|
||||
E2KAalda lda[64];
|
||||
E2KAauPrefState pl, pr;
|
||||
} E2KAauState;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint64_t base: 48; /* 47:0 */
|
||||
uint64_t unused1: 6; /* 53:48 */
|
||||
uint64_t tag: 3; /* 56:54 */
|
||||
uint64_t opc: 2; /* 58:57 */
|
||||
uint64_t ipd: 2; /* 60:59 */
|
||||
uint64_t unused2: 3; /* 63:61 */
|
||||
};
|
||||
uint64_t raw;
|
||||
} E2KCtpr;
|
||||
|
||||
/* E2K FPU regs are compatible with x87 regs */
|
||||
#define FPSR_IE (1U << 0) /* invalid operation */
|
||||
#define FPSR_DE (1U << 1) /* denormalized operand */
|
||||
#define FPSR_ZE (1U << 2) /* zero divide */
|
||||
#define FPSR_OE (1U << 3) /* overflow */
|
||||
#define FPSR_UE (1U << 4) /* underflow */
|
||||
#define FPSR_PE (1U << 5) /* precision */
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t ef : 6; /* exception flags */
|
||||
uint32_t sf : 1; /* stack fault, unused */
|
||||
uint32_t es : 1; /* error summary status */
|
||||
uint32_t _c0 : 1; /* condition code 0, unused */
|
||||
uint32_t c1 : 1; /* condition code 1 */
|
||||
uint32_t _c2 : 1; /* condition code 2, unused */
|
||||
uint32_t top: 3; /* stack top, unused */
|
||||
uint32_t _c3 : 1; /* condition code 3, unused */
|
||||
uint32_t b : 1; /* fpu busy */
|
||||
};
|
||||
uint32_t raw;
|
||||
} E2KFpsrState;
|
||||
|
||||
#define FPCR_EM (FPSR_IE|FPSR_DE|FPSR_ZE|FPSR_OE|FPSR_UE|FPSR_PE)
|
||||
|
||||
#define FPCR_PC_SP 0 /* single precision (32 bits) */
|
||||
#define FPCR_PC_RESERVED 1 /* reserved */
|
||||
#define FPCR_PC_DP 2 /* double precision (64 bits) */
|
||||
#define FPCR_PC_XP 3 /* extended precision (80 bits) */
|
||||
|
||||
#define FPCR_RC_NEAR 0 /* round to nearest */
|
||||
#define FPCR_RC_DOWN 1 /* round down */
|
||||
#define FPCR_RC_UP 2 /* round up */
|
||||
#define FPCR_RC_CHOP 3 /* round toward zero (truncate) */
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t em : 6; /* masks flags */
|
||||
uint32_t _one : 1; /* reserved, always 1 (?) */
|
||||
uint32_t _zero0 : 1; /* reserved, always 0 */
|
||||
uint32_t pc : 2; /* precision control */
|
||||
uint32_t rc : 2; /* rounding control */
|
||||
uint32_t ic : 1; /* infinity control */
|
||||
uint32_t _zero1 : 3; /* reserved */
|
||||
};
|
||||
uint32_t raw;
|
||||
} E2KFpcrState;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint64_t lo;
|
||||
struct {
|
||||
uint64_t base: 48;
|
||||
uint64_t unused1: 10;
|
||||
uint64_t protected: 1;
|
||||
uint64_t read: 1;
|
||||
uint64_t write: 1;
|
||||
uint64_t unsued2: 3;
|
||||
};
|
||||
};
|
||||
union {
|
||||
uint64_t hi;
|
||||
struct {
|
||||
uint64_t curptr: 32;
|
||||
uint64_t size: 32;
|
||||
};
|
||||
};
|
||||
} E2KUserStackDesc;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint64_t l1col: 2; /* 1:0 */
|
||||
uint64_t l1msb: 2; /* 3:2 */
|
||||
uint64_t word: 9; /* 12:4 */
|
||||
uint64_t page: 28; /* 40:13 */
|
||||
uint64_t mask: 8; /* 48:41 */
|
||||
uint64_t rg: 8; /* 56:49 */
|
||||
uint64_t quadro: 1; /* 57 */
|
||||
uint64_t val: 1; /* 58 */
|
||||
uint64_t unused: 5; /* 63:59 */
|
||||
};
|
||||
uint64_t raw;
|
||||
} E2KDamEntry;
|
||||
|
||||
typedef union {
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
floatx80 f80;
|
||||
uint8_t u8v[16];
|
||||
uint16_t u16v[8];
|
||||
uint32_t u32v[4];
|
||||
uint64_t u64v[2];
|
||||
int8_t i8v[16];
|
||||
int16_t i16v[8];
|
||||
int32_t i32v[4];
|
||||
int64_t i64v[2];
|
||||
} E2KReg;
|
||||
|
||||
typedef struct {
|
||||
/* register file */
|
||||
uint8_t tags[E2K_REG_COUNT]; /* registers tags */
|
||||
uint64_t regs[E2K_REG_COUNT]; /* low parts of registers */
|
||||
uint64_t xregs[E2K_REG_COUNT]; /* high parts of registers */
|
||||
uint64_t pregs; /* predicate file */
|
||||
target_ulong ip; /* instruction address */
|
||||
|
||||
/* temporaries for FX/SIMD ops */
|
||||
E2KReg t0, t1, t2, t3;
|
||||
|
||||
/* DAM */
|
||||
E2KDamEntry dam[32];
|
||||
|
||||
/* procedure chain info */
|
||||
uint64_t cr0_lo;
|
||||
uint64_t cr0_hi;
|
||||
E2KCr1State cr1;
|
||||
|
||||
/* Procedure chain info = cr0_lo, cr0_hi, cr1_lo, cr1_hi */
|
||||
E2KPcsState pcsp;
|
||||
uint64_t pcshtp;
|
||||
|
||||
/* Procedure stack pointer (for regs) */
|
||||
E2KPsState psp;
|
||||
E2KPshtpState pshtp;
|
||||
|
||||
E2KWdState wd;
|
||||
E2KBnState bn;
|
||||
E2KBpState bp;
|
||||
|
||||
uint64_t lsr; /* loop status register */
|
||||
|
||||
uint64_t sbr;
|
||||
E2KUserStackDesc usd;
|
||||
|
||||
/* control registers */
|
||||
E2KCtpr ctprs[3]; // Control Transfer Preparation Register (CTPR)
|
||||
target_ulong ct_cond;
|
||||
|
||||
target_ulong nip; /* next instruction address */
|
||||
|
||||
uint64_t upsr;
|
||||
uint64_t idr;
|
||||
|
||||
uint32_t pfpfr; // Packed Floating Point Flag Register (PFPFR)
|
||||
E2KFpsrState fpsr; // Floating point state register (FPSR)
|
||||
E2KFpcrState fpcr; // Floating point control register (FPCR)
|
||||
|
||||
float_status fp_status;
|
||||
|
||||
E2KAauState aau;
|
||||
|
||||
int interrupt_index;
|
||||
|
||||
/* internal use */
|
||||
uint32_t is_bp; /* breakpoint flag */
|
||||
int syscall_wbs; // FIXME: temp for syscall
|
||||
/* zeroing upper register half for 32-bit instructions */
|
||||
uint32_t wdbl;
|
||||
|
||||
/* Fields up to this point are cleared by a CPU reset */
|
||||
struct {} end_reset_fields;
|
||||
|
||||
uint32_t version;
|
||||
|
||||
struct e2k_def_t def;
|
||||
} CPUE2KState;
|
||||
|
||||
/**
|
||||
* E2KCPU:
|
||||
* @env: #CPUE2KState
|
||||
*
|
||||
* An Elbrus CPU.
|
||||
*/
|
||||
struct E2KCPU {
|
||||
/*< private >*/
|
||||
CPUState parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
CPUNegativeOffsetState neg;
|
||||
CPUE2KState env;
|
||||
};
|
||||
|
||||
static inline void cpu_get_tb_cpu_state(CPUE2KState *env, target_ulong *pc,
|
||||
target_ulong *cs_base, uint32_t *pflags)
|
||||
{
|
||||
*pc = env->ip;
|
||||
*cs_base = 0;
|
||||
*pflags = MMU_USER_IDX;
|
||||
}
|
||||
|
||||
void e2k_cpu_do_interrupt(CPUState *cs);
|
||||
void e2k_cpu_list(void);
|
||||
int e2k_cpu_signal_handler(int host_signum, void *pinfo, void *puc);
|
||||
int e2k_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n);
|
||||
int e2k_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n);
|
||||
void e2k_break_save_state(CPUE2KState *env);
|
||||
bool e2k_cpu_tlb_fill(CPUState *cpu, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
void e2k_update_fp_status(CPUE2KState *env);
|
||||
|
||||
#define cpu_signal_handler e2k_cpu_signal_handler
|
||||
#define cpu_list e2k_cpu_list
|
||||
|
||||
#define e2k_wrap_reg_index(i) (E2K_NR_COUNT + i) % E2K_NR_COUNT
|
||||
|
||||
static inline uint64_t e2k_state_desc_lo(E2KStackState *desc)
|
||||
{
|
||||
uint64_t lo = 0;
|
||||
|
||||
lo = deposit64(lo, DESC_LO_BASE_OFF, DESC_LO_BASE_LEN,
|
||||
(uint64_t) desc->base);
|
||||
lo = deposit64(lo, DESC_LO_READ_OFF, 1, desc->is_readable);
|
||||
lo = deposit64(lo, DESC_LO_WRITE_OFF, 1, desc->is_writable);
|
||||
|
||||
return lo;
|
||||
}
|
||||
|
||||
static inline uint64_t e2k_state_desc_hi(E2KStackState *env)
|
||||
{
|
||||
uint64_t hi = 0;
|
||||
|
||||
hi = deposit64(hi, DESC_HI_IND_OFF, DESC_HI_IND_LEN, env->index);
|
||||
hi = deposit64(hi, DESC_HI_SIZE_OFF, DESC_HI_SIZE_OFF, env->size);
|
||||
|
||||
return hi;
|
||||
}
|
||||
|
||||
#define e2k_state_pcsp_lo(env) e2k_state_desc_lo(&(env)->pcsp)
|
||||
#define e2k_state_pcsp_hi(env) e2k_state_desc_hi(&(env)->pcsp)
|
||||
#define e2k_state_psp_lo(env) e2k_state_desc_lo(&(env)->psp)
|
||||
#define e2k_state_psp_hi(env) e2k_state_desc_hi(&(env)->psp)
|
||||
|
||||
static inline uint64_t e2k_state_pshtp(CPUE2KState *env)
|
||||
{
|
||||
E2KPshtpState *s = &env->pshtp;
|
||||
uint64_t ret = 0;
|
||||
|
||||
ret = deposit64(ret, PSHTP_IND_OFF, PSHTP_IND_LEN, s->index);
|
||||
ret = deposit64(ret, PSHTP_FXIND_OFF, PSHTP_FXIND_LEN, s->fx_index);
|
||||
ret = deposit64(ret, PSHTP_TIND_OFF, PSHTP_TIND_LEN, s->t_index);
|
||||
ret = deposit64(ret, PSHTP_FX_OFF, 1, s->fx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint64_t e2k_state_wd(CPUE2KState *env)
|
||||
{
|
||||
E2KWdState *wd = &env->wd;
|
||||
uint64_t ret = 0;
|
||||
|
||||
ret = deposit64(ret, WD_BASE_OFF, WD_BASE_LEN, wd->base * 8);
|
||||
ret = deposit64(ret, WD_SIZE_OFF, WD_SIZE_LEN, wd->size * 8);
|
||||
ret = deposit64(ret, WD_PSIZE_OFF, WD_PSIZE_LEN, wd->psize * 8);
|
||||
ret = deposit64(ret, WD_FX_OFF, 1, wd->fx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t e2k_state_br(CPUE2KState *env)
|
||||
{
|
||||
E2KBnState *bn = &env->bn;
|
||||
E2KBpState *bp = &env->bp;
|
||||
uint32_t ret = 0;
|
||||
|
||||
ret = deposit32(ret, BR_RBS_OFF, BR_RBS_LEN, bn->base / 2);
|
||||
ret = deposit32(ret, BR_RSZ_OFF, BR_RSZ_LEN, bn->size / 2 - 1);
|
||||
ret = deposit32(ret, BR_RCUR_OFF, BR_RCUR_LEN, bn->cur / 2);
|
||||
|
||||
ret = deposit32(ret, BR_PSZ_OFF, BR_PSZ_LEN, bp->size);
|
||||
ret = deposit32(ret, BR_PCUR_OFF, BR_PCUR_LEN, bp->cur);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void e2k_state_br_set(CPUE2KState *env, uint32_t br)
|
||||
{
|
||||
E2KBnState *bn = &env->bn;
|
||||
E2KBpState *bp = &env->bp;
|
||||
|
||||
bn->base = extract32(br, BR_RBS_OFF, BR_RBS_LEN) * 2;
|
||||
bn->size = extract32(br, BR_RSZ_OFF, BR_RSZ_LEN) * 2 + 2;
|
||||
bn->cur = extract32(br, BR_RCUR_OFF, BR_RCUR_LEN) * 2;
|
||||
|
||||
bp->size = extract32(br, BR_PSZ_OFF, BR_PSZ_LEN);
|
||||
bp->cur = extract32(br, BR_PCUR_OFF, BR_PCUR_LEN);
|
||||
}
|
||||
|
||||
typedef CPUE2KState CPUArchState;
|
||||
typedef E2KCPU ArchCPU;
|
||||
|
||||
#include "exec/cpu-all.h"
|
||||
|
||||
#endif
|
274
target/e2k/gdbstub.c
Normal file
274
target/e2k/gdbstub.c
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Elbrus 2000 gdb server stub
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||
* Copyright (c) 2020 Alibek Omarov
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/gdbstub.h"
|
||||
|
||||
/* TODO: reverse engineer e2k-linux-gdb register ids */
|
||||
|
||||
int e2k_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
// CPUClass *cc = CPU_GET_CLASS(cs);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
|
||||
switch (n) {
|
||||
case 0: return gdb_get_reg64(mem_buf, 0); // unk
|
||||
case 1: return gdb_get_reg64(mem_buf, 0); // b0
|
||||
case 2: return gdb_get_reg64(mem_buf, 0); // b1
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (3 <= n && n < 35) {
|
||||
return gdb_get_reg64(mem_buf, env->regs[E2K_NR_COUNT + n - 3]);
|
||||
}
|
||||
|
||||
switch (n) {
|
||||
case 35: return gdb_get_reg64(mem_buf, 0); // psr
|
||||
case 36: return gdb_get_reg64(mem_buf, env->upsr); // upsr
|
||||
case 37: return gdb_get_reg64(mem_buf, 0); // oscud_lo
|
||||
case 38: return gdb_get_reg64(mem_buf, 0); // oscud_hi
|
||||
case 39: return gdb_get_reg64(mem_buf, 0); // osgd_lo
|
||||
case 40: return gdb_get_reg64(mem_buf, 0); // osgd_hi
|
||||
case 41: return gdb_get_reg64(mem_buf, 0); // osem
|
||||
case 42: return gdb_get_reg64(mem_buf, 0); // osr0
|
||||
case 43: return gdb_get_reg64(mem_buf, 0); // pfpfr
|
||||
case 44: return gdb_get_reg64(mem_buf, 0); // fpcr
|
||||
case 45: return gdb_get_reg64(mem_buf, 0); // fpsr
|
||||
case 46: return gdb_get_reg64(mem_buf, 0); // usbr
|
||||
case 47: return gdb_get_reg64(mem_buf, env->usd.lo); // usd_lo
|
||||
case 48: return gdb_get_reg64(mem_buf, env->usd.hi); // usd_hi
|
||||
case 49: return gdb_get_reg64(mem_buf, e2k_state_psp_lo(env)); // psp_lo
|
||||
case 50: return gdb_get_reg64(mem_buf, e2k_state_psp_hi(env)); // psp_hi
|
||||
case 51: return gdb_get_reg64(mem_buf, e2k_state_pshtp(env)); // pshtp
|
||||
case 52: return gdb_get_reg64(mem_buf, env->pregs); // pregs
|
||||
case 53: return gdb_get_reg64(mem_buf, env->ip); // ip
|
||||
case 54: return gdb_get_reg64(mem_buf, env->cr1.lo); // cr1_lo
|
||||
case 55: return gdb_get_reg64(mem_buf, env->cr1.hi); // cr1_hi
|
||||
case 56: return gdb_get_reg64(mem_buf, 0); // cwd
|
||||
case 57: return gdb_get_reg64(mem_buf, e2k_state_pcsp_lo(env)); // pcsp_lo
|
||||
case 58: return gdb_get_reg64(mem_buf, e2k_state_pcsp_hi(env)); // pcsp_hi
|
||||
case 59: return gdb_get_reg64(mem_buf, env->pcshtp); // pcshtp
|
||||
case 60: return gdb_get_reg64(mem_buf, 0); // cud_lo
|
||||
case 61: return gdb_get_reg64(mem_buf, 0); // cud_hi
|
||||
case 62: return gdb_get_reg64(mem_buf, 0); // gd_lo
|
||||
case 63: return gdb_get_reg64(mem_buf, 0); // gd_hi
|
||||
case 64: return gdb_get_reg64(mem_buf, 0); // cs_lo
|
||||
case 65: return gdb_get_reg64(mem_buf, 0); // cs_hi
|
||||
case 66: return gdb_get_reg64(mem_buf, 0); // ds_lo
|
||||
case 67: return gdb_get_reg64(mem_buf, 0); // ds_hi
|
||||
case 68: return gdb_get_reg64(mem_buf, 0); // es_lo
|
||||
case 69: return gdb_get_reg64(mem_buf, 0); // es_hi
|
||||
case 70: return gdb_get_reg64(mem_buf, 0); // fs_lo
|
||||
case 71: return gdb_get_reg64(mem_buf, 0); // fs_hi
|
||||
case 72: return gdb_get_reg64(mem_buf, 0); // gs_lo
|
||||
case 73: return gdb_get_reg64(mem_buf, 0); // gs_hi
|
||||
case 74: return gdb_get_reg64(mem_buf, 0); // ss_lo
|
||||
case 75: return gdb_get_reg64(mem_buf, 0); // ss_hi
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (76 <= n && n < 140) {
|
||||
int idx = (n - 76) >> 1;
|
||||
if (n & 1) {
|
||||
return gdb_get_reg64(mem_buf, env->aau.ds[idx].hi); // addN_hi
|
||||
} else {
|
||||
return gdb_get_reg64(mem_buf, env->aau.ds[idx].lo); // addN_lo
|
||||
}
|
||||
}
|
||||
|
||||
if (140 <= n && n < 156) {
|
||||
return gdb_get_reg64(mem_buf, env->aau.inds[n - 140]); // aaindN
|
||||
}
|
||||
|
||||
if (156 <= n && n < 164) {
|
||||
return gdb_get_reg64(mem_buf, env->aau.incrs[n - 156]); // aaincrN
|
||||
}
|
||||
|
||||
if (164 <= n && n < 196) {
|
||||
return gdb_get_reg64(mem_buf, env->aau.pl.area[n - 164].ldi); // aaldiN
|
||||
}
|
||||
|
||||
if (196 <= n && n < 228) {
|
||||
return gdb_get_reg64(mem_buf, env->aau.pr.area[n - 196].ldi); // aaldiN
|
||||
}
|
||||
|
||||
if (n == 228) {
|
||||
return gdb_get_reg64(mem_buf, env->aau.ldv); // aaldv
|
||||
}
|
||||
|
||||
if (229 <= n && n < 293) {
|
||||
return gdb_get_reg64(mem_buf, env->aau.lda[n - 229].raw); // aaldaN
|
||||
}
|
||||
|
||||
switch (n) {
|
||||
case 293: return gdb_get_reg64(mem_buf, env->aau.ldm); // aaldm
|
||||
case 294: return gdb_get_reg64(mem_buf, env->aau.sr.raw); // aasr
|
||||
case 295: return gdb_get_reg64(mem_buf, env->aau.fstr); // aafstr
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (296 <= n && n < 312) {
|
||||
return gdb_get_reg64(mem_buf, env->aau.stis[n - 296]); // aastiN
|
||||
}
|
||||
|
||||
switch (n) {
|
||||
case 312: return gdb_get_reg64(mem_buf, cpu_get_host_ticks()); // clkr
|
||||
case 313: return gdb_get_reg64(mem_buf, 0); // dibcr
|
||||
case 314: return gdb_get_reg64(mem_buf, 0); // ddbcr
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (315 <= n && n < 319) {
|
||||
return gdb_get_reg64(mem_buf, 0); // dibarN
|
||||
}
|
||||
|
||||
if (319 <= n && n < 323) {
|
||||
return gdb_get_reg64(mem_buf, 0); // ddbarN
|
||||
}
|
||||
|
||||
switch (n) {
|
||||
case 323: return gdb_get_reg64(mem_buf, 0); // dimcr
|
||||
case 324: return gdb_get_reg64(mem_buf, 0); // ddmcr
|
||||
case 325: return gdb_get_reg64(mem_buf, 0); // dimar0
|
||||
case 326: return gdb_get_reg64(mem_buf, 0); // dimar1
|
||||
case 327: return gdb_get_reg64(mem_buf, 0); // ddmar0
|
||||
case 328: return gdb_get_reg64(mem_buf, 0); // ddmar1
|
||||
case 329: return gdb_get_reg64(mem_buf, 0); // dibsr
|
||||
case 330: return gdb_get_reg64(mem_buf, 0); // ddbsr
|
||||
case 331: return gdb_get_reg64(mem_buf, 0); // dtcr
|
||||
case 332: return gdb_get_reg64(mem_buf, 0); // dtarf
|
||||
case 333: return gdb_get_reg64(mem_buf, 0); // dtart
|
||||
case 334: return gdb_get_reg64(mem_buf, e2k_state_wd(env)); // wd
|
||||
case 335: return gdb_get_reg64(mem_buf, 0); // unk
|
||||
case 336: return gdb_get_reg64(mem_buf, 0); // bgr
|
||||
case 337: return gdb_get_reg64(mem_buf, 0); // unk
|
||||
case 338: return gdb_get_reg64(mem_buf, 0); // nip
|
||||
case 339: return gdb_get_reg64(mem_buf, env->ctprs[0].raw); // ctpr1
|
||||
case 340: return gdb_get_reg64(mem_buf, env->ctprs[1].raw); // ctpr2
|
||||
case 341: return gdb_get_reg64(mem_buf, env->ctprs[2].raw); // ctpr3
|
||||
case 342: return gdb_get_reg64(mem_buf, 0); // eir
|
||||
case 343: return gdb_get_reg64(mem_buf, 0); // tr
|
||||
case 344: return gdb_get_reg64(mem_buf, 0); // cutd
|
||||
case 345: return gdb_get_reg64(mem_buf, 0); // cuir
|
||||
case 346: return gdb_get_reg64(mem_buf, 0); // tsd
|
||||
case 347: return gdb_get_reg64(mem_buf, env->lsr); // lsr
|
||||
case 348: return gdb_get_reg64(mem_buf, env->lsr & LSR_ILCR_MASK); // ilcr
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (349 <= n && n < 356) {
|
||||
return gdb_get_reg64(mem_buf, 0); // unk
|
||||
}
|
||||
|
||||
if (356 <= n && n < 360) {
|
||||
return gdb_get_reg64(mem_buf, 0); // gN tags (tag len is 1 byte)
|
||||
}
|
||||
|
||||
if (360 <= n && n < 368) {
|
||||
return gdb_get_reg64(mem_buf, 0); // xgN
|
||||
}
|
||||
|
||||
if (n == 368) {
|
||||
return gdb_get_reg64(mem_buf, 0); // rpr_hi
|
||||
}
|
||||
|
||||
if (n == 369) {
|
||||
return gdb_get_reg64(mem_buf, 0); // rpr_lo
|
||||
}
|
||||
|
||||
if (370 <= n && n < 389) {
|
||||
return gdb_get_reg64(mem_buf, 0); // tir_N_lo
|
||||
}
|
||||
|
||||
if (389 <= n && n < 408) {
|
||||
return gdb_get_reg64(mem_buf, 0); // tir_N_hi
|
||||
}
|
||||
|
||||
if (408 <= n && n < 418) {
|
||||
return gdb_get_reg64(mem_buf, 0); // trap_cell_addr_N
|
||||
}
|
||||
|
||||
if (418 <= n && n < 428) {
|
||||
return gdb_get_reg64(mem_buf, 0); // trap_cell_val_N
|
||||
}
|
||||
|
||||
if (n == 428) {
|
||||
return gdb_get_reg64(mem_buf, 0); // trap_cell_tag_N [0, 7)
|
||||
}
|
||||
|
||||
if (n == 429) {
|
||||
return gdb_get_reg64(mem_buf, 0); // trap_cell_tag_N [8, 9)
|
||||
}
|
||||
|
||||
if (430 <= n && n < 440) {
|
||||
return gdb_get_reg64(mem_buf, 0); // trap_cell_info_N
|
||||
}
|
||||
|
||||
if (440 <= n && n < 472) {
|
||||
return gdb_get_reg64(mem_buf, env->dam[n - 440].raw); // dam_N
|
||||
}
|
||||
|
||||
if (472 <= n && n < 504) {
|
||||
return gdb_get_reg64(mem_buf, 0); // sbbp_N
|
||||
}
|
||||
|
||||
if (504 <= n && n < 552) {
|
||||
return gdb_get_reg64(mem_buf, 0); // mlt_N (3 regs)
|
||||
}
|
||||
|
||||
if (n == 552) {
|
||||
return gdb_get_reg64(mem_buf, env->pcsp.base); // pcsp_base
|
||||
}
|
||||
|
||||
if (n == 553) {
|
||||
return gdb_get_reg64(mem_buf, env->psp.base); // psp_base
|
||||
}
|
||||
|
||||
if (554 <= n && n < 573) {
|
||||
return gdb_get_reg64(mem_buf, 0); // unk
|
||||
}
|
||||
|
||||
if (n == 573) {
|
||||
return gdb_get_reg32(mem_buf, 0); // unk
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s: unknown register %d\n", __FUNCTION__, n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int e2k_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
{
|
||||
// E2KCPU *cpu = E2K_CPU(cs);
|
||||
// CPUClass *cc = CPU_GET_CLASS(cs);
|
||||
// CPUE2KState *env = &cpu->env;
|
||||
|
||||
fprintf(stderr, "%s: unknown register %d\n", __FUNCTION__, n);
|
||||
|
||||
// TODO: e2k_cpu_gdb_write_register
|
||||
return 0;
|
||||
}
|
304
target/e2k/helper.c
Normal file
304
target/e2k/helper.c
Normal file
@ -0,0 +1,304 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "translate.h"
|
||||
|
||||
#define PS_FORCE_FX true
|
||||
|
||||
static inline void reset_ctprs(CPUE2KState *env)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
env->ctprs[i].tag = CTPR_TAG_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void stack_push(CPUE2KState *env, E2KStackState *s, uint64_t value)
|
||||
{
|
||||
if ((s->index + 8) > s->size) {
|
||||
helper_raise_exception(env, E2K_EXCP_MAPERR);
|
||||
return;
|
||||
}
|
||||
|
||||
cpu_stq_le_data_ra(env, s->base + s->index, value, GETPC());
|
||||
s->index += 8;
|
||||
}
|
||||
|
||||
static inline uint64_t stack_pop(CPUE2KState *env, E2KStackState *s)
|
||||
{
|
||||
if (s->index < 8) {
|
||||
helper_raise_exception(env, E2K_EXCP_MAPERR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s->index -= 8;
|
||||
return cpu_ldq_le_data(env, s->base + s->index);
|
||||
}
|
||||
|
||||
#define pcs_push(env, value) stack_push(env, &env->pcsp, (value))
|
||||
#define pcs_pop(env) stack_pop(env, &env->pcsp)
|
||||
|
||||
static inline void ps_push(CPUE2KState *env, uint64_t value, uint8_t tag)
|
||||
{
|
||||
cpu_stb_data(env, env->psp.base_tag + env->psp.index / 8, tag);
|
||||
stack_push(env, &env->psp, value);
|
||||
}
|
||||
|
||||
static inline uint64_t ps_pop(CPUE2KState *env, uint8_t *ret_tag)
|
||||
{
|
||||
uint64_t ret = stack_pop(env, &env->psp);
|
||||
if (ret_tag != NULL) {
|
||||
*ret_tag = cpu_ldub_data(env, env->psp.base_tag + env->psp.index / 8);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void proc_chain_save(CPUE2KState *env, int wbs)
|
||||
{
|
||||
pcs_push(env, env->cr0_lo);
|
||||
pcs_push(env, env->cr0_hi);
|
||||
pcs_push(env, env->cr1.lo);
|
||||
pcs_push(env, env->cr1.hi);
|
||||
|
||||
env->pshtp.index += wbs * 2;
|
||||
|
||||
env->cr0_lo = env->pregs;
|
||||
env->cr0_hi = env->ip;
|
||||
env->cr1.wbs = wbs;
|
||||
env->cr1.wpsz = env->wd.psize / 2;
|
||||
env->cr1.wfx = env->wd.fx;
|
||||
env->cr1.br = e2k_state_br(env);
|
||||
env->cr1.ussz = env->usd.size >> 4;
|
||||
|
||||
env->wd.fx = true;
|
||||
env->wd.base = e2k_wrap_reg_index(env->wd.base + wbs * 2);
|
||||
env->wd.size -= wbs * 2;
|
||||
env->wd.psize = env->wd.size;
|
||||
}
|
||||
|
||||
static inline void proc_chain_restore(CPUE2KState *env)
|
||||
{
|
||||
int wbs;
|
||||
|
||||
env->pregs = env->cr0_lo;
|
||||
env->ip = env->cr0_hi;
|
||||
wbs = env->cr1.wbs;
|
||||
e2k_state_br_set(env, env->cr1.br);
|
||||
env->wd.size = env->wd.psize + wbs * 2;
|
||||
env->wd.psize = env->cr1.wpsz * 2;
|
||||
env->wd.base = e2k_wrap_reg_index(env->wd.base - wbs * 2);
|
||||
env->wd.fx = env->cr1.wfx;
|
||||
env->wdbl = env->cr1.wdbl;
|
||||
env->usd.size = env->cr1.ussz << 4;
|
||||
env->usd.base = env->sbr - env->usd.size;
|
||||
|
||||
env->pshtp.index -= wbs * 2;
|
||||
|
||||
env->cr1.hi = pcs_pop(env);
|
||||
env->cr1.lo = pcs_pop(env);
|
||||
env->cr0_hi = pcs_pop(env);
|
||||
env->cr0_lo = pcs_pop(env);
|
||||
}
|
||||
|
||||
static inline void ps_spill(CPUE2KState *env, bool force, bool force_fx)
|
||||
{
|
||||
while (E2K_NR_COUNT < env->pshtp.index + env->wd.size ||
|
||||
(force && env->wd.size + env->pshtp.index))
|
||||
{
|
||||
int i = e2k_wrap_reg_index(env->wd.base - env->pshtp.index);
|
||||
ps_push(env, env->regs[i], env->tags[i]);
|
||||
ps_push(env, env->regs[i + 1], env->tags[i + 1]);
|
||||
|
||||
// TODO: push fx
|
||||
if (force_fx) {
|
||||
ps_push(env, env->xregs[i], 0);
|
||||
ps_push(env, env->xregs[i + 1], 0);
|
||||
}
|
||||
|
||||
env->regs[i] = 0;
|
||||
env->tags[i] = E2K_TAG_NON_NUMBER64;
|
||||
env->regs[i + 1] = 0;
|
||||
env->tags[i + 1] = E2K_TAG_NON_NUMBER64;
|
||||
|
||||
env->pshtp.index -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ps_fill(CPUE2KState *env, bool force_fx)
|
||||
{
|
||||
while(env->pshtp.index < 0) {
|
||||
env->pshtp.index += 2;
|
||||
int i = e2k_wrap_reg_index(env->wd.base - env->pshtp.index);
|
||||
if (force_fx) {
|
||||
env->xregs[i + 1] = ps_pop(env, NULL);
|
||||
env->xregs[i] = ps_pop(env, NULL);
|
||||
}
|
||||
env->regs[i + 1] = ps_pop(env, &env->tags[i + 1]);
|
||||
env->regs[i] = ps_pop(env, &env->tags[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void do_call(CPUE2KState *env, int wbs, target_ulong pc_next)
|
||||
{
|
||||
env->ip = pc_next;
|
||||
proc_chain_save(env, wbs);
|
||||
reset_ctprs(env);
|
||||
}
|
||||
|
||||
void helper_setwd(CPUE2KState *env, uint32_t lts)
|
||||
{
|
||||
int old_size = env->wd.size, size = extract32(lts, 5, 7) * 2;
|
||||
|
||||
if (size < env->wd.psize) {
|
||||
helper_raise_exception(env, E2K_EXCP_ILLOPN);
|
||||
return;
|
||||
}
|
||||
|
||||
env->wd.size = size;
|
||||
env->wd.fx = extract32(lts, 4, 1) == 0;
|
||||
|
||||
if (env->version >= 3) {
|
||||
bool dbl = extract32(lts, 3, 1);
|
||||
env->cr1.wdbl = dbl;
|
||||
env->wdbl = dbl;
|
||||
}
|
||||
|
||||
ps_spill(env, false, PS_FORCE_FX);
|
||||
|
||||
if (old_size < size) {
|
||||
unsigned int i, offset = env->wd.base + old_size;
|
||||
|
||||
for (i = 0; i < size - old_size; i++) {
|
||||
int idx = e2k_wrap_reg_index(offset + i);
|
||||
env->regs[idx] = 0;
|
||||
env->tags[idx] = E2K_TAG_NON_NUMBER64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t helper_prep_return(CPUE2KState *env, int ipd)
|
||||
{
|
||||
E2KCtpr ret = { 0 };
|
||||
|
||||
if (env->pcsp.index < 32) {
|
||||
helper_raise_exception(env, E2K_EXCP_MAPERR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret.base = env->cr0_hi;
|
||||
ret.tag = CTPR_TAG_RETURN;
|
||||
ret.ipd = ipd;
|
||||
|
||||
return ret.raw;
|
||||
}
|
||||
|
||||
void helper_return(CPUE2KState *env)
|
||||
{
|
||||
proc_chain_restore(env);
|
||||
ps_fill(env, PS_FORCE_FX);
|
||||
reset_ctprs(env);
|
||||
}
|
||||
|
||||
static inline void do_syscall(CPUE2KState *env, int call_wbs,
|
||||
target_ulong pc_next)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
env->ip = pc_next;
|
||||
env->syscall_wbs = call_wbs;
|
||||
reset_ctprs(env);
|
||||
|
||||
cs->exception_index = E2K_EXCP_SYSCALL;
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
void helper_call(CPUE2KState *env, uint64_t ctpr_raw, int call_wbs,
|
||||
target_ulong pc_next)
|
||||
{
|
||||
E2KCtpr ctpr = { .raw = ctpr_raw };
|
||||
|
||||
switch (ctpr.tag) {
|
||||
case CTPR_TAG_DISP:
|
||||
do_call(env, call_wbs, pc_next);
|
||||
env->ip = ctpr.base;
|
||||
break;
|
||||
case CTPR_TAG_SDISP:
|
||||
do_syscall(env, call_wbs, pc_next);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void helper_raise_exception(CPUE2KState *env, int tt)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
cs->exception_index = tt;
|
||||
|
||||
proc_chain_save(env, env->wd.size / 2);
|
||||
ps_spill(env, true, true);
|
||||
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
void HELPER(raise_exception_no_spill)(CPUE2KState *env, int tt)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
cs->exception_index = tt;
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
void e2k_break_save_state(CPUE2KState *env)
|
||||
{
|
||||
env->is_bp = true;
|
||||
proc_chain_save(env, env->wd.size / 2);
|
||||
ps_spill(env, true, true);
|
||||
}
|
||||
|
||||
void helper_break_restore_state(CPUE2KState *env)
|
||||
{
|
||||
env->is_bp = false;
|
||||
proc_chain_restore(env);
|
||||
ps_fill(env, true);
|
||||
}
|
||||
|
||||
bool e2k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
|
||||
proc_chain_save(env, env->wd.size / 2);
|
||||
ps_spill(env, true, true);
|
||||
|
||||
cs->exception_index = E2K_EXCP_MAPERR;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
void helper_debug(CPUE2KState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
e2k_break_save_state(env);
|
||||
cs->exception_index = EXCP_DEBUG;
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
void helper_debug_i32(uint32_t x)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "log %#x\n", x);
|
||||
}
|
||||
|
||||
void helper_debug_i64(uint64_t x)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "log %#lx\n", x);
|
||||
}
|
||||
|
||||
void helper_debug_ptr(void *x)
|
||||
{
|
||||
qemu_log_mask(LOG_UNIMP, "log %p\n", x);
|
||||
}
|
87
target/e2k/helper.h
Normal file
87
target/e2k/helper.h
Normal file
@ -0,0 +1,87 @@
|
||||
#define dh_alias_Reg ptr
|
||||
#define dh_alias_f80 ptr
|
||||
#define dh_ctype_Reg E2KReg *
|
||||
#define dh_ctype_f80 floatx80 *
|
||||
#define dh_is_signed_Reg dh_is_signed_ptr
|
||||
#define dh_is_signed_f80 dh_is_signed_ptr
|
||||
|
||||
DEF_HELPER_2(raise_exception, noreturn, env, int)
|
||||
DEF_HELPER_2(raise_exception_no_spill, noreturn, env, int)
|
||||
DEF_HELPER_1(debug, void, env)
|
||||
DEF_HELPER_2(prep_return, i64, env, int)
|
||||
DEF_HELPER_1(return, void, env)
|
||||
DEF_HELPER_4(call, void, env, i64, int, tl)
|
||||
DEF_HELPER_2(sxt, i64, i64, i32)
|
||||
DEF_HELPER_1(debug_i32, void, i32)
|
||||
DEF_HELPER_1(debug_i64, void, i64)
|
||||
DEF_HELPER_1(debug_ptr, void, ptr)
|
||||
DEF_HELPER_2(state_reg_read_i64, i64, env, int)
|
||||
DEF_HELPER_2(state_reg_read_i32, i32, env, int)
|
||||
DEF_HELPER_3(state_reg_write_i64, void, env, int, i64)
|
||||
DEF_HELPER_3(state_reg_write_i32, void, env, int, i32)
|
||||
DEF_HELPER_2(getsp, i64, env, i32) /* FIXME: return tl? */
|
||||
DEF_HELPER_1(break_restore_state, void, env)
|
||||
DEF_HELPER_2(setwd, void, env, i32)
|
||||
DEF_HELPER_2(probe_read_access, int, env, tl)
|
||||
DEF_HELPER_2(probe_write_access, int, env, tl)
|
||||
DEF_HELPER_3(packed_shuffle_i64, i64, i64, i64, i64)
|
||||
DEF_HELPER_2(pcmpeqb, i64, i64, i64)
|
||||
DEF_HELPER_2(pminub, i64, i64, i64)
|
||||
DEF_HELPER_2(pminsh, i64, i64, i64)
|
||||
DEF_HELPER_2(pmaxub, i64, i64, i64)
|
||||
DEF_HELPER_2(pmaxsh, i64, i64, i64)
|
||||
DEF_HELPER_2(pmovmskb, i64, i64, i64)
|
||||
DEF_HELPER_1(aau_load_program, void, env)
|
||||
DEF_HELPER_3(mova_ptr, tl, env, int, int)
|
||||
DEF_HELPER_3(aau_am, void, env, int, int)
|
||||
DEF_HELPER_4(dam_lock_addr, void, env, i64, int, int)
|
||||
DEF_HELPER_4(dam_unlock_addr, int, env, i64, int, int)
|
||||
|
||||
#define DEF_HELPER_3_32_64(name) \
|
||||
DEF_HELPER_3(name##s, i32, env, i32, i32) \
|
||||
DEF_HELPER_3(name##d, i64, env, i64, i64)
|
||||
|
||||
DEF_HELPER_3_32_64(fadd)
|
||||
DEF_HELPER_3_32_64(fsub)
|
||||
DEF_HELPER_3_32_64(fmin)
|
||||
DEF_HELPER_3_32_64(fmax)
|
||||
DEF_HELPER_3_32_64(fmul)
|
||||
DEF_HELPER_3_32_64(fdiv)
|
||||
DEF_HELPER_3_32_64(fcmpeq)
|
||||
DEF_HELPER_3_32_64(fcmpneq)
|
||||
DEF_HELPER_3_32_64(fcmple)
|
||||
DEF_HELPER_3_32_64(fcmpnle)
|
||||
DEF_HELPER_3_32_64(fcmplt)
|
||||
DEF_HELPER_3_32_64(fcmpnlt)
|
||||
DEF_HELPER_3_32_64(fcmpuod)
|
||||
DEF_HELPER_3_32_64(fcmpod)
|
||||
#undef DEF_HELPER_3_32_64
|
||||
|
||||
DEF_HELPER_2(fstois, i32, env, i32)
|
||||
DEF_HELPER_2(istofs, i32, env, i32)
|
||||
DEF_HELPER_2(fstoistr, i32, env, i32)
|
||||
DEF_HELPER_3(fstofx, void, f80, env, i32)
|
||||
|
||||
DEF_HELPER_2(fdtoid, i64, env, i64)
|
||||
DEF_HELPER_2(idtofd, i64, env, i64)
|
||||
DEF_HELPER_2(fdtoidtr, i64, env, i64)
|
||||
DEF_HELPER_3(fdtofx, void, f80, env, i64)
|
||||
|
||||
DEF_HELPER_2(fstofd, i64, env, i32)
|
||||
DEF_HELPER_2(fstoid, i64, env, i32)
|
||||
DEF_HELPER_2(istofd, i64, env, i32)
|
||||
DEF_HELPER_2(fstoidtr, i64, env, i32)
|
||||
|
||||
DEF_HELPER_2(fdtofs, i32, env, i64)
|
||||
DEF_HELPER_2(fdtois, i32, env, i64)
|
||||
DEF_HELPER_2(idtofs, i32, env, i64)
|
||||
DEF_HELPER_2(fdtoistr, i32, env, i64)
|
||||
|
||||
DEF_HELPER_2(fxtofs, i32, env, f80)
|
||||
DEF_HELPER_2(fxtofd, i64, env, f80)
|
||||
|
||||
DEF_HELPER_3(fxaddxx, void, env, f80, f80)
|
||||
DEF_HELPER_3(fxsubxx, void, env, f80, f80)
|
||||
DEF_HELPER_3(fxrsubxx, void, env, f80, f80)
|
||||
DEF_HELPER_3(fxmulxx, void, env, f80, f80)
|
||||
DEF_HELPER_3(fxdivxx, void, env, f80, f80)
|
72
target/e2k/helper_aau.c
Normal file
72
target/e2k/helper_aau.c
Normal file
@ -0,0 +1,72 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/helper-proto.h"
|
||||
|
||||
static inline void init_prefetch_area(E2KAauAreaState *s, E2KAauPrefInstr pi,
|
||||
uint32_t *inds)
|
||||
{
|
||||
if (pi.fmt != 0) {
|
||||
s->pi = pi;
|
||||
s->ldi = 0;
|
||||
s->cdi = inds[pi.ind] & ~((1 << pi.fmt) - 1);
|
||||
} else {
|
||||
s->pi.raw = 0;
|
||||
s->ldi = 0;
|
||||
s->cdi = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void HELPER(aau_load_program)(CPUE2KState *env)
|
||||
{
|
||||
unsigned int i;
|
||||
E2KCtpr ctpr = env->ctprs[1];
|
||||
|
||||
if (ctpr.tag != CTPR_TAG_DISP || ctpr.opc != CTPR_OPC_LDISP) {
|
||||
helper_raise_exception(env, E2K_EXCP_ILLOPC);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
E2KAauPrefInstr l, r;
|
||||
size_t offset = i * 16;
|
||||
|
||||
l.raw = cpu_ldq_le_data(env, ctpr.base + offset);
|
||||
r.raw = cpu_ldq_le_data(env, ctpr.base + offset + 8);
|
||||
|
||||
init_prefetch_area(&env->aau.pl.area[i], l, env->aau.inds);
|
||||
init_prefetch_area(&env->aau.pr.area[i], r, env->aau.inds);
|
||||
|
||||
if (l.ct || r.ct) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
target_ulong HELPER(mova_ptr)(CPUE2KState *env, int chan, int area)
|
||||
{
|
||||
E2KAauPrefState *ps = chan < 2 ? &env->aau.pl : &env->aau.pr;
|
||||
E2KAauAreaState *as = &ps->area[area];
|
||||
E2KAauPrefInstr instr = as->pi;
|
||||
E2KAad aad = env->aau.ds[instr.aad];
|
||||
|
||||
return aad.base + as->cdi;
|
||||
}
|
||||
|
||||
void HELPER(aau_am)(CPUE2KState *env, int chan, int area)
|
||||
{
|
||||
E2KAauPrefState *ps = chan < 2 ? &env->aau.pl : &env->aau.pr;
|
||||
E2KAauAreaState *as = &ps->area[area];
|
||||
E2KAauPrefInstr instr = as->pi;
|
||||
uint32_t incr = env->aau.incrs[instr.incr];
|
||||
int size;
|
||||
|
||||
if (instr.fmt == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
size = 1 << (instr.fmt - 1);
|
||||
as->cdi += size * incr;
|
||||
}
|
183
target/e2k/helper_fpu.c
Normal file
183
target/e2k/helper_fpu.c
Normal file
@ -0,0 +1,183 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/helper-proto.h"
|
||||
|
||||
#define glue3(x, y, z) glue(glue(x, y), z)
|
||||
#define deref(x) *(x)
|
||||
|
||||
static inline void fpu_set_exception(CPUE2KState *env, int mask)
|
||||
{
|
||||
env->fpsr.ef |= mask;
|
||||
if (env->fpsr.ef & (~env->fpcr.em & FPCR_EM)) {
|
||||
env->fpsr.es = 1;
|
||||
env->fpsr.b = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint8_t save_exception_flags(CPUE2KState *env)
|
||||
{
|
||||
uint8_t old_flags = get_float_exception_flags(&env->fp_status);
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
return old_flags;
|
||||
}
|
||||
|
||||
static inline void merge_exception_flags(CPUE2KState *env, uint8_t old_flags)
|
||||
{
|
||||
uint8_t new_flags = get_float_exception_flags(&env->fp_status);
|
||||
float_raise(old_flags, &env->fp_status);
|
||||
fpu_set_exception(env,
|
||||
((new_flags & float_flag_invalid ? FPSR_IE : 0) |
|
||||
(new_flags & float_flag_divbyzero ? FPSR_ZE : 0) |
|
||||
(new_flags & float_flag_overflow ? FPSR_OE : 0) |
|
||||
(new_flags & float_flag_underflow ? FPSR_UE : 0) |
|
||||
(new_flags & float_flag_inexact ? FPSR_PE : 0) |
|
||||
(new_flags & float_flag_input_denormal ? FPSR_DE : 0)));
|
||||
}
|
||||
|
||||
void e2k_update_fp_status(CPUE2KState *env)
|
||||
{
|
||||
int x;
|
||||
|
||||
switch(env->fpcr.rc) {
|
||||
case FPCR_RC_UP:
|
||||
x = float_round_up;
|
||||
break;
|
||||
case FPCR_RC_DOWN:
|
||||
x = float_round_down;
|
||||
break;
|
||||
case FPCR_RC_CHOP:
|
||||
x = float_round_to_zero;
|
||||
break;
|
||||
case FPCR_RC_NEAR:
|
||||
x = float_round_nearest_even;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
set_float_rounding_mode(x, &env->fp_status);
|
||||
|
||||
switch(env->fpcr.pc) {
|
||||
case FPCR_PC_XP: x = 80; break;
|
||||
case FPCR_PC_DP: x = 64; break;
|
||||
case FPCR_PC_SP: x = 32; break;
|
||||
case FPCR_PC_RESERVED:
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
set_floatx80_rounding_precision(x, &env->fp_status);
|
||||
|
||||
}
|
||||
|
||||
#define GENERATE_SIMPLE_FLOAT2_OP(name, function, size) \
|
||||
uint##size##_t HELPER(name)(CPUE2KState *env, uint##size##_t x, uint##size##_t y) \
|
||||
{ \
|
||||
uint8_t old_flags = save_exception_flags(env); \
|
||||
float##size z = float##size##_##function (make_float##size (x), make_float##size (y), &env->fp_status); \
|
||||
merge_exception_flags(env, old_flags); \
|
||||
return float##size##_val(z); \
|
||||
}
|
||||
|
||||
#define GENERATE_CMP_FLOAT2_OP(name, function, expr, size) \
|
||||
uint##size##_t HELPER(name)(CPUE2KState *env, uint##size##_t x, uint##size##_t y) \
|
||||
{ \
|
||||
uint8_t old_flags = save_exception_flags(env); \
|
||||
uint##size##_t z = expr float##size##_##function (make_float##size (x), make_float##size (y), &env->fp_status); \
|
||||
merge_exception_flags(env, old_flags); \
|
||||
return z; \
|
||||
}
|
||||
|
||||
#define no_cvt(x) (x) // when function already returns in correct type
|
||||
|
||||
#define GENERATE_CVT_FLOAT1_OP(name, from_t, to_t, size_from, size_to, func_from, func_to) \
|
||||
size_to HELPER(name)(CPUE2KState *env, size_from x) \
|
||||
{\
|
||||
uint8_t old_flags = save_exception_flags(env); \
|
||||
size_to z = func_to( glue3(from_t, _to_, to_t) (func_from(x), &env->fp_status) );\
|
||||
merge_exception_flags(env, old_flags); \
|
||||
return z; \
|
||||
}
|
||||
|
||||
#define GENERATE_SIMPLE_FLOAT2_OPS_32_64(name, function) \
|
||||
GENERATE_SIMPLE_FLOAT2_OP(glue(name, s), function, 32) \
|
||||
GENERATE_SIMPLE_FLOAT2_OP(glue(name, d), function, 64)
|
||||
|
||||
#define GENERATE_CMP_FLOAT2_OPS_32_64(name, function, expr) \
|
||||
GENERATE_CMP_FLOAT2_OP(glue(name, s), function, expr, 32) \
|
||||
GENERATE_CMP_FLOAT2_OP(glue(name, d), function, expr, 64)
|
||||
|
||||
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fadd, add)
|
||||
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fsub, sub)
|
||||
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fmin, min)
|
||||
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fmax, max)
|
||||
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fmul, mul)
|
||||
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fdiv, div)
|
||||
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpeq, eq, )
|
||||
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpneq, eq, !)
|
||||
GENERATE_CMP_FLOAT2_OPS_32_64(fcmple, le, )
|
||||
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpnle, le, !)
|
||||
GENERATE_CMP_FLOAT2_OPS_32_64(fcmplt, lt, )
|
||||
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpnlt, lt, !)
|
||||
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpuod, unordered, )
|
||||
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpod, unordered, !)
|
||||
|
||||
GENERATE_CVT_FLOAT1_OP(fstois, float32, int32, uint32_t, uint32_t, make_float32, no_cvt)
|
||||
GENERATE_CVT_FLOAT1_OP(istofs, int32, float32, uint32_t, uint32_t, no_cvt, float32_val)
|
||||
GENERATE_CVT_FLOAT1_OP(fstoistr, float32, int32_round_to_zero, uint32_t, uint32_t, make_float32, no_cvt)
|
||||
|
||||
GENERATE_CVT_FLOAT1_OP(fdtoid, float64, int64, uint64_t, uint64_t, make_float64, no_cvt)
|
||||
GENERATE_CVT_FLOAT1_OP(idtofd, int64, float64, uint64_t, uint64_t, no_cvt, float64_val)
|
||||
GENERATE_CVT_FLOAT1_OP(fdtoidtr, float64, int64_round_to_zero, uint64_t, uint64_t, make_float64, no_cvt)
|
||||
|
||||
GENERATE_CVT_FLOAT1_OP(fstofd, float32, float64, uint32_t, uint64_t, make_float32, float64_val)
|
||||
GENERATE_CVT_FLOAT1_OP(fstoid, float32, int64, uint32_t, uint64_t, make_float32, no_cvt)
|
||||
GENERATE_CVT_FLOAT1_OP(istofd, int32, float64, uint32_t, uint64_t, no_cvt, float64_val)
|
||||
GENERATE_CVT_FLOAT1_OP(fstoidtr, float32, int64_round_to_zero, uint32_t, uint64_t, make_float32, no_cvt)
|
||||
|
||||
GENERATE_CVT_FLOAT1_OP(fdtofs, float64, float32, uint64_t, uint32_t, make_float64, float32_val)
|
||||
GENERATE_CVT_FLOAT1_OP(fdtois, float64, int32, uint64_t, uint32_t, make_float64, no_cvt)
|
||||
GENERATE_CVT_FLOAT1_OP(idtofs, int64, float32, uint64_t, uint32_t, no_cvt, float32_val)
|
||||
GENERATE_CVT_FLOAT1_OP(fdtoistr, float64, int32_round_to_zero, uint64_t, uint32_t, make_float64, no_cvt)
|
||||
|
||||
GENERATE_CVT_FLOAT1_OP(fxtofs, floatx80, float32, floatx80*, uint32_t, deref, float32_val)
|
||||
GENERATE_CVT_FLOAT1_OP(fxtofd, floatx80, float64, floatx80*, uint64_t, deref, float64_val)
|
||||
|
||||
void HELPER(fstofx)(floatx80 *ret, CPUE2KState *env, uint32_t x)
|
||||
{
|
||||
uint8_t old_flags = save_exception_flags(env);
|
||||
*ret = float32_to_floatx80(make_float32(x), &env->fp_status);
|
||||
merge_exception_flags(env, old_flags);
|
||||
}
|
||||
|
||||
void HELPER(fdtofx)(floatx80 *ret, CPUE2KState *env, uint64_t x)
|
||||
{
|
||||
uint8_t old_flags = save_exception_flags(env);
|
||||
*ret = float64_to_floatx80(make_float64(x), &env->fp_status);
|
||||
merge_exception_flags(env, old_flags);
|
||||
}
|
||||
|
||||
#define GEN_OP2_XX(name, op) \
|
||||
void HELPER(name)(CPUE2KState *env, floatx80 *x, floatx80 *y) \
|
||||
{ \
|
||||
uint8_t old_flags = save_exception_flags(env); \
|
||||
*x = glue(floatx80_, op)(*x, *y, &env->fp_status); \
|
||||
merge_exception_flags(env, old_flags); \
|
||||
}
|
||||
|
||||
GEN_OP2_XX(fxaddxx, add)
|
||||
GEN_OP2_XX(fxsubxx, sub)
|
||||
GEN_OP2_XX(fxmulxx, mul)
|
||||
GEN_OP2_XX(fxdivxx, div)
|
||||
|
||||
void HELPER(fxrsubxx)(CPUE2KState *env, floatx80 *x, floatx80 *y)
|
||||
{
|
||||
uint8_t old_flags = save_exception_flags(env);
|
||||
*x = floatx80_sub(*y, *x, &env->fp_status);
|
||||
merge_exception_flags(env, old_flags);
|
||||
}
|
140
target/e2k/helper_int.c
Normal file
140
target/e2k/helper_int.c
Normal file
@ -0,0 +1,140 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "translate.h"
|
||||
|
||||
uint64_t helper_sxt(uint64_t x, uint32_t y)
|
||||
{
|
||||
int size;
|
||||
|
||||
switch (x & 3) {
|
||||
case 0:
|
||||
size = 8;
|
||||
break;
|
||||
case 1:
|
||||
size = 16;
|
||||
break;
|
||||
default:
|
||||
size = 32;
|
||||
break;
|
||||
}
|
||||
|
||||
if (x & 4) {
|
||||
return y & GEN_MASK(0, size);
|
||||
} else {
|
||||
return (((int64_t) y) << (64 - size) >> (64 - size));
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t* state_reg_ptr(CPUE2KState *env, int idx)
|
||||
{
|
||||
switch (idx) {
|
||||
case 0x80: return &env->upsr; /* %upsr */
|
||||
case 0x83: return &env->lsr; /* %lsr */
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t helper_state_reg_read_i64(CPUE2KState *env, int idx)
|
||||
{
|
||||
switch (idx) {
|
||||
case 0x01: return e2k_state_wd(env); /* %wd */
|
||||
case 0x0f: return e2k_state_pcsp_lo(env); /* %pcsp.lo */
|
||||
case 0x0d: return e2k_state_pcsp_hi(env); /* %pcsp.hi */
|
||||
case 0x13: return env->pcshtp; /* %pcshtp */
|
||||
case 0x2c: return env->usd.hi; /* %usd.hi */
|
||||
case 0x2d: return env->usd.lo; /* %usd.lo */
|
||||
case 0x51: return env->cr0_hi; /* %cr0.hi */
|
||||
case 0x53: return env->cr0_lo; /* %cr0.lo */
|
||||
case 0x55: return env->cr1.hi; /* %cr1.hi */
|
||||
case 0x57: return env->cr1.lo; /* %cr1.lo */
|
||||
case 0x81: return env->ip; /* %ip */
|
||||
case 0x85: return env->fpcr.raw; /* %fpcr */
|
||||
case 0x86: return env->fpsr.raw; /* %fpsr */
|
||||
case 0x8a: return env->idr; /* %idr */
|
||||
case 0x90: return cpu_get_host_ticks(); /* %clkr */
|
||||
default: {
|
||||
uint64_t *p = state_reg_ptr(env, idx);
|
||||
|
||||
if (p != NULL) {
|
||||
return *p;
|
||||
} else {
|
||||
qemu_log_mask(LOG_UNIMP, "read unknown state register 0x%x\n", idx);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t helper_state_reg_read_i32(CPUE2KState *env, int idx)
|
||||
{
|
||||
return helper_state_reg_read_i64(env, idx);
|
||||
}
|
||||
|
||||
void helper_state_reg_write_i64(CPUE2KState *env, int idx, uint64_t val)
|
||||
{
|
||||
switch(idx) {
|
||||
case 0x85: /* %fpcr */
|
||||
env->fpcr.raw = val;
|
||||
e2k_update_fp_status(env);
|
||||
break;
|
||||
case 0x86: env->fpsr.raw = val; break; /* %fpsr */
|
||||
default: {
|
||||
uint64_t *p = state_reg_ptr(env, idx);
|
||||
|
||||
if (p != NULL) {
|
||||
*p = val;
|
||||
} else {
|
||||
qemu_log_mask(LOG_UNIMP, "unknown state register 0x%x\n", idx);
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void helper_state_reg_write_i32(CPUE2KState *env, int idx, uint32_t val)
|
||||
{
|
||||
switch (idx) {
|
||||
case 0x85: /* %fpcr */
|
||||
env->fpcr.raw = val;
|
||||
e2k_update_fp_status(env);
|
||||
break;
|
||||
case 0x86: env->fpsr.raw = val; break; /* %fpsr */
|
||||
default: {
|
||||
uint32_t *p = (uint32_t*) state_reg_ptr(env, idx);
|
||||
|
||||
if (p != NULL) {
|
||||
*p = val;
|
||||
} else {
|
||||
qemu_log_mask(LOG_UNIMP, "unknown state register 0x%x\n", idx);
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t helper_getsp(CPUE2KState *env, uint32_t src2)
|
||||
{
|
||||
int32_t s2 = src2 & ~0xf;
|
||||
|
||||
env->usd.base += s2;
|
||||
env->usd.size -= s2;
|
||||
|
||||
return env->usd.base;
|
||||
}
|
||||
|
||||
void HELPER(dam_lock_addr)(CPUE2KState *env, uint64_t addr, int size, int reg)
|
||||
{
|
||||
// TODO: helper_dam_lock_addr
|
||||
}
|
||||
|
||||
int HELPER(dam_unlock_addr)(CPUE2KState *env, uint64_t addr, int size, int reg)
|
||||
{
|
||||
// TODO: helper_dam_unlock_addr
|
||||
return 1;
|
||||
}
|
27
target/e2k/helper_sm.c
Normal file
27
target/e2k/helper_sm.c
Normal file
@ -0,0 +1,27 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "translate.h"
|
||||
|
||||
int HELPER(probe_read_access)(CPUE2KState *env, target_ulong addr)
|
||||
{
|
||||
int flags;
|
||||
void *ignore;
|
||||
|
||||
flags = probe_access_flags(env, addr, MMU_DATA_LOAD, 0, true, &ignore, 0);
|
||||
|
||||
return (flags & TLB_INVALID_MASK) == 0;
|
||||
}
|
||||
|
||||
int HELPER(probe_write_access)(CPUE2KState *env, target_ulong addr)
|
||||
{
|
||||
int flags;
|
||||
void *ignore;
|
||||
|
||||
flags = probe_access_flags(env, addr, MMU_DATA_STORE, 0, true, &ignore, 0);
|
||||
|
||||
return (flags & TLB_INVALID_MASK) == 0;
|
||||
}
|
196
target/e2k/helper_vec.c
Normal file
196
target/e2k/helper_vec.c
Normal file
@ -0,0 +1,196 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "translate.h"
|
||||
|
||||
static uint8_t reverse_bits(uint8_t b)
|
||||
{
|
||||
b = ((b & 0xf0) >> 4) | ((b & 0x0f) << 4);
|
||||
b = ((b & 0xcc) >> 2) | ((b & 0x33) << 2);
|
||||
b = ((b & 0xaa) >> 1) | ((b & 0x55) << 1);
|
||||
return b;
|
||||
}
|
||||
|
||||
typedef union {
|
||||
uint8_t ub[8];
|
||||
uint16_t uh[4];
|
||||
uint32_t uw[2];
|
||||
uint64_t uq;
|
||||
int8_t sb[8];
|
||||
int16_t sh[4];
|
||||
int32_t sw[2];
|
||||
int64_t sq;
|
||||
} vec64;
|
||||
|
||||
uint64_t HELPER(packed_shuffle_i64)(uint64_t src1, uint64_t src2, uint64_t src3)
|
||||
{
|
||||
vec64 ret, s1, s2, s3;
|
||||
unsigned int i;
|
||||
|
||||
s1.uq = src1;
|
||||
s2.uq = src2;
|
||||
s3.uq = src3;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
uint8_t desc = s3.ub[i];
|
||||
int index = extract8(desc, 0, 3);
|
||||
uint8_t byte;
|
||||
|
||||
if (desc < 0x80) {
|
||||
if (desc & 0x08) {
|
||||
byte = s1.ub[index];
|
||||
} else {
|
||||
byte = s2.ub[index];
|
||||
}
|
||||
|
||||
switch(desc >> 5) {
|
||||
case 0x1:
|
||||
byte = reverse_bits(byte);
|
||||
break;
|
||||
case 0x2:
|
||||
if ((byte & 0x80) != 0) {
|
||||
byte = 0xff;
|
||||
} else {
|
||||
byte = 0;
|
||||
}
|
||||
break;
|
||||
case 0x3:
|
||||
if ((byte & 1) != 0) {
|
||||
byte = 0xff;
|
||||
} else {
|
||||
byte = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (desc & 0x10) {
|
||||
byte = ~byte;
|
||||
}
|
||||
} else {
|
||||
switch(desc >> 6) {
|
||||
case 0xa:
|
||||
byte = 0x7f;
|
||||
break;
|
||||
case 0xc:
|
||||
byte = 0x80;
|
||||
break;
|
||||
case 0xe:
|
||||
byte = 0xff;
|
||||
break;
|
||||
default:
|
||||
byte = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret.ub[i] = byte;
|
||||
}
|
||||
|
||||
return ret.uq;
|
||||
}
|
||||
|
||||
// FIXME: not tested
|
||||
uint64_t HELPER(pcmpeqb)(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
unsigned int i;
|
||||
vec64 s1, s2, ret;
|
||||
|
||||
s1.uq = src1;
|
||||
s2.uq = src2;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (s1.ub[i] == s2.ub[i]) {
|
||||
ret.ub[i] = 0xff;
|
||||
} else {
|
||||
ret.ub[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret.uq;
|
||||
}
|
||||
|
||||
uint64_t HELPER(pminub)(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
unsigned int i;
|
||||
vec64 s1, s2, ret;
|
||||
|
||||
s1.uq = src1;
|
||||
s2.uq = src2;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
ret.ub[i] = MIN(s1.ub[i], s2.ub[i]);
|
||||
}
|
||||
|
||||
return ret.uq;
|
||||
}
|
||||
|
||||
uint64_t HELPER(pminsh)(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
unsigned int i;
|
||||
vec64 s1, s2, ret;
|
||||
|
||||
s1.uq = src1;
|
||||
s2.uq = src2;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret.sh[i] = MIN(s1.sh[i], s2.sh[i]);
|
||||
}
|
||||
|
||||
return ret.uq;
|
||||
}
|
||||
|
||||
uint64_t HELPER(pmaxub)(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
unsigned int i;
|
||||
vec64 s1, s2, ret;
|
||||
|
||||
s1.uq = src1;
|
||||
s2.uq = src2;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
ret.ub[i] = MAX(s1.ub[i], s2.ub[i]);
|
||||
}
|
||||
|
||||
return ret.uq;
|
||||
}
|
||||
|
||||
uint64_t HELPER(pmaxsh)(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
unsigned int i;
|
||||
vec64 s1, s2, ret;
|
||||
|
||||
s1.uq = src1;
|
||||
s2.uq = src2;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret.sh[i] = MAX(s1.sh[i], s2.sh[i]);
|
||||
}
|
||||
|
||||
return ret.uq;
|
||||
}
|
||||
|
||||
uint64_t HELPER(pmovmskb)(uint64_t src1, uint64_t src2)
|
||||
{
|
||||
unsigned int i;
|
||||
vec64 s1, s2;
|
||||
uint16_t ret = 0;
|
||||
|
||||
s1.uq = src1;
|
||||
s2.uq = src2;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (s1.sb[i] < 0) {
|
||||
ret |= 1 << (i + 8);
|
||||
}
|
||||
if (s2.sb[i] < 0) {
|
||||
ret |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
21
target/e2k/meson.build
Normal file
21
target/e2k/meson.build
Normal file
@ -0,0 +1,21 @@
|
||||
e2k_ss = ss.source_set()
|
||||
e2k_ss.add(files(
|
||||
'cpu.c',
|
||||
'gdbstub.c',
|
||||
'helper.c',
|
||||
'helper_aau.c',
|
||||
'helper_fpu.c',
|
||||
'helper_int.c',
|
||||
'helper_sm.c',
|
||||
'helper_vec.c',
|
||||
'translate.c',
|
||||
'translate/alc.c',
|
||||
'translate/aau.c',
|
||||
'translate/control.c',
|
||||
'translate/plu.c',
|
||||
'translate/state.c',
|
||||
))
|
||||
|
||||
# no softmmu support yet
|
||||
|
||||
target_arch += {'e2k': e2k_ss}
|
562
target/e2k/translate.c
Normal file
562
target/e2k/translate.c
Normal file
@ -0,0 +1,562 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu.h"
|
||||
#include "exec/log.h"
|
||||
#include "disas/disas.h"
|
||||
#include "translate.h"
|
||||
|
||||
struct CPUE2KStateTCG e2k_cs;
|
||||
|
||||
/* returns zero if bundle is invalid */
|
||||
static size_t unpack_bundle(CPUE2KState *env,
|
||||
target_ulong pc, UnpackedBundle *bundle)
|
||||
{
|
||||
unsigned int gap;
|
||||
unsigned int pos = 0;
|
||||
unsigned int mdl;
|
||||
unsigned int hsyll_cntr = 0;
|
||||
unsigned int i;
|
||||
uint32_t hs;
|
||||
|
||||
memset(bundle, 0, sizeof(UnpackedBundle));
|
||||
|
||||
bundle->hs = hs = translator_ldl(env, pc + pos);
|
||||
pos += 4;
|
||||
|
||||
/* Check for SS. */
|
||||
if (GET_BIT(hs, 12)) {
|
||||
bundle->ss_present = true;
|
||||
bundle->ss = translator_ldl(env, pc + pos);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
/* Check for available ALS syllables. */
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (GET_BIT(hs, 26 + i)) {
|
||||
bundle->als_present[i] = true;
|
||||
bundle->als[i] = translator_ldl(env, pc + pos);
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for CS0. */
|
||||
if (GET_BIT(hs, 14)) {
|
||||
bundle->cs0_present = true;
|
||||
bundle->cs0 = translator_ldl(env, pc + pos);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
if (GET_BIT(hs, 25)) {
|
||||
bundle->ales_present[5] = ALES_ALLOCATED;
|
||||
bundle->ales[5] = 0x01c0;
|
||||
}
|
||||
|
||||
if (GET_BIT(hs, 22)) {
|
||||
bundle->ales_present[2] = ALES_ALLOCATED;
|
||||
bundle->ales[2] = 0x01c0;
|
||||
}
|
||||
|
||||
/* Calculate the size of f1 fragment in bytes. For a valid bundle it
|
||||
should be equal to either of `pos', `pos + 4' or `pos + 8'. What should I
|
||||
do if it's not? */
|
||||
/* TODO: exception */
|
||||
mdl = ((hs & 0xf) + 1) * 4;
|
||||
|
||||
/* The following condition means that ALES{2,5} are physically present within
|
||||
the wide instruction. However, they should be probably taken into account
|
||||
only if HS.ale{2,5} are set. Should I disassemble them if these bits are
|
||||
not set but the syllables physically exist? */
|
||||
if ((GET_BIT(hs, 15) && mdl == pos + 8) ||
|
||||
(!GET_BIT(hs, 15) && mdl == pos + 4)) {
|
||||
/* Fill in ALES5 and ALES2 syllables even if none of them is specified in
|
||||
HS as present. This will let me output this syllable into disassembly
|
||||
whichever case takes place. */
|
||||
bundle->ales[5] = translator_lduw(env, pc + pos);
|
||||
bundle->ales[2] = translator_lduw(env, pc + pos + 2);
|
||||
|
||||
/* Adjust `ALES_PRESENT[{5,2}]' as proposed above now that we know that
|
||||
they are allocated. */
|
||||
bundle->ales_present[5] |= ALES_PRESENT;
|
||||
bundle->ales_present[2] |= ALES_PRESENT;
|
||||
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
/* Check for CS1. */
|
||||
if (GET_BIT(hs, 15)) {
|
||||
bundle->cs1_present = 1;
|
||||
bundle->cs1 = translator_ldl(env, pc + pos);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
/* A primitive control just for a moment. */
|
||||
if (mdl != pos) {
|
||||
/* This is either an APB instruction or an invalid one. Let's stupidly
|
||||
believe that the former takes place and signalize our caller about
|
||||
that by returning 0. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for ALES{0,1,3,4}. */
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (i == 2)
|
||||
continue;
|
||||
|
||||
if (GET_BIT(hs, 20 + i)) {
|
||||
unsigned int offset = 2 * ((hsyll_cntr & ~0x1) + 1 - (hsyll_cntr & 0x1));
|
||||
bundle->ales_present[i] = ALES_PRESENT;
|
||||
|
||||
/* Recall the idiotic order of half-syllables in the packed wide
|
||||
instruction. */
|
||||
bundle->ales[i] = translator_lduw(env, pc + pos + offset);
|
||||
hsyll_cntr++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for AASj half-syllables. To encode them SS syllable of SF1 type
|
||||
should be present. */
|
||||
if (bundle->ss_present && !GET_BIT(bundle->ss, 20)) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (GET_BIT(bundle->ss, 12 + i)) {
|
||||
bundle->aas_present[i >> 1] = true;
|
||||
bundle->aas_present[i + 2] = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (bundle->aas_present[i]) {
|
||||
unsigned int offset = 2 * ((hsyll_cntr & ~0x1) + 1 - (hsyll_cntr & 0x1));
|
||||
/* Recall the idiotic order of half-syllables in the packed wide
|
||||
instruction. Note that the first AAS half-syllable may share a
|
||||
syllable with the last ALES. */
|
||||
bundle->aas[i] = translator_lduw(env, pc + pos + offset);
|
||||
hsyll_cntr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* align half-syllables */
|
||||
hsyll_cntr += hsyll_cntr & 1;
|
||||
|
||||
/* Calculate the next 32-bit syllable's position. It may be the uppermost LTS
|
||||
syllable. Note that I don't consider the case when LTS syllables reuse the
|
||||
values encoded in the preceding ones, though according to `iset-v5.single'
|
||||
this is quite legal. GAS doesn't produce such a code. Hopefully neither LAS
|
||||
has ever done that . . . */
|
||||
gap = pos + 2 * hsyll_cntr;
|
||||
|
||||
/* Set POS to point to the last syllable in the current wide instruction and
|
||||
extract CDSj and PLSj syllables if any. */
|
||||
pos = ((GET_FIELD(hs, 4, 3) + 1) << 3) - 4;
|
||||
|
||||
/* Check for CDSj syllables. */
|
||||
for (i = 0; i < GET_FIELD(hs, 16, 2); i++) {
|
||||
bundle->cds_present[i] = true;
|
||||
bundle->cds[i] = translator_ldl(env, pc + pos);
|
||||
pos -= 4;
|
||||
}
|
||||
|
||||
/* Check for PLSj syllables. */
|
||||
for (i = 0; i < GET_FIELD(hs, 18, 2); i++) {
|
||||
bundle->pls_present[i] = true;
|
||||
bundle->pls[i] = translator_ldl(env, pc + pos);
|
||||
pos -= 4;
|
||||
}
|
||||
|
||||
/* Now POS should point to the lowermost LTS0 syllable if any. If there are
|
||||
no LTSj syllables in this instruction, POS should point to the last
|
||||
syllable consisting of half-syllables.
|
||||
|
||||
If neither of these conditions holds true, believe that it's not a valid
|
||||
synchronous instruction by analogy with the middle point test above.
|
||||
Engineers are said to customize instructions with references to missing
|
||||
literal syllables occasionally, but the lack of space for more substantial
|
||||
syllables should not be allowed for. */
|
||||
if (pos < gap && pos != gap - 4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Extract available LTSj syllables. */
|
||||
for (i = 0; i < 4 && pos >= gap; i++) {
|
||||
bundle->lts_present[i] = true;
|
||||
bundle->lts[i] = translator_ldl(env, pc + pos);
|
||||
pos -= 4;
|
||||
}
|
||||
|
||||
return 8 + GET_FIELD(hs, 4, 3) * 8;
|
||||
}
|
||||
|
||||
static inline bool use_goto_tb(DisasContext *s, target_ulong pc,
|
||||
target_ulong npc)
|
||||
{
|
||||
if (unlikely(s->base.singlestep_enabled || singlestep)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
return (pc & TARGET_PAGE_MASK) == (s->base.tb->pc & TARGET_PAGE_MASK) &&
|
||||
(npc & TARGET_PAGE_MASK) == (s->base.tb->pc & TARGET_PAGE_MASK);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void gen_goto_tb(DisasContext *ctx, int tb_num,
|
||||
target_ulong pc, target_ulong npc)
|
||||
{
|
||||
if (use_goto_tb(ctx, pc, npc)) {
|
||||
/* jump to same page: we can use a direct jump */
|
||||
tcg_gen_goto_tb(tb_num);
|
||||
tcg_gen_movi_tl(e2k_cs.pc, npc);
|
||||
tcg_gen_exit_tb(ctx->base.tb, tb_num);
|
||||
} else {
|
||||
/* jump to another page: currently not optimized */
|
||||
tcg_gen_movi_tl(e2k_cs.pc, npc);
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void e2k_tr_gen_exception(DisasContext *ctx, int which)
|
||||
{
|
||||
TCGv_i32 t = tcg_const_i32(which);
|
||||
|
||||
e2k_gen_save_cpu_state(ctx);
|
||||
gen_helper_raise_exception(cpu_env, t);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
tcg_temp_free_i32(t);
|
||||
}
|
||||
|
||||
void e2k_tr_gen_exception_no_spill(DisasContext *ctx, int excp)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_const_i32(excp);
|
||||
|
||||
e2k_gen_save_cpu_state(ctx);
|
||||
gen_helper_raise_exception_no_spill(cpu_env, t0);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
static inline void gen_ctpr_tag(TCGv_i64 ret, TCGv_i64 ctpr)
|
||||
{
|
||||
tcg_gen_extract_i64(ret, ctpr, CTPR_TAG_OFF, CTPR_TAG_LEN);
|
||||
}
|
||||
|
||||
static inline void gen_goto_ctpr_disp(TCGv_i64 ctpr)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
|
||||
tcg_gen_extract_i64(t0, ctpr, CTPR_BASE_OFF, CTPR_BASE_LEN);
|
||||
tcg_gen_trunc_i64_tl(t1, t0);
|
||||
tcg_gen_mov_tl(e2k_cs.pc, t1);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
|
||||
tcg_temp_free(t1);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
static inline void do_reset(DisasContext *ctx)
|
||||
{
|
||||
memset(ctx->mas, 0, sizeof(ctx->mas));
|
||||
ctx->illtag = e2k_get_temp_i32(ctx);
|
||||
tcg_gen_movi_i32(ctx->illtag, 0);
|
||||
}
|
||||
|
||||
static inline target_ulong do_decode(DisasContext *ctx, CPUState *cs)
|
||||
{
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
unsigned int len;
|
||||
|
||||
ctx->pc = ctx->base.pc_next;
|
||||
len = unpack_bundle(env, ctx->pc, &ctx->bundle);
|
||||
|
||||
if (len == 0) {
|
||||
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
|
||||
}
|
||||
|
||||
return ctx->pc + len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Executes instructions from a bundle and store the results to
|
||||
* temporary buffer.
|
||||
*/
|
||||
static inline void do_execute(DisasContext *ctx)
|
||||
{
|
||||
e2k_control_execute(ctx);
|
||||
e2k_alc_execute(ctx);
|
||||
e2k_aau_execute(ctx);
|
||||
e2k_plu_execute(ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes results of instructions from a bundle to the state
|
||||
*
|
||||
* Note
|
||||
* ====
|
||||
*
|
||||
* Must not generate any exception.
|
||||
* */
|
||||
static inline void do_commit(DisasContext *ctx)
|
||||
{
|
||||
e2k_control_window_change(ctx);
|
||||
e2k_alc_commit(ctx);
|
||||
e2k_aau_commit(ctx);
|
||||
e2k_plu_commit(ctx);
|
||||
e2k_stubs_commit(ctx);
|
||||
}
|
||||
|
||||
static inline void do_branch(DisasContext *ctx, target_ulong pc_next)
|
||||
{
|
||||
TCGLabel *l0 = gen_new_label();
|
||||
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, ctx->illtag, 0, l0);
|
||||
e2k_gen_exception(E2K_EXCP_ILLOPC);
|
||||
gen_set_label(l0);
|
||||
|
||||
if (ctx->ct.type == CT_NONE) {
|
||||
e2k_gen_save_pc(ctx->base.pc_next);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
if (ctx->ct.is_branch) {
|
||||
TCGLabel *l0 = gen_new_label();
|
||||
tcg_gen_brcondi_i32(TCG_COND_NE, e2k_cs.ct_cond, 0, l0);
|
||||
gen_goto_tb(ctx, TB_EXIT_IDX0, ctx->pc, pc_next);
|
||||
gen_set_label(l0);
|
||||
}
|
||||
|
||||
switch(ctx->ct.type) {
|
||||
case CT_IBRANCH:
|
||||
gen_goto_tb(ctx, TB_EXIT_IDX1, ctx->pc, ctx->ct.u.target);
|
||||
break;
|
||||
case CT_JUMP: {
|
||||
TCGLabel *l0 = gen_new_label();
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGv_i64 t0 = tcg_temp_local_new_i64();
|
||||
|
||||
gen_ctpr_tag(t0, ctx->ct.u.ctpr);
|
||||
tcg_gen_brcondi_i64(TCG_COND_EQ, t0, CTPR_TAG_DISP, l0);
|
||||
tcg_gen_brcondi_i64(TCG_COND_EQ, t0, CTPR_TAG_RETURN, l1);
|
||||
tcg_temp_free_i64(t0);
|
||||
|
||||
// TODO: ldisp, sdisp
|
||||
e2k_gen_exception(0);
|
||||
|
||||
gen_set_label(l1);
|
||||
gen_helper_return(cpu_env);
|
||||
|
||||
gen_set_label(l0);
|
||||
gen_goto_ctpr_disp(ctx->ct.u.ctpr);
|
||||
break;
|
||||
}
|
||||
case CT_CALL: {
|
||||
TCGv_i32 wbs = tcg_const_i32(ctx->ct.wbs);
|
||||
TCGv npc = tcg_const_tl(pc_next);
|
||||
|
||||
gen_helper_call(cpu_env, ctx->ct.u.ctpr, wbs, npc);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
|
||||
tcg_temp_free(npc);
|
||||
tcg_temp_free_i32(wbs);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void e2k_tr_init_disas_context(DisasContextBase *db, CPUState *cs)
|
||||
{
|
||||
DisasContext *ctx = container_of(db, DisasContext, base);
|
||||
E2KCPU *cpu = E2K_CPU(cs);
|
||||
CPUE2KState *env = &cpu->env;
|
||||
|
||||
ctx->version = env->version;
|
||||
}
|
||||
|
||||
static bool e2k_tr_breakpoint_check(DisasContextBase *db, CPUState *cs,
|
||||
const CPUBreakpoint *bp)
|
||||
{
|
||||
DisasContext *ctx = container_of(db, DisasContext, base);
|
||||
|
||||
e2k_gen_save_pc(ctx->base.pc_next);
|
||||
gen_helper_debug(cpu_env);
|
||||
tcg_gen_exit_tb(NULL, TB_EXIT_IDX0);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
/*
|
||||
* The address covered by the breakpoint must be included in
|
||||
* [tb->pc, tb->pc + tb->size) in order to for it to be
|
||||
* properly cleared -- thus we increment the PC here so that
|
||||
* the logic setting tb->size below does the right thing.
|
||||
*/
|
||||
ctx->base.pc_next += 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs)
|
||||
{
|
||||
// DisasContext *ctx = container_of(db, DisasContext, base);
|
||||
|
||||
tcg_gen_movi_i32(e2k_cs.ct_cond, 0);
|
||||
}
|
||||
|
||||
static void e2k_tr_insn_start(DisasContextBase *db, CPUState *cs)
|
||||
{
|
||||
DisasContext *ctx = container_of(db, DisasContext, base);
|
||||
|
||||
tcg_gen_insn_start(ctx->base.pc_next);
|
||||
}
|
||||
|
||||
static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs)
|
||||
{
|
||||
DisasContext *ctx = container_of(db, DisasContext, base);
|
||||
TCGLabel *l0 = gen_new_label();
|
||||
target_ulong pc_next;
|
||||
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, e2k_cs.is_bp, 0, l0);
|
||||
gen_helper_break_restore_state(cpu_env);
|
||||
gen_set_label(l0);
|
||||
|
||||
do_reset(ctx);
|
||||
pc_next = do_decode(ctx, cs);
|
||||
do_execute(ctx);
|
||||
do_commit(ctx);
|
||||
do_branch(ctx, pc_next);
|
||||
|
||||
ctx->base.pc_next = pc_next;
|
||||
|
||||
/* Free temporary values */
|
||||
while(ctx->t32_len) {
|
||||
tcg_temp_free_i32(ctx->t32[--ctx->t32_len]);
|
||||
}
|
||||
|
||||
while(ctx->t64_len) {
|
||||
tcg_temp_free_i64(ctx->t64[--ctx->t64_len]);
|
||||
}
|
||||
|
||||
while(ctx->ttl_len) {
|
||||
tcg_temp_free(ctx->ttl[--ctx->ttl_len]);
|
||||
}
|
||||
}
|
||||
|
||||
static void e2k_tr_tb_stop(DisasContextBase *db, CPUState *cs)
|
||||
{
|
||||
DisasContext *ctx = container_of(db, DisasContext, base);
|
||||
|
||||
if (ctx->base.is_jmp == DISAS_TOO_MANY) {
|
||||
gen_goto_tb(ctx, TB_EXIT_IDX0, ctx->pc, ctx->base.pc_next);
|
||||
}
|
||||
}
|
||||
|
||||
static void e2k_tr_disas_log(const DisasContextBase *db, CPUState *cpu)
|
||||
{
|
||||
DisasContext *dc = container_of(db, DisasContext, base);
|
||||
|
||||
qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
|
||||
log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size);
|
||||
}
|
||||
|
||||
static const TranslatorOps e2k_tr_ops = {
|
||||
.init_disas_context = e2k_tr_init_disas_context,
|
||||
.tb_start = e2k_tr_tb_start,
|
||||
.breakpoint_check = e2k_tr_breakpoint_check,
|
||||
.insn_start = e2k_tr_insn_start,
|
||||
.translate_insn = e2k_tr_translate_insn,
|
||||
.tb_stop = e2k_tr_tb_stop,
|
||||
.disas_log = e2k_tr_disas_log,
|
||||
};
|
||||
|
||||
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
|
||||
{
|
||||
DisasContext dc = { 0 };
|
||||
|
||||
translator_loop(&e2k_tr_ops, &dc.base, cs, tb, max_insns);
|
||||
}
|
||||
|
||||
void restore_state_to_opc(CPUE2KState *env, TranslationBlock *tb,
|
||||
target_ulong *data)
|
||||
{
|
||||
env->ip = data[0];
|
||||
}
|
||||
|
||||
void e2k_tcg_initialize(void) {
|
||||
char buf[16] = { 0 };
|
||||
|
||||
static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = {
|
||||
{ &e2k_cs.wd_base, offsetof(CPUE2KState, wd.base), "woff" },
|
||||
{ &e2k_cs.wd_size, offsetof(CPUE2KState, wd.size), "wsize" },
|
||||
{ &e2k_cs.boff, offsetof(CPUE2KState, bn.base), "boff" },
|
||||
{ &e2k_cs.bsize, offsetof(CPUE2KState, bn.size), "bsize" },
|
||||
{ &e2k_cs.bcur, offsetof(CPUE2KState, bn.cur), "bcur" },
|
||||
{ &e2k_cs.psize, offsetof(CPUE2KState, bp.size), "psize" },
|
||||
{ &e2k_cs.pcur, offsetof(CPUE2KState, bp.cur), "pcur" },
|
||||
{ &e2k_cs.is_bp, offsetof(CPUE2KState, is_bp), "is_bp" },
|
||||
{ &e2k_cs.wdbl, offsetof(CPUE2KState, wdbl), "wdbl" },
|
||||
{ &e2k_cs.aasti_tags, offsetof(CPUE2KState, aau.sti_tags), "aasti_tags" },
|
||||
{ &e2k_cs.aaind_tags, offsetof(CPUE2KState, aau.ind_tags), "aaind_tags" },
|
||||
{ &e2k_cs.aaincr_tags, offsetof(CPUE2KState, aau.incr_tags), "aaincr_tags" },
|
||||
{ &e2k_cs.ct_cond, offsetof(CPUE2KState, ct_cond), "cond" },
|
||||
};
|
||||
|
||||
static const struct { TCGv_i64 *ptr; int off; const char *name; } r64[] = {
|
||||
{ &e2k_cs.pregs, offsetof(CPUE2KState, pregs), "pregs" },
|
||||
{ &e2k_cs.lsr, offsetof(CPUE2KState, lsr), "lsr" },
|
||||
};
|
||||
|
||||
static const struct { TCGv *ptr; int off; const char *name; } rtl[] = {
|
||||
{ &e2k_cs.pc, offsetof(CPUE2KState, ip), "pc" },
|
||||
{ &e2k_cs.npc, offsetof(CPUE2KState, nip), "npc" },
|
||||
};
|
||||
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(r32); i++) {
|
||||
*r32[i].ptr = tcg_global_mem_new_i32(cpu_env, r32[i].off, r32[i].name);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(r64); i++) {
|
||||
*r64[i].ptr = tcg_global_mem_new_i64(cpu_env, r64[i].off, r64[i].name);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rtl); i++) {
|
||||
*rtl[i].ptr = tcg_global_mem_new(cpu_env, rtl[i].off, rtl[i].name);
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
snprintf(buf, ARRAY_SIZE(buf), "%%ctpr%d", i + 1);
|
||||
e2k_cs.ctprs[i] = tcg_global_mem_new_i64(cpu_env,
|
||||
offsetof(CPUE2KState, ctprs[i].raw), buf);
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
snprintf(buf, ARRAY_SIZE(buf), "%%aasti%d", i);
|
||||
e2k_cs.aasti[i] = tcg_global_mem_new_i32(cpu_env,
|
||||
offsetof(CPUE2KState, aau.stis[i]), buf);
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
snprintf(buf, ARRAY_SIZE(buf), "%%aaind%d", i);
|
||||
e2k_cs.aaind[i] = tcg_global_mem_new_i32(cpu_env,
|
||||
offsetof(CPUE2KState, aau.inds[i]), buf);
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
snprintf(buf, ARRAY_SIZE(buf), "%%aaincr%d", i);
|
||||
e2k_cs.aaincr[i] = tcg_global_mem_new_i32(cpu_env,
|
||||
offsetof(CPUE2KState, aau.incrs[i]), buf);
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
snprintf(buf, ARRAY_SIZE(buf), "%%aad%d_lo", i);
|
||||
e2k_cs.aad_lo[i] = tcg_global_mem_new_i64(cpu_env,
|
||||
offsetof(CPUE2KState, aau.ds[i].lo), buf);
|
||||
snprintf(buf, ARRAY_SIZE(buf), "%%aad%d_hi", i);
|
||||
e2k_cs.aad_hi[i] = tcg_global_mem_new_i64(cpu_env,
|
||||
offsetof(CPUE2KState, aau.ds[i].hi), buf);
|
||||
}
|
||||
}
|
570
target/e2k/translate.h
Normal file
570
target/e2k/translate.h
Normal file
@ -0,0 +1,570 @@
|
||||
#ifndef E2K_TRANSLATE_H
|
||||
#define E2K_TRANSLATE_H
|
||||
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "exec/translator.h"
|
||||
|
||||
#define IS_BASED(i) (((i) & 0x80) == 0)
|
||||
#define IS_REGULAR(i) (((i) & 0xc0) == 0x80)
|
||||
#define IS_IMM5(i) (((i) & 0xe0) == 0xc0)
|
||||
#define IS_IMM4(i) (((i) & 0xf0) == 0xc0)
|
||||
#define IS_LIT(i) (((i) & 0xf0) == 0xd0)
|
||||
#define IS_LIT16_LO(i) (((i) & 0x0e) == 0x00)
|
||||
#define IS_LIT16_HI(i) (((i) & 0x0e) == 0x04)
|
||||
#define IS_LIT32(i) (((i) & 0x0c) == 0x08)
|
||||
#define IS_LIT64(i) (((i) & 0x0c) == 0x0c)
|
||||
#define IS_GLOBAL(i) (((i) & 0xe0) == 0xe0)
|
||||
|
||||
#define GET_BASED(i) ((i) & 0x7f)
|
||||
#define GET_REGULAR(i) ((i) & 0x3f)
|
||||
#define GET_IMM5(i) ((i) & 0x1f)
|
||||
#define GET_IMM4(i) ((i) & 0x0f)
|
||||
#define GET_LIT(i) ((i) & 0x03)
|
||||
#define GET_GLOBAL(i) ((i) & 0x1f)
|
||||
|
||||
typedef enum {
|
||||
ALES_NONE = 0x00,
|
||||
ALES_PRESENT = 0x01,
|
||||
ALES_ALLOCATED = 0x02,
|
||||
} AlesFlag;
|
||||
|
||||
typedef struct {
|
||||
TCGv_i32 cdi[32];
|
||||
TCGv_i64 pib[32];
|
||||
} CPUE2KAauPrefStateTCG;
|
||||
|
||||
typedef struct CPUE2KStateTCG {
|
||||
TCGv pc;
|
||||
TCGv npc;
|
||||
TCGv_i64 ctprs[3];
|
||||
TCGv_i32 ct_cond;
|
||||
TCGv_i32 is_bp; /* breakpoint flag */
|
||||
TCGv_i32 wdbl;
|
||||
TCGv_i64 lsr;
|
||||
TCGv_i32 wd_base; /* holds wbs * 2 */
|
||||
TCGv_i32 wd_size; /* holds wsz * 2 */
|
||||
TCGv_i32 boff; /* holds rbs * 2 */
|
||||
TCGv_i32 bsize; /* holds rsz * 2 + 2 */
|
||||
TCGv_i32 bcur; /* holds rcur * 2 */
|
||||
TCGv_i64 pregs;
|
||||
TCGv_i32 psize; /* holds psz */
|
||||
TCGv_i32 pcur; /* holds pcur */
|
||||
/* AAU */
|
||||
TCGv_i32 aasti[16];
|
||||
TCGv_i32 aasti_tags;
|
||||
TCGv_i32 aaind[16];
|
||||
TCGv_i32 aaind_tags;
|
||||
TCGv_i32 aaincr[8];
|
||||
TCGv_i32 aaincr_tags;
|
||||
TCGv_i64 aad_lo[32];
|
||||
TCGv_i64 aad_hi[32];
|
||||
CPUE2KAauPrefStateTCG aapl, aapr;
|
||||
} CPUE2KStateTCG;
|
||||
|
||||
extern struct CPUE2KStateTCG e2k_cs;
|
||||
|
||||
typedef struct UnpackedBundle {
|
||||
uint32_t hs;
|
||||
uint32_t ss;
|
||||
uint32_t als[6];
|
||||
uint32_t cs0;
|
||||
uint16_t ales[6];
|
||||
uint32_t cs1;
|
||||
uint16_t aas[6];
|
||||
uint32_t lts[4];
|
||||
uint32_t pls[3];
|
||||
uint32_t cds[3];
|
||||
|
||||
bool ss_present;
|
||||
bool als_present[6];
|
||||
bool cs0_present;
|
||||
AlesFlag ales_present[6];
|
||||
bool cs1_present;
|
||||
bool aas_present[6];
|
||||
bool lts_present[4];
|
||||
bool pls_present[3];
|
||||
bool cds_present[3];
|
||||
} UnpackedBundle;
|
||||
|
||||
typedef enum {
|
||||
AL_RESULT_NONE = 0,
|
||||
|
||||
AL_RESULT_SIZE_MASK = 0x3,
|
||||
AL_RESULT_32 = 0x00,
|
||||
AL_RESULT_64 = 0x01,
|
||||
AL_RESULT_80 = 0x02,
|
||||
AL_RESULT_128 = 0x03,
|
||||
|
||||
AL_RESULT_TYPE_MASK = 0xc,
|
||||
AL_RESULT_REG = 0x04,
|
||||
AL_RESULT_PREG = 0x08,
|
||||
AL_RESULT_CTPR = 0x0c,
|
||||
|
||||
AL_RESULT_REG32 = AL_RESULT_REG | AL_RESULT_32,
|
||||
AL_RESULT_REG64 = AL_RESULT_REG | AL_RESULT_64,
|
||||
AL_RESULT_REG80 = AL_RESULT_REG | AL_RESULT_80,
|
||||
AL_RESULT_REG128 = AL_RESULT_REG | AL_RESULT_128,
|
||||
AL_RESULT_CTPR32 = AL_RESULT_CTPR | AL_RESULT_32,
|
||||
AL_RESULT_CTPR64 = AL_RESULT_CTPR | AL_RESULT_64,
|
||||
} AlResultType;
|
||||
|
||||
#define e2k_al_result_size(x) ((x) & AL_RESULT_SIZE_MASK)
|
||||
#define e2k_al_result_type(x) ((x) & AL_RESULT_TYPE_MASK)
|
||||
|
||||
typedef struct {
|
||||
AlResultType type;
|
||||
/* check tag for 32-bit ops if wdbl is set */
|
||||
bool check_tag;
|
||||
/* poison result if tag is not zero */
|
||||
bool poison;
|
||||
union {
|
||||
struct {
|
||||
uint8_t dst; /* %rN, 1st phase */
|
||||
TCGv_i32 index;
|
||||
TCGv_i32 tag;
|
||||
union {
|
||||
TCGv_i32 v32;
|
||||
TCGv_i64 v64;
|
||||
};
|
||||
union {
|
||||
TCGv_i32 x32; /* FX ops */
|
||||
TCGv_i64 x64; /* SIMD ops v5+ */
|
||||
};
|
||||
} reg;
|
||||
struct {
|
||||
int index;
|
||||
union {
|
||||
TCGv_i32 v32;
|
||||
TCGv_i64 v64;
|
||||
};
|
||||
} preg, ctpr;
|
||||
};
|
||||
} AlResult;
|
||||
|
||||
typedef enum {
|
||||
AAU_RESULT_NONE,
|
||||
AAU_RESULT_REG32,
|
||||
AAU_RESULT_REG64,
|
||||
} AauResultType;
|
||||
|
||||
typedef struct {
|
||||
AauResultType type;
|
||||
uint8_t dst;
|
||||
TCGv_i32 index;
|
||||
union {
|
||||
TCGv_i32 v32;
|
||||
TCGv_i64 v64;
|
||||
};
|
||||
} AauResult;
|
||||
|
||||
typedef struct {
|
||||
int reg; // -1 means do not write
|
||||
TCGv_i32 value;
|
||||
} PlResult;
|
||||
|
||||
typedef enum {
|
||||
CT_NONE,
|
||||
CT_IBRANCH,
|
||||
CT_JUMP,
|
||||
CT_CALL,
|
||||
} ControlTransferType;
|
||||
|
||||
typedef struct {
|
||||
ControlTransferType type;
|
||||
union {
|
||||
target_ulong target;
|
||||
TCGv_i64 ctpr;
|
||||
} u;
|
||||
int wbs;
|
||||
bool is_branch;
|
||||
} ControlTransfer;
|
||||
|
||||
typedef struct DisasContext {
|
||||
DisasContextBase base;
|
||||
UnpackedBundle bundle;
|
||||
target_ulong pc;
|
||||
int jump_ctpr;
|
||||
int mmuidx;
|
||||
uint8_t mas[6];
|
||||
bool loop_mode;
|
||||
TCGv_i32 is_prologue;
|
||||
TCGv_i32 is_epilogue;
|
||||
/* optional, can be NULL */
|
||||
TCGv_i32 mlock;
|
||||
|
||||
int version;
|
||||
/* Force ILLOP for bad instruction format for cases where real CPU
|
||||
do not generate it. */
|
||||
bool strict;
|
||||
|
||||
// Temporary values.
|
||||
TCGv_i32 t32[64];
|
||||
TCGv_i64 t64[32];
|
||||
TCGv ttl[8];
|
||||
// Allocated temporary values count.
|
||||
int t32_len;
|
||||
int t64_len;
|
||||
int ttl_len;
|
||||
|
||||
/* illegal tag for delayed exception */
|
||||
TCGv_i32 illtag;
|
||||
TCGv_i64 cond[6];
|
||||
AlResult al_results[6];
|
||||
TCGv_i32 al_cond[6];
|
||||
AauResult aau_results[4];
|
||||
int aau_am[4];
|
||||
PlResult pl_results[3];
|
||||
ControlTransfer ct;
|
||||
} DisasContext;
|
||||
|
||||
/* exception generated in translation time */
|
||||
void e2k_tr_gen_exception(DisasContext *dc, int which);
|
||||
void e2k_tr_gen_exception_no_spill(DisasContext *ctx, int excp);
|
||||
|
||||
/* exception generated in runtime */
|
||||
static inline void e2k_gen_exception(int excp)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_const_i32(excp);
|
||||
|
||||
// TODO: check if need to save state
|
||||
gen_helper_raise_exception(cpu_env, t0);
|
||||
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
|
||||
#define e2k_todo(ctx, fmt, ...) \
|
||||
do { \
|
||||
if (unlikely(qemu_loglevel_mask(LOG_UNIMP))) { \
|
||||
qemu_log("%#lx: todo: ", ctx->pc); \
|
||||
qemu_log(fmt, ## __VA_ARGS__); \
|
||||
qemu_log("\n"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define e2k_todo_illop(ctx, fmt, ...) \
|
||||
do { \
|
||||
e2k_todo(ctx, fmt, ## __VA_ARGS__); \
|
||||
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC); \
|
||||
} while (0)
|
||||
|
||||
static inline void e2k_gen_mask_i64(TCGv_i64 ret, TCGv_i64 len)
|
||||
{
|
||||
TCGv_i64 one = tcg_const_i64(1);
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_shl_i64(t0, one, len);
|
||||
tcg_gen_subi_i64(ret, t0, 1);
|
||||
|
||||
tcg_temp_free_i64(t0);
|
||||
tcg_temp_free_i64(one);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_maski_i64(TCGv_i64 ret, int len)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_const_i64(len);
|
||||
e2k_gen_mask_i64(ret, t0);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg1,
|
||||
TCGv_i64 offset, TCGv_i64 len)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_shr_i64(t0, arg1, offset);
|
||||
e2k_gen_mask_i64(t1, len);
|
||||
tcg_gen_and_i64(ret, t0, t1);
|
||||
|
||||
tcg_temp_free_i64(t1);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1,
|
||||
TCGv_i64 arg2, TCGv_i64 offset, TCGv_i64 len)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
TCGv_i64 t2 = tcg_temp_new_i64();
|
||||
TCGv_i64 t3 = tcg_temp_new_i64();
|
||||
TCGv_i64 t4 = tcg_temp_new_i64();
|
||||
TCGv_i64 t5 = tcg_temp_new_i64();
|
||||
|
||||
e2k_gen_mask_i64(t0, len);
|
||||
tcg_gen_shl_i64(t1, t0, offset);
|
||||
tcg_gen_not_i64(t2, t1);
|
||||
tcg_gen_and_i64(t3, arg1, t2);
|
||||
tcg_gen_and_i64(t4, arg2, t0);
|
||||
tcg_gen_shl_i64(t5, t4, offset);
|
||||
tcg_gen_or_i64(ret, t3, t5);
|
||||
|
||||
tcg_temp_free_i64(t5);
|
||||
tcg_temp_free_i64(t4);
|
||||
tcg_temp_free_i64(t3);
|
||||
tcg_temp_free_i64(t2);
|
||||
tcg_temp_free_i64(t1);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
static inline TCGv_i32 e2k_get_temp_i32(DisasContext *dc)
|
||||
{
|
||||
assert(dc->t32_len < ARRAY_SIZE(dc->t32));
|
||||
return dc->t32[dc->t32_len++] = tcg_temp_local_new_i32();
|
||||
}
|
||||
|
||||
static inline TCGv_i32 e2k_get_const_i32(DisasContext *dc, uint32_t value)
|
||||
{
|
||||
assert(dc->t32_len < ARRAY_SIZE(dc->t32));
|
||||
return dc->t32[dc->t32_len++] = tcg_const_local_i32(value);
|
||||
}
|
||||
|
||||
static inline TCGv_i64 e2k_get_temp_i64(DisasContext *dc)
|
||||
{
|
||||
assert(dc->t64_len < ARRAY_SIZE(dc->t64));
|
||||
return dc->t64[dc->t64_len++] = tcg_temp_local_new_i64();
|
||||
}
|
||||
|
||||
static inline TCGv_i64 e2k_get_const_i64(DisasContext *dc, uint64_t value)
|
||||
{
|
||||
assert(dc->t64_len < ARRAY_SIZE(dc->t64));
|
||||
return dc->t64[dc->t64_len++] = tcg_const_local_i64(value);
|
||||
}
|
||||
|
||||
static inline TCGv e2k_get_temp(DisasContext *dc)
|
||||
{
|
||||
assert(dc->ttl_len < ARRAY_SIZE(dc->ttl));
|
||||
return dc->ttl[dc->ttl_len++] = tcg_temp_local_new();
|
||||
}
|
||||
|
||||
static inline void e2k_gen_save_pc(target_ulong pc)
|
||||
{
|
||||
tcg_gen_movi_tl(e2k_cs.pc, pc);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_save_cpu_state(DisasContext *ctx)
|
||||
{
|
||||
e2k_gen_save_pc(ctx->pc);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_lcnt_i64(TCGv_i64 ret)
|
||||
{
|
||||
tcg_gen_andi_i64(ret, e2k_cs.lsr, (1UL << 32) - 1);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_lcnt_i32(TCGv_i32 ret)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
|
||||
e2k_gen_lcnt_i64(t0);
|
||||
tcg_gen_extrl_i64_i32(ret, t0);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_lcnt_set_i32(TCGv_i32 value)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_extu_i32_i64(t0, value);
|
||||
tcg_gen_deposit_i64(e2k_cs.lsr, e2k_cs.lsr, t0, LSR_LCNT_OFF, LSR_LCNT_LEN);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_ecnt_i64(TCGv_i64 ret)
|
||||
{
|
||||
tcg_gen_extract_i64(ret, e2k_cs.lsr, LSR_ECNT_OFF, LSR_ECNT_LEN);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_ecnt_i32(TCGv_i32 ret)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
|
||||
e2k_gen_ecnt_i64(t0);
|
||||
tcg_gen_extrl_i64_i32(ret, t0);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_ecnt_set_i32(TCGv_i32 value)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_extu_i32_i64(t0, value);
|
||||
tcg_gen_deposit_i64(e2k_cs.lsr, e2k_cs.lsr, t0, LSR_ECNT_OFF, LSR_ECNT_LEN);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_pcnt_i32(TCGv_i32 ret)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_extract_i64(t0, e2k_cs.lsr, LSR_PCNT_OFF, LSR_PCNT_LEN);
|
||||
tcg_gen_extrl_i64_i32(ret, t0);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_pcnt_set_i32(TCGv_i32 value)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_extu_i32_i64(t0, value);
|
||||
tcg_gen_deposit_i64(e2k_cs.lsr, e2k_cs.lsr, t0, LSR_PCNT_OFF, LSR_PCNT_LEN);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_lsr_strem_i32(TCGv_i32 ret)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_extract_i64(t0, e2k_cs.lsr, LSR_STRMD_OFF, LSR_STRMD_LEN);
|
||||
tcg_gen_extrl_i64_i32(ret, t0);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_lsr_strem_set_i32(TCGv_i32 value)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_extu_i32_i64(t0, value);
|
||||
tcg_gen_deposit_i64(e2k_cs.lsr, e2k_cs.lsr, t0, LSR_STRMD_OFF,
|
||||
LSR_STRMD_LEN);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_lcntex(TCGv_i32 ret)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_extrl_i64_i32(t0, e2k_cs.lsr);
|
||||
tcg_gen_setcondi_i32(TCG_COND_EQ, ret, t0, 0);
|
||||
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
void e2k_gen_store_preg(int idx, TCGv_i64 val);
|
||||
|
||||
void e2k_gen_reg_tag_read_i64(TCGv_i32 ret, TCGv_i32 idx);
|
||||
void e2k_gen_reg_tag_read_i32(TCGv_i32 ret, TCGv_i32 idx);
|
||||
void e2k_gen_reg_tag_write_i64(TCGv_i32 value, TCGv_i32 idx);
|
||||
void e2k_gen_reg_tag_write_i32(TCGv_i32 value, TCGv_i32 idx);
|
||||
|
||||
static inline void e2k_gen_reg_tag_writei_i64(int value, TCGv_i32 idx)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_const_i32(value);
|
||||
e2k_gen_reg_tag_write_i64(t0, idx);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_reg_tag_writei_i32(int value, TCGv_i32 idx)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_const_i32(value);
|
||||
e2k_gen_reg_tag_write_i32(t0, idx);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_reg_tag_extract_lo(TCGv_i32 ret, TCGv_i32 tags)
|
||||
{
|
||||
tcg_gen_andi_i32(ret, tags, GEN_MASK(0, E2K_TAG_SIZE));
|
||||
}
|
||||
|
||||
static inline void e2k_gen_reg_tag_extract_hi(TCGv_i32 ret, TCGv_i32 tags)
|
||||
{
|
||||
tcg_gen_shri_i32(ret, tags, E2K_TAG_SIZE);
|
||||
}
|
||||
|
||||
void e2k_gen_reg_tag_check_i64(TCGv_i32 ret, TCGv_i32 tag);
|
||||
void e2k_gen_reg_tag_check_i32(TCGv_i32 ret, TCGv_i32 tag);
|
||||
|
||||
void e2k_gen_reg_index_from_wregi(TCGv_i32 ret, int idx);
|
||||
void e2k_gen_reg_index_from_bregi(TCGv_i32 ret, int idx);
|
||||
void e2k_gen_reg_index_from_gregi(TCGv_i32 ret, int idx);
|
||||
static inline void e2k_gen_reg_index(TCGv_i32 ret, uint8_t arg)
|
||||
{
|
||||
if (IS_BASED(arg)) {
|
||||
e2k_gen_reg_index_from_bregi(ret, GET_BASED(arg));
|
||||
} else if (IS_REGULAR(arg)) {
|
||||
e2k_gen_reg_index_from_wregi(ret, GET_REGULAR(arg));
|
||||
} else if (IS_GLOBAL(arg)) {
|
||||
e2k_gen_reg_index_from_gregi(ret, GET_GLOBAL(arg));
|
||||
} else {
|
||||
e2k_gen_exception(E2K_EXCP_ILLOPN);
|
||||
}
|
||||
}
|
||||
|
||||
void e2k_gen_reg_read_i64(TCGv_i64 ret, TCGv_i32 idx);
|
||||
void e2k_gen_reg_read_i32(TCGv_i32 ret, TCGv_i32 idx);
|
||||
void e2k_gen_reg_write_i64(TCGv_i64 value, TCGv_i32 idx);
|
||||
void e2k_gen_reg_write_i32(TCGv_i32 value, TCGv_i32 idx);
|
||||
|
||||
void e2k_gen_xreg_read_i64(TCGv_i64 ret, TCGv_i32 idx);
|
||||
void e2k_gen_xreg_read_i32(TCGv_i32 ret, TCGv_i32 idx);
|
||||
void e2k_gen_xreg_read16u_i32(TCGv_i32 ret, TCGv_i32 idx);
|
||||
void e2k_gen_xreg_write_i64(TCGv_i64 value, TCGv_i32 idx);
|
||||
void e2k_gen_xreg_write_i32(TCGv_i32 value, TCGv_i32 idx);
|
||||
void e2k_gen_xreg_write16u_i32(TCGv_i32 value, TCGv_i32 idx);
|
||||
|
||||
void e2k_gen_preg_i64(TCGv_i64 ret, int reg);
|
||||
void e2k_gen_preg_i32(TCGv_i32 ret, int reg);
|
||||
TCGv_i64 e2k_get_preg(DisasContext *dc, int reg);
|
||||
void e2k_gen_cond_i32(DisasContext *ctx, TCGv_i32 ret, uint8_t psrc);
|
||||
|
||||
static inline void e2k_gen_cond_i64(DisasContext *ctx, TCGv_i64 ret,
|
||||
uint8_t psrc)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
|
||||
e2k_gen_cond_i32(ctx, t0, psrc);
|
||||
tcg_gen_extu_i32_i64(ret, t0);
|
||||
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_is_last_iter(TCGv_i32 ret)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
TCGv_i32 t1 = tcg_temp_new_i32();
|
||||
TCGv_i64 t2 = tcg_temp_new_i64();
|
||||
TCGv_i32 t3 = tcg_temp_new_i32();
|
||||
|
||||
e2k_gen_lcnt_i32(t0);
|
||||
tcg_gen_setcondi_i32(TCG_COND_LTU, t1, t0, 2);
|
||||
tcg_gen_andi_i64(t2, e2k_cs.lsr, LSR_VLC_BIT);
|
||||
tcg_gen_setcondi_i64(TCG_COND_NE, t2, t2, 0);
|
||||
tcg_gen_extrl_i64_i32(t3, t2);
|
||||
tcg_gen_and_i32(ret, t1, t3);
|
||||
|
||||
tcg_temp_free_i32(t3);
|
||||
tcg_temp_free_i64(t2);
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
static inline void e2k_gen_is_loop_end_i32(TCGv_i32 ret)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
TCGv_i32 t1 = tcg_temp_new_i32();
|
||||
TCGv_i32 t2 = tcg_temp_new_i32();
|
||||
|
||||
e2k_gen_ecnt_i32(t0);
|
||||
tcg_gen_setcondi_i32(TCG_COND_EQ, t1, t0, 0);
|
||||
e2k_gen_is_last_iter(t2);
|
||||
tcg_gen_and_i32(ret, t1, t2);
|
||||
|
||||
tcg_temp_free_i32(t2);
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
void e2k_control_execute(DisasContext *ctx);
|
||||
void e2k_control_window_change(DisasContext *ctx);
|
||||
void e2k_stubs_commit(DisasContext *ctx);
|
||||
|
||||
void e2k_alc_execute(DisasContext *ctx);
|
||||
void e2k_alc_commit(DisasContext *ctx);
|
||||
|
||||
void e2k_aau_execute(DisasContext *ctx);
|
||||
void e2k_aau_commit(DisasContext *ctx);
|
||||
void e2k_plu_execute(DisasContext *ctx);
|
||||
void e2k_plu_commit(DisasContext *ctx);
|
||||
|
||||
#endif
|
215
target/e2k/translate/aau.c
Normal file
215
target/e2k/translate/aau.c
Normal file
@ -0,0 +1,215 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu.h"
|
||||
#include "exec/log.h"
|
||||
#include "translate.h"
|
||||
|
||||
typedef struct {
|
||||
int chan;
|
||||
union {
|
||||
struct {
|
||||
uint16_t am: 1;
|
||||
uint16_t ind: 5;
|
||||
uint16_t area: 6;
|
||||
uint16_t opc: 3;
|
||||
uint16_t be: 1;
|
||||
};
|
||||
uint16_t aas;
|
||||
};
|
||||
uint8_t dst;
|
||||
} Instr;
|
||||
|
||||
static void gen_load_prefetch_program(DisasContext *ctx)
|
||||
{
|
||||
gen_helper_aau_load_program(cpu_env);
|
||||
}
|
||||
|
||||
static void gen_aau_result_reg64(DisasContext *ctx, Instr *instr, TCGv_i64 dst)
|
||||
{
|
||||
AauResult *res = &ctx->aau_results[instr->chan];
|
||||
res->type = AAU_RESULT_REG64;
|
||||
res->dst = instr->dst;
|
||||
res->index = e2k_get_temp_i32(ctx);
|
||||
res->v64 = dst;
|
||||
if (IS_REGULAR(instr->dst)) {
|
||||
res->dst = instr->dst;
|
||||
} else {
|
||||
res->dst = 0;
|
||||
e2k_gen_reg_index(res->index, instr->dst);
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_aau_result_reg32(DisasContext *ctx, Instr *instr, TCGv_i32 dst)
|
||||
{
|
||||
AauResult *res = &ctx->aau_results[instr->chan];
|
||||
res->type = AAU_RESULT_REG32;
|
||||
res->dst = instr->dst;
|
||||
res->index = e2k_get_temp_i32(ctx);
|
||||
res->v32 = dst;
|
||||
if (IS_REGULAR(instr->dst)) {
|
||||
res->dst = instr->dst;
|
||||
} else {
|
||||
res->dst = 0;
|
||||
e2k_gen_reg_index(res->index, instr->dst);
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_mova_i32(DisasContext *ctx, Instr *instr, TCGv ptr)
|
||||
{
|
||||
MemOp memop = instr->be ? MO_BE : MO_LE;
|
||||
TCGv_i32 dst = e2k_get_temp_i32(ctx);
|
||||
|
||||
switch(instr->opc) {
|
||||
case 1: memop |= MO_8; break; /* movab */
|
||||
case 2: memop |= MO_16; break; /* movah */
|
||||
case 3: memop |= MO_32; break; /* movaw */
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
|
||||
tcg_gen_qemu_ld_i32(dst, ptr, 0, memop);
|
||||
gen_aau_result_reg32(ctx, instr, dst);
|
||||
}
|
||||
|
||||
static void gen_mova_i64(DisasContext *ctx, Instr *instr, TCGv ptr)
|
||||
{
|
||||
TCGv_i64 dst = e2k_get_temp_i64(ctx);
|
||||
|
||||
tcg_gen_qemu_ld_i64(dst, ptr, 0, instr->be ? MO_BEQ : MO_LEQ);
|
||||
gen_aau_result_reg64(ctx, instr, dst);
|
||||
}
|
||||
|
||||
static inline void gen_mova_ptr(TCGv ret, Instr *instr)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_const_i32(instr->chan);
|
||||
TCGv_i32 t1 = tcg_const_i32(instr->area);
|
||||
TCGv t2 = tcg_temp_new();
|
||||
|
||||
gen_helper_mova_ptr(t2, cpu_env, t0, t1);
|
||||
tcg_gen_addi_tl(ret, t2, instr->ind);
|
||||
|
||||
tcg_temp_free(t2);
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
static void gen_mova(DisasContext *ctx, Instr *instr)
|
||||
{
|
||||
TCGv t5 = tcg_temp_new();
|
||||
|
||||
ctx->aau_am[instr->chan] = instr->am ? instr->area : -1;
|
||||
// TODO: check ind has proper alignment
|
||||
// TODO: check ind is less than mrng
|
||||
gen_mova_ptr(t5, instr);
|
||||
|
||||
switch(instr->opc) {
|
||||
case 1: /* movab */
|
||||
case 2: /* movah */
|
||||
case 3: /* movaw */
|
||||
gen_mova_i32(ctx, instr, t5);
|
||||
break;
|
||||
case 4: /* movad */
|
||||
gen_mova_i64(ctx, instr, t5);
|
||||
break;
|
||||
case 5: /* movaq */
|
||||
qemu_log_mask(LOG_UNIMP, "0x%lx: movaq is not implemented\n", ctx->pc);
|
||||
abort();
|
||||
break;
|
||||
case 7: /* movaqp */
|
||||
qemu_log_mask(LOG_UNIMP, "0x%lx: movaqp is not implemented\n", ctx->pc);
|
||||
abort();
|
||||
break;
|
||||
default:
|
||||
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
|
||||
break;
|
||||
}
|
||||
|
||||
tcg_temp_free(t5);
|
||||
}
|
||||
|
||||
static inline void gen_aau_am(DisasContext *ctx, int chan, int area)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_const_i32(chan);
|
||||
TCGv_i32 t1 = tcg_const_i32(area);
|
||||
|
||||
gen_helper_aau_am(cpu_env, t0, t1);
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
void e2k_aau_execute(DisasContext *ctx)
|
||||
{
|
||||
const UnpackedBundle *bundle = &ctx->bundle;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
Instr instr = { 0 };
|
||||
AauResult *res = &ctx->aau_results[i];
|
||||
|
||||
instr.chan = i;
|
||||
instr.aas = bundle->aas[i + 2];
|
||||
instr.dst = extract16(bundle->aas[i / 2], ((i & 1) ^ 1) * 8, 8);
|
||||
|
||||
if (!bundle->aas_present[i + 2] || instr.opc == 0) {
|
||||
ctx->aau_am[i] = -1;
|
||||
res->type = AAU_RESULT_NONE;
|
||||
continue;
|
||||
}
|
||||
|
||||
gen_mova(ctx, &instr);
|
||||
}
|
||||
|
||||
/* bap */
|
||||
if (ctx->bundle.ss & (1 << 28)) {
|
||||
gen_load_prefetch_program(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void e2k_aau_commit(DisasContext *ctx)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
AauResult *res = &ctx->aau_results[i];
|
||||
|
||||
if (res->type == AAU_RESULT_REG32 || res->type == AAU_RESULT_REG64) {
|
||||
if (IS_REGULAR(res->dst)) {
|
||||
e2k_gen_reg_index_from_wregi(res->index, GET_REGULAR(res->dst));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
AauResult *res = &ctx->aau_results[i];
|
||||
TCGv_i32 zero = tcg_const_i32(0);
|
||||
|
||||
// TODO: aau.tags
|
||||
switch(res->type) {
|
||||
case AAU_RESULT_REG32: {
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
|
||||
/* mova{b,h,w} always write to reg64 */
|
||||
tcg_gen_extu_i32_i64(t0, res->v32);
|
||||
e2k_gen_reg_tag_write_i32(zero, res->index);
|
||||
e2k_gen_reg_write_i64(t0, res->index);
|
||||
tcg_temp_free_i64(t0);
|
||||
break;
|
||||
}
|
||||
case AAU_RESULT_REG64:
|
||||
e2k_gen_reg_tag_write_i64(zero, res->index);
|
||||
e2k_gen_reg_write_i64(res->v64, res->index);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
tcg_temp_free_i32(zero);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
int area = ctx->aau_am[i];
|
||||
if (area == -1 || ((i == 1 || i == 3) && ctx->aau_am[i - 1] == area)) {
|
||||
continue;
|
||||
}
|
||||
gen_aau_am(ctx, i, area);
|
||||
}
|
||||
}
|
4129
target/e2k/translate/alc.c
Normal file
4129
target/e2k/translate/alc.c
Normal file
File diff suppressed because it is too large
Load Diff
683
target/e2k/translate/control.c
Normal file
683
target/e2k/translate/control.c
Normal file
@ -0,0 +1,683 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu.h"
|
||||
#include "exec/log.h"
|
||||
#include "translate.h"
|
||||
|
||||
static inline TCGCond cond_from_advance(int advance)
|
||||
{
|
||||
switch (advance) {
|
||||
case 0x01: return TCG_COND_EQ;
|
||||
case 0x02: return TCG_COND_NE;
|
||||
case 0x03: return TCG_COND_ALWAYS;
|
||||
default: return TCG_COND_NEVER;
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_movcond_flag_i32(TCGv_i32 ret, int flag, TCGv_i32 cond,
|
||||
TCGv_i32 v1, TCGv_i32 v2)
|
||||
{
|
||||
TCGv_i32 one = tcg_const_i32(1);
|
||||
TCGCond c = cond_from_advance(flag);
|
||||
|
||||
tcg_gen_movcond_i32(c, ret, cond, one, v1, v2);
|
||||
tcg_temp_free_i32(one);
|
||||
}
|
||||
|
||||
static inline void gen_dec_wrap(TCGv_i32 ret, TCGv_i32 cur, int n,
|
||||
TCGv_i32 size)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_addi_i32(t0, size, n);
|
||||
tcg_gen_sub_i32(t0, t0, cur);
|
||||
tcg_gen_remu_i32(t0, t0, size);
|
||||
tcg_gen_sub_i32(ret, size, t0);
|
||||
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
static inline void gen_cur_dec(DisasContext *ctx, TCGv_i32 ret, int cond,
|
||||
TCGv_i32 cur, int n, TCGv_i32 size)
|
||||
{
|
||||
TCGLabel *l0 = gen_new_label();
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, size, 0, l0);
|
||||
gen_dec_wrap(t0, cur, n, size);
|
||||
gen_movcond_flag_i32(ret, cond, e2k_cs.ct_cond, t0, cur);
|
||||
gen_set_label(l0);
|
||||
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
static void gen_advance_pcnt(TCGv_i32 ret)
|
||||
{
|
||||
TCGLabel *l0 = gen_new_label();
|
||||
TCGv_i32 t0 = tcg_temp_local_new_i32();
|
||||
TCGv_i32 t1 = tcg_temp_new_i32();
|
||||
|
||||
e2k_gen_pcnt_i32(t0);
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0);
|
||||
tcg_gen_subi_i32(t1, t0, 1);
|
||||
e2k_gen_pcnt_set_i32(t1);
|
||||
gen_set_label(l0);
|
||||
tcg_gen_mov_i32(ret, t0);
|
||||
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
static inline void gen_lcnt_overflow(TCGv_i32 lcnt)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_extu_i32_i64(t0, lcnt);
|
||||
tcg_gen_setcondi_i64(TCG_COND_EQ, t1, t0, 0);
|
||||
tcg_gen_shli_i64(t1, t1, LSR_OVER_OFF);
|
||||
tcg_gen_or_i64(e2k_cs.lsr, e2k_cs.lsr, t1);
|
||||
|
||||
tcg_temp_free_i64(t1);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
static void gen_advance_lcnt(TCGv_i32 ret)
|
||||
{
|
||||
TCGLabel *l0 = gen_new_label();
|
||||
TCGv_i32 t0 = tcg_temp_local_new_i32();
|
||||
|
||||
e2k_gen_lcnt_i32(t0);
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0);
|
||||
tcg_gen_subi_i32(t0, t0, 1);
|
||||
e2k_gen_lcnt_set_i32(t0);
|
||||
|
||||
gen_set_label(l0);
|
||||
gen_lcnt_overflow(t0);
|
||||
tcg_gen_mov_i32(ret, t0);
|
||||
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
static void gen_advance_ecnt(void)
|
||||
{
|
||||
TCGLabel *l0 = gen_new_label();
|
||||
TCGv_i32 t0 = tcg_temp_local_new_i32();
|
||||
TCGv_i32 t1 = tcg_temp_new_i32();
|
||||
|
||||
e2k_gen_ecnt_i32(t0);
|
||||
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0);
|
||||
tcg_gen_subi_i32(t1, t0, 1);
|
||||
e2k_gen_ecnt_set_i32(t1);
|
||||
gen_set_label(l0);
|
||||
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
static void gen_advance_loop_counters(void)
|
||||
{
|
||||
TCGLabel *l0 = gen_new_label();
|
||||
TCGv_i32 t0 = tcg_temp_local_new_i32();
|
||||
TCGv_i32 t1 = tcg_temp_local_new_i32();
|
||||
|
||||
gen_advance_pcnt(t0);
|
||||
gen_advance_lcnt(t1);
|
||||
tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, l0);
|
||||
tcg_gen_brcondi_i32(TCG_COND_NE, t1, 0, l0);
|
||||
gen_advance_ecnt();
|
||||
gen_set_label(l0);
|
||||
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
void e2k_stubs_commit(DisasContext *ctx)
|
||||
{
|
||||
uint32_t ss = ctx->bundle.ss;
|
||||
int alc = extract32(ss, 16, 2);
|
||||
int abp = extract32(ss, 18, 2);
|
||||
int abn = extract32(ss, 21, 2);
|
||||
int abg = extract32(ss, 23, 2);
|
||||
int vfdi = extract32(ss, 26, 1);
|
||||
|
||||
if (alc) {
|
||||
TCGLabel *l0 = gen_new_label();
|
||||
TCGCond cond = cond_from_advance(alc);
|
||||
|
||||
tcg_gen_brcondi_i32(tcg_invert_cond(cond), e2k_cs.ct_cond, 1, l0);
|
||||
gen_advance_loop_counters();
|
||||
gen_set_label(l0);
|
||||
}
|
||||
|
||||
if (abp) {
|
||||
TCGv_i32 t0 = tcg_temp_local_new_i32();
|
||||
tcg_gen_addi_i32(t0, e2k_cs.psize, 1);
|
||||
gen_cur_dec(ctx, e2k_cs.pcur, abp, e2k_cs.pcur, 1, t0);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
if (abn) {
|
||||
gen_cur_dec(ctx, e2k_cs.bcur, abn, e2k_cs.bcur, 2, e2k_cs.bsize);
|
||||
}
|
||||
|
||||
if (abg != 0) {
|
||||
// TODO: impl abg
|
||||
e2k_todo_illop(ctx, "abg");
|
||||
}
|
||||
|
||||
if (vfdi != 0) {
|
||||
// TODO: impl vfdi
|
||||
e2k_todo_illop(ctx, "vfdi");
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_cs0(DisasContext *dc)
|
||||
{
|
||||
typedef enum {
|
||||
NOTHING,
|
||||
IBRANCH,
|
||||
PREF,
|
||||
PUTTSD,
|
||||
DONE,
|
||||
HRET,
|
||||
GLAUNCH,
|
||||
DISP,
|
||||
SDISP,
|
||||
GETTSD,
|
||||
LDISP,
|
||||
RETURN
|
||||
} cs0_type;
|
||||
|
||||
static cs0_type cs0_ops[4][4] = {
|
||||
{IBRANCH, PREF, PUTTSD, DONE},
|
||||
{DISP, NOTHING, SDISP, GETTSD},
|
||||
{DISP, LDISP, SDISP, GETTSD},
|
||||
{DISP, NOTHING, SDISP, RETURN}
|
||||
};
|
||||
const UnpackedBundle *bundle = &dc->bundle;
|
||||
uint32_t cs0 = bundle->cs0;
|
||||
|
||||
unsigned int ctpr = (cs0 & 0xc0000000) >> 30;
|
||||
unsigned int ctp_opc = (cs0 & 0x30000000) >> 28;
|
||||
unsigned int param_type = (cs0 & 0x00000007);
|
||||
cs0_type type = cs0_ops[ctpr][ctp_opc];
|
||||
|
||||
if (type == RETURN && param_type == 1) {
|
||||
type = GETTSD;
|
||||
} else if (type == DONE) {
|
||||
if (param_type == 3) {
|
||||
type = HRET;
|
||||
} else if (param_type == 4) {
|
||||
type = GLAUNCH;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == IBRANCH || type == DONE || type == HRET || type == GLAUNCH) {
|
||||
if (!bundle->ss_present || (bundle->ss & 0x00000c00)) {
|
||||
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
|
||||
} else if ((bundle->ss & 0x1ff)
|
||||
&& !(bundle->cs1_present
|
||||
/* CS1.opc == CALL */
|
||||
&& (bundle->cs1 & 0xf0000000) >> 28 == 5
|
||||
/* CS1.param.ctopc == HCALL */
|
||||
&& (bundle->cs1 & 0x380) >> 7 == 2))
|
||||
{
|
||||
if (type == IBRANCH && dc->ct.type == CT_NONE) {
|
||||
/* C0F2 has `disp' field. In `C0F1' it's called `param'. Is this
|
||||
the only difference between these two formats? Funnily enough,
|
||||
DONE is also C0F2 and thus has `disp', though it obviously
|
||||
makes no sense for it. */
|
||||
uint32_t disp = (cs0 & 0x0fffffff);
|
||||
/* Calculate a signed displacement in bytes. */
|
||||
int32_t sdisp = ((int32_t) (disp << 4)) >> 1;
|
||||
dc->ct.type = CT_IBRANCH;
|
||||
dc->ct.u.target = dc->pc + sdisp;
|
||||
} else {
|
||||
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Note that according to Table B.4.1 it's possible to obtain
|
||||
` gettsd %ctpr{1,2} with an invalid value for CS0.param.type. */
|
||||
if (type == GETTSD && param_type != 1) {
|
||||
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
|
||||
}
|
||||
int ipd = bundle->ss_present ? GET_FIELD(bundle->ss, 30, 2) : 3;
|
||||
if (type == DISP || type == LDISP) {
|
||||
unsigned int disp = GET_FIELD(cs0, 0, 28);
|
||||
/* Calculate a signed displacement in bytes. */
|
||||
int sdisp = ((int) (disp << 4)) >> 1;
|
||||
uint64_t reg = (dc->pc + sdisp) |
|
||||
((uint64_t) CTPR_TAG_DISP << CTPR_TAG_OFF) |
|
||||
((uint64_t) ipd << CTPR_IPD_OFF);
|
||||
if (type == LDISP) {
|
||||
reg |= (uint64_t) CTPR_OPC_LDISP << CTPR_OPC_OFF;
|
||||
}
|
||||
tcg_gen_movi_tl(e2k_cs.ctprs[ctpr - 1], reg);
|
||||
} else if (type == SDISP) {
|
||||
unsigned int disp = GET_FIELD(cs0, 0, 28) << 11;
|
||||
target_ulong base = ((uint64_t) 0xe2 << 40) | disp;
|
||||
uint64_t reg = (dc->pc + base) |
|
||||
((uint64_t) CTPR_TAG_SDISP << CTPR_TAG_OFF) |
|
||||
((uint64_t) ipd << CTPR_IPD_OFF);
|
||||
tcg_gen_movi_tl(e2k_cs.ctprs[ctpr - 1], reg);
|
||||
}
|
||||
|
||||
/* Note that RETURN is said to be COPF1. I can't understand what its
|
||||
`CS0.param' is needed for: all of the bits except the three
|
||||
lowermost ones are undefined, while the latter also known as "type"
|
||||
field should be filled in with zeroes. */
|
||||
if (type == RETURN) {
|
||||
TCGv_i32 t0 = tcg_const_i32(ipd);
|
||||
|
||||
if (ctpr != 3) {
|
||||
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPN);
|
||||
}
|
||||
|
||||
gen_helper_prep_return(e2k_cs.ctprs[2], cpu_env, t0);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
/* GETTSD has as meaningless `CS0.param' as RETURN. The only
|
||||
difference is that its `CS0.param.type' should be equal to `1'. I
|
||||
wonder if I should check for that and output something like
|
||||
"invalid gettsd" if this turns out not to be the case . . . */
|
||||
if (type == GETTSD) {
|
||||
// TODO: gettsd
|
||||
e2k_todo_illop(dc, "gettsd");
|
||||
}
|
||||
|
||||
if (type == PUTTSD) {
|
||||
// unsigned int disp = (cs0 & 0x0fffffff);
|
||||
// int sgnd_disp = ((int) (disp << 4)) >> 1;
|
||||
/* PUTTSD obviously doesn't take %ctpr{j} parameter. TODO: beware of
|
||||
an optional predicate which may control its execution which is
|
||||
encoded via `SS.ctcond.psrc' and `SS.ts_opc == PUTTSDC{P,N}' in
|
||||
case of `SS.type == 1' (see C.21.4). I wonder if `ct %ctpr<j>'
|
||||
encoded in `SS.ctop' under the same `SS.ctcond' takes an effect in
|
||||
such a case. */
|
||||
// my_printf ("%s0x%llx", type == PUTTSD ? "" : ", ",
|
||||
/* FIXME: this way I ensure that it'll work correctly
|
||||
both on 32 and 64-bit hosts. */
|
||||
// (unsigned long long) (instr_addr + sgnd_disp));
|
||||
// TODO: puttsd
|
||||
e2k_todo_illop(dc, "puttsd");
|
||||
}
|
||||
|
||||
if (type == PREF) {
|
||||
// unsigned int pdisp = (bundle->cs0 & 0x0ffffff0) >> 4;
|
||||
// unsigned int ipd = (bundle->cs0 & 0x00000008) >> 3;
|
||||
// unsigned int prefr = bundle->cs0 & 0x00000007;
|
||||
// TODO: pref
|
||||
e2k_todo_illop(dc, "pref");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_cs1(DisasContext *dc)
|
||||
{
|
||||
enum {
|
||||
SETR0,
|
||||
SETR1,
|
||||
SETEI,
|
||||
WAIT,
|
||||
SETBR,
|
||||
CALL,
|
||||
MAS_OPC,
|
||||
FLUSHR,
|
||||
BG
|
||||
};
|
||||
|
||||
const UnpackedBundle *bundle = &dc->bundle;
|
||||
unsigned int cs1 = bundle->cs1;
|
||||
unsigned int opc = (cs1 & 0xf0000000) >> 28;
|
||||
|
||||
if (opc == SETEI) {
|
||||
bool sft = GET_BIT(cs1, 27);
|
||||
|
||||
if (sft) {
|
||||
if (dc->version >= 2) {
|
||||
// TODO: setsft
|
||||
e2k_todo_illop(dc, "setsft");
|
||||
} else {
|
||||
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
|
||||
}
|
||||
} else {
|
||||
// uint8_t eir = GET_FIELD_LEN(cs1, 0, 8);
|
||||
// TODO: setei
|
||||
e2k_todo_illop(dc, "setei");
|
||||
}
|
||||
} else if (opc == WAIT) {
|
||||
// unsigned int ma_c = (cs1 & 0x00000020) >> 5;
|
||||
// unsigned int fl_c = (cs1 & 0x00000010) >> 4;
|
||||
unsigned int ld_c = (cs1 & 0x00000008) >> 3;
|
||||
unsigned int st_c = (cs1 & 0x00000004) >> 2;
|
||||
// unsigned int all_e = (cs1 & 0x00000002) >> 1;
|
||||
// unsigned int all_c = cs1 & 0x00000001;
|
||||
|
||||
if (dc->version >= 5) {
|
||||
/* `sa{l,s}' fields are `elbrus-v5'-specific. Each of them makes sense
|
||||
only in the presence of `{ld,st}_c == 1' respectively. */
|
||||
if (ld_c) {
|
||||
// unsigned int sal = (cs1 & 0x00000100) >> 8;
|
||||
// my_printf ("sal = %d, ", sal);
|
||||
}
|
||||
|
||||
if (st_c) {
|
||||
// unsigned int sas = (cs1 & 0x00000080) >> 7;
|
||||
// my_printf ("sas = %d, ", sas);
|
||||
}
|
||||
}
|
||||
|
||||
if (dc->version >= 2) {
|
||||
/* `trap' field was introduced starting from `elbrus-v2'. */
|
||||
// unsigned int trap = (cs1 & 0x00000040) >> 6;
|
||||
// my_printf ("trap = %d, ", trap);
|
||||
}
|
||||
// TODO: wait
|
||||
e2k_todo(dc, "wait");
|
||||
// my_printf ("ma_c = %d, fl_c = %d, ld_c = %d, st_c = %d, all_e = %d, "
|
||||
// "all_c = %d", ma_c, fl_c, ld_c, st_c, all_e, all_c);
|
||||
} else if (opc == CALL) {
|
||||
unsigned int ctop = (bundle->ss & 0x00000c00) >> 10;
|
||||
if (ctop) {
|
||||
dc->ct.type = CT_CALL;
|
||||
dc->ct.wbs = GET_FIELD(cs1, 0, 7);
|
||||
} else {
|
||||
unsigned int cs1_ctopc = (cs1 & 0x380) >> 7;
|
||||
/* CS1.param.ctpopc == HCALL. CS0 is required to encode HCALL. */
|
||||
if (cs1_ctopc == 2 && bundle->cs0_present &&
|
||||
dc->ct.type == CT_NONE)
|
||||
{
|
||||
unsigned int cs0 = bundle->cs0;
|
||||
unsigned int cs0_opc = (cs0 & 0xf0000000) >> 28;
|
||||
if (cs0_opc == 0) {
|
||||
// unsigned int hdisp = (cs0 & 0x1e) >> 1;
|
||||
// TODO: hcall hdisp, wbs ? cond
|
||||
e2k_todo_illop(dc, "hcall");
|
||||
}
|
||||
} else {
|
||||
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
|
||||
}
|
||||
}
|
||||
} else if (opc == MAS_OPC) {
|
||||
dc->mas[0] = extract32(cs1, 21, 7);
|
||||
dc->mas[2] = extract32(cs1, 14, 7);
|
||||
dc->mas[3] = extract32(cs1, 7, 7);
|
||||
dc->mas[5] = extract32(cs1, 0, 7);
|
||||
} else if (opc == FLUSHR) {
|
||||
if (cs1 & 0x00000001) {
|
||||
// TODO: flushr
|
||||
e2k_todo_illop(dc, "flushr");
|
||||
}
|
||||
|
||||
if (cs1 & 0x00000002) {
|
||||
// TODO: flushc
|
||||
e2k_todo_illop(dc, "flushc");
|
||||
}
|
||||
} else if (opc == BG) {
|
||||
// unsigned int chkm4 = (cs1 & 0x00010000) >> 16;
|
||||
// unsigned int dmask = (cs1 & 0x0000ff00) >> 8;
|
||||
// unsigned int umsk = cs1 & 0x000000ff;
|
||||
|
||||
// TODO: vfbg
|
||||
e2k_todo_illop(dc, "vfbg");
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_jmp(DisasContext *ctx)
|
||||
{
|
||||
int cond_type = extract32(ctx->bundle.ss, 5, 4);
|
||||
int ctpr = extract32(ctx->bundle.ss, 10, 2);
|
||||
|
||||
if (ctpr != 0) {
|
||||
ctx->ct.type = CT_JUMP;
|
||||
ctx->ct.u.ctpr = e2k_cs.ctprs[ctpr - 1];
|
||||
}
|
||||
|
||||
ctx->ct.is_branch = cond_type > 1;
|
||||
if (cond_type == 1) {
|
||||
tcg_gen_movi_i32(e2k_cs.ct_cond, 1);
|
||||
} else if (cond_type > 1) {
|
||||
uint8_t psrc = extract32(ctx->bundle.ss, 0, 5);
|
||||
TCGv_i32 pcond = tcg_temp_local_new_i32();
|
||||
TCGv_i32 lcond = tcg_temp_local_new_i32();
|
||||
|
||||
switch (cond_type) {
|
||||
case 0x2:
|
||||
case 0x6:
|
||||
case 0xf:
|
||||
/* %predN */
|
||||
e2k_gen_preg_i32(pcond, psrc);
|
||||
break;
|
||||
case 0x3:
|
||||
case 0x7:
|
||||
case 0xe: {
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
e2k_gen_preg_i32(t0, psrc);
|
||||
tcg_gen_setcondi_i32(TCG_COND_EQ, pcond, t0, 0);
|
||||
tcg_temp_free_i32(t0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cond_type) {
|
||||
case 0x4:
|
||||
case 0x6:
|
||||
case 0xe:
|
||||
/* #LOOP_END */
|
||||
e2k_gen_is_loop_end_i32(lcond);
|
||||
break;
|
||||
case 0x5:
|
||||
case 0x7:
|
||||
case 0xf: { /* #NOT_LOOP_END */
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
e2k_gen_is_loop_end_i32(t0);
|
||||
tcg_gen_setcondi_i32(TCG_COND_EQ, lcond, t0, 0);
|
||||
tcg_temp_free_i32(t0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (cond_type) {
|
||||
case 0x2:
|
||||
case 0x3:
|
||||
/* {,~}%predN */
|
||||
tcg_gen_mov_i32(e2k_cs.ct_cond, pcond);
|
||||
break;
|
||||
case 0x4:
|
||||
case 0x5:
|
||||
/* #{,NOT_}LOOP_END */
|
||||
tcg_gen_mov_i32(e2k_cs.ct_cond, lcond);
|
||||
break;
|
||||
case 0x6:
|
||||
case 0xe: {
|
||||
/* {,~}%predN || #LOOP_END */
|
||||
TCGv_i32 z = tcg_const_i32(0);
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_or_i32(t0, pcond, lcond);
|
||||
tcg_gen_movcond_i32(TCG_COND_EQ, e2k_cs.ct_cond,
|
||||
ctx->is_prologue, z, t0, lcond);
|
||||
tcg_temp_free_i32(t0);
|
||||
tcg_temp_free_i32(z);
|
||||
break;
|
||||
}
|
||||
case 0x7:
|
||||
case 0xf: {
|
||||
/* {,~}%predN && #NOT_LOOP_END */
|
||||
TCGv_i32 z = tcg_const_i32(0);
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_and_i32(t0, pcond, lcond);
|
||||
tcg_gen_movcond_i32(TCG_COND_EQ, e2k_cs.ct_cond,
|
||||
ctx->is_prologue, z, t0, lcond);
|
||||
tcg_temp_free_i32(t0);
|
||||
tcg_temp_free_i32(z);
|
||||
break;
|
||||
}
|
||||
case 0x8:
|
||||
/* %MLOCK || %dt_alM */
|
||||
if (psrc & 0xf) {
|
||||
// static const int conv[] = {0, 1, 3, 4};
|
||||
int i;
|
||||
|
||||
e2k_todo(ctx, "%%MLOCK || %%dt_alM");
|
||||
// %dt_al
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (psrc & (1 << i)) {
|
||||
// i
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* %MLOCK */
|
||||
if (ctx->mlock) {
|
||||
tcg_gen_mov_i32(e2k_cs.ct_cond, ctx->mlock);
|
||||
} else {
|
||||
tcg_gen_movi_i32(e2k_cs.ct_cond, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x9: {
|
||||
/* `lock_cond || pl_cond' control transfer conditions. */
|
||||
unsigned int type = (psrc & 0x18) >> 3;
|
||||
if (type == 0) {
|
||||
// static const int cmp_num_to_alc[] = {0, 1, 3, 4};
|
||||
// unsigned int cmp_num = (psrc & 0x6) >> 1;
|
||||
// unsigned int neg = psrc & 0x1;
|
||||
//
|
||||
// my_printf ("%%MLOCK || %s%%cmp%d", neg ? "~" : "",
|
||||
// cmp_num_to_alc[cmp_num]);
|
||||
e2k_todo(ctx, "%%MLOCK || %%cmpN");
|
||||
} else if (type == 1) {
|
||||
// unsigned int cmp_jk = (psrc & 0x4) >> 2;
|
||||
// unsigned int negj = (psrc & 0x2) >> 1;
|
||||
// unsigned int negk = psrc & 0x1;
|
||||
|
||||
// my_printf ("%%MLOCK || %s%%cmp%d || %s%%cmp%d",
|
||||
// negj ? "~" : "", cmp_jk == 0 ? 0 : 3,
|
||||
// negk ? "~" : "", cmp_jk == 0 ? 1 : 4);
|
||||
e2k_todo(ctx, "%%MLOCK || %%cmpN || %%cmpM");
|
||||
} else if (type == 2) {
|
||||
// unsigned int clp_num = (psrc & 0x6) >> 1;
|
||||
// unsigned int neg = psrc & 0x1;
|
||||
|
||||
// "%%MLOCK || %s%%clp%d", neg ? "~" : "", clp_num
|
||||
e2k_todo(ctx, "%%MLOCK || %%clpN");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
e2k_todo_illop(ctx, "undefined control transfer type %#x", cond_type);
|
||||
break;
|
||||
}
|
||||
|
||||
tcg_temp_free_i32(lcond);
|
||||
tcg_temp_free_i32(pcond);
|
||||
}
|
||||
}
|
||||
|
||||
void e2k_control_window_change(DisasContext *dc)
|
||||
{
|
||||
enum {
|
||||
SETR0,
|
||||
SETR1,
|
||||
SETEI,
|
||||
WAIT,
|
||||
SETBR,
|
||||
CALL,
|
||||
MAS_OPC,
|
||||
FLUSHR,
|
||||
BG
|
||||
};
|
||||
|
||||
const UnpackedBundle *bundle = &dc->bundle;
|
||||
uint32_t cs1 = bundle->cs1;
|
||||
int opc = extract32(cs1, 28, 4);
|
||||
|
||||
if (!dc->bundle.cs1_present) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (opc == SETR0 || opc == SETR1 || opc == SETBR) {
|
||||
bool setbp = (cs1 >> 27) & 1;
|
||||
bool setbn = (cs1 >> 26) & 1;
|
||||
|
||||
if (opc == SETR1) {
|
||||
if (!bundle->lts_present[0]) {
|
||||
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
|
||||
} else {
|
||||
/* Find out if VFRPSZ is always encoded together with SETWD. This
|
||||
seems to be the case even if no SETWD has been explicitly
|
||||
specified. */
|
||||
// unsigned int rpsz = (bundle->lts[0] & 0x0001f000) >> 12;
|
||||
e2k_todo(dc, "vfrpsz");
|
||||
}
|
||||
}
|
||||
|
||||
if (opc == SETR0 || opc == SETR1) {
|
||||
if (!bundle->lts_present[0]) {
|
||||
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
|
||||
} else {
|
||||
TCGv_i32 lts = tcg_const_i32(bundle->lts[0]);
|
||||
|
||||
gen_helper_setwd(cpu_env, lts);
|
||||
tcg_temp_free_i32(lts);
|
||||
}
|
||||
}
|
||||
|
||||
if (setbn) {
|
||||
int rbs = GET_FIELD(cs1, BR_RBS_OFF, BR_RBS_LEN);
|
||||
int rsz = GET_FIELD(cs1, BR_RSZ_OFF, BR_RSZ_LEN);
|
||||
int rcur = GET_FIELD(cs1, BR_RCUR_OFF, BR_RCUR_LEN);
|
||||
|
||||
tcg_gen_movi_i32(e2k_cs.boff, rbs * 2);
|
||||
tcg_gen_movi_i32(e2k_cs.bsize, (rsz + 1) * 2);
|
||||
tcg_gen_movi_i32(e2k_cs.bcur, rcur * 2);
|
||||
}
|
||||
|
||||
if (setbp) {
|
||||
int psz = GET_FIELD(cs1, BR_PSZ_OFF, BR_PSZ_LEN);
|
||||
|
||||
tcg_gen_movi_i32(e2k_cs.psize, psz);
|
||||
tcg_gen_movi_i32(e2k_cs.pcur, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_prologue_epilogue(DisasContext *ctx)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
|
||||
ctx->is_prologue = e2k_get_temp_i32(ctx);
|
||||
e2k_gen_pcnt_i32(t0);
|
||||
tcg_gen_setcondi_i32(TCG_COND_NE, ctx->is_prologue, t0, 0);
|
||||
|
||||
ctx->is_epilogue = e2k_get_temp_i32(ctx);
|
||||
e2k_gen_lcnt_i32(t0);
|
||||
tcg_gen_setcondi_i32(TCG_COND_EQ, ctx->is_epilogue, t0, 0);
|
||||
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
void e2k_control_execute(DisasContext *ctx)
|
||||
{
|
||||
ctx->ct.type = CT_NONE;
|
||||
ctx->loop_mode = (ctx->bundle.hs & (1 << 10)) != 0;
|
||||
|
||||
gen_prologue_epilogue(ctx);
|
||||
|
||||
if (ctx->bundle.ss_present) {
|
||||
gen_jmp(ctx);
|
||||
}
|
||||
|
||||
if (ctx->bundle.cs0_present) {
|
||||
gen_cs0(ctx);
|
||||
}
|
||||
|
||||
if (ctx->bundle.cs1_present) {
|
||||
gen_cs1(ctx);
|
||||
}
|
||||
}
|
213
target/e2k/translate/plu.c
Normal file
213
target/e2k/translate/plu.c
Normal file
@ -0,0 +1,213 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu.h"
|
||||
#include "exec/log.h"
|
||||
#include "translate.h"
|
||||
|
||||
static void gen_get_lp(TCGv_i32 ret, uint16_t clp, int offset, TCGv_i32 lp[7])
|
||||
{
|
||||
int p = GET_FIELD(clp, offset, 3);
|
||||
int neg = GET_BIT(clp, offset + 3);
|
||||
|
||||
tcg_gen_xori_i32(ret, lp[p], neg);
|
||||
}
|
||||
|
||||
void e2k_gen_cond_i32(DisasContext *ctx, TCGv_i32 ret, uint8_t psrc)
|
||||
{
|
||||
if (psrc & 0x80) {
|
||||
if (psrc == 0xc0) {
|
||||
// TODO: %bgrpred
|
||||
qemu_log_mask(LOG_UNIMP, "%#lx: %%bgrpred is not implemented!\n", ctx->pc);
|
||||
abort();
|
||||
} else if ((psrc & 0xe0) == 0xc0) {
|
||||
// TODO: %rndpredN
|
||||
qemu_log_mask(LOG_UNIMP, "%#lx: %%rndpred is not implemented!\n", ctx->pc);
|
||||
abort();
|
||||
} else {
|
||||
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
|
||||
}
|
||||
} else {
|
||||
int idx = extract8(psrc, 0, 5);
|
||||
if (psrc == 0) {
|
||||
// %lcntex
|
||||
e2k_gen_lcntex(ret);
|
||||
} else if ((psrc & 0x40) == 0) {
|
||||
// TODO: %spredMASK
|
||||
qemu_log_mask(LOG_UNIMP, "%#lx: %%spred is not implemented!\n", ctx->pc);
|
||||
abort();
|
||||
} else if ((psrc & 0x60) == 0x60) {
|
||||
// %predN
|
||||
e2k_gen_preg_i32(ret, idx);
|
||||
} else {
|
||||
// %pcntN
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
|
||||
e2k_gen_pcnt_i32(t0);
|
||||
tcg_gen_setcondi_i32(TCG_COND_LEU, ret, t0, idx);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scan_needed(const UnpackedBundle *bundle, int need[7])
|
||||
{
|
||||
bool once_more = true;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (bundle->pls_present[i] && GET_BIT(bundle->pls[i], 5)) {
|
||||
need[4 + i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
while (once_more) {
|
||||
once_more = false;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
int p0, p1;
|
||||
|
||||
if (need[4 + i] != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p0 = GET_FIELD(bundle->pls[i], 10, 3);
|
||||
p1 = GET_FIELD(bundle->pls[i], 6, 3);
|
||||
|
||||
if (p0 < 7 && need[p0] == 0) {
|
||||
need[p0] = 1;
|
||||
|
||||
if (p0 >= 4) {
|
||||
once_more = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (p1 < 7 && need[p1] == 0) {
|
||||
need[p1] = 1;
|
||||
|
||||
if (p1 >= 4) {
|
||||
once_more = true;
|
||||
}
|
||||
}
|
||||
|
||||
need[4 + i] = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void e2k_plu_execute(DisasContext *ctx)
|
||||
{
|
||||
const UnpackedBundle *bundle = &ctx->bundle;
|
||||
int need[7] = { 0 };
|
||||
unsigned int i;
|
||||
TCGv_i32 lp[7];
|
||||
|
||||
scan_needed(bundle, need);
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
if (need[i]) {
|
||||
lp[i] = tcg_temp_new_i32();
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
ctx->pl_results[i].reg = -1;
|
||||
|
||||
if (!bundle->pls_present[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < 2) {
|
||||
if (need[i * 2]) {
|
||||
int elp = GET_FIELD(bundle->pls[i], 24, 7);
|
||||
e2k_gen_cond_i32(ctx, lp[i * 2], elp);
|
||||
}
|
||||
|
||||
if (need[i * 2 + 1]) {
|
||||
int elp = GET_FIELD(bundle->pls[i], 16, 7);
|
||||
e2k_gen_cond_i32(ctx, lp[i * 2 + 1], elp);
|
||||
}
|
||||
}
|
||||
|
||||
if (need[4 + i]) {
|
||||
uint16_t clp = GET_FIELD(bundle->pls[i], 0, 16);
|
||||
int opc = GET_FIELD(clp, 14, 2);
|
||||
TCGv_i32 p0 = tcg_temp_new_i32();
|
||||
TCGv_i32 p1 = tcg_temp_new_i32();
|
||||
int vdst = GET_BIT(clp, 5);
|
||||
int pdst = GET_FIELD(clp, 0, 5);
|
||||
|
||||
// TODO: check clp arg
|
||||
// {C/M}LP0 0, 1 => 4
|
||||
// {C/M}LP1 0, 1, 2, 3, 4 => 5
|
||||
// {C/M}LP2 0, 1, 2, 3, 4, 5 => 6
|
||||
// maximal cascading is 2
|
||||
|
||||
gen_get_lp(p0, clp, 10, lp);
|
||||
gen_get_lp(p1, clp, 6, lp);
|
||||
|
||||
if (vdst) {
|
||||
ctx->pl_results[i].reg = pdst;
|
||||
ctx->pl_results[i].value = e2k_get_temp_i32(ctx);
|
||||
}
|
||||
|
||||
switch (opc) {
|
||||
case 0: /* andp */
|
||||
// FIXME: what is the difference between `andp` and `landp`?
|
||||
case 1: /* landp */
|
||||
tcg_gen_and_i32(lp[4 + i], p0, p1);
|
||||
if (vdst) {
|
||||
tcg_gen_mov_i32(ctx->pl_results[i].value, lp[4 + i]);
|
||||
}
|
||||
break;
|
||||
case 3: { /* movep */
|
||||
// FIXME: clp cannot read result of movep???
|
||||
tcg_gen_and_i32(lp[4 + i], p0, p1);
|
||||
|
||||
if (vdst) {
|
||||
TCGv_i32 one = tcg_const_i32(1);
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
TCGv_i32 t1 = tcg_temp_new_i32();
|
||||
|
||||
e2k_gen_preg_i64(t0, pdst);
|
||||
tcg_gen_extrl_i64_i32(t1, t0);
|
||||
tcg_gen_movcond_i32(TCG_COND_EQ, ctx->pl_results[i].value,
|
||||
p0, one, p1, t1);
|
||||
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i64(t0);
|
||||
tcg_temp_free_i32(one);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
if (need[i]) {
|
||||
tcg_temp_free_i32(lp[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void e2k_plu_commit(DisasContext *ctx)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
TCGv_i64 t0;
|
||||
|
||||
if (ctx->pl_results[i].reg < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
t0 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_extu_i32_i64(t0, ctx->pl_results[i].value);
|
||||
e2k_gen_store_preg(ctx->pl_results[i].reg, t0);
|
||||
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
}
|
302
target/e2k/translate/state.c
Normal file
302
target/e2k/translate/state.c
Normal file
@ -0,0 +1,302 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu.h"
|
||||
#include "exec/log.h"
|
||||
#include "translate.h"
|
||||
|
||||
static inline void gen_ptr_from_index(TCGv_ptr ret, TCGv_ptr ptr, TCGv_i32 idx,
|
||||
int size)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
TCGv_ptr t1 = tcg_temp_new_ptr();
|
||||
|
||||
tcg_gen_muli_i32(t0, idx, size);
|
||||
tcg_gen_ext_i32_ptr(t1, t0);
|
||||
tcg_gen_add_ptr(ret, ptr, t1);
|
||||
|
||||
tcg_temp_free_ptr(t1);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
static inline void gen_preg_index(TCGv_i32 ret, int idx)
|
||||
{
|
||||
TCGv_i32 i = tcg_const_i32(idx);
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
TCGv_i32 t1 = tcg_temp_new_i32();
|
||||
TCGv_i32 t2 = tcg_temp_new_i32();
|
||||
TCGv_i32 t3 = tcg_temp_new_i32();
|
||||
|
||||
assert(idx < 32);
|
||||
|
||||
tcg_gen_addi_i32(t0, e2k_cs.psize, 1);
|
||||
tcg_gen_addi_i32(t1, e2k_cs.pcur, idx);
|
||||
tcg_gen_remu_i32(t2, t1, t0);
|
||||
tcg_gen_movi_i32(t3, idx);
|
||||
tcg_gen_movcond_i32(TCG_COND_LEU, ret, i, e2k_cs.psize, t2, t3);
|
||||
|
||||
tcg_temp_free_i32(t3);
|
||||
tcg_temp_free_i32(t2);
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i32(t0);
|
||||
tcg_temp_free_i32(i);
|
||||
}
|
||||
|
||||
static void gen_preg_offset(TCGv_i64 ret, int idx)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
TCGv_i32 t1 = tcg_temp_new_i32();
|
||||
|
||||
gen_preg_index(t0, idx);
|
||||
tcg_gen_muli_i32(t1, t0, 2);
|
||||
tcg_gen_extu_i32_i64(ret, t1);
|
||||
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
static void gen_preg_clear(TCGv_i64 ret, TCGv_i64 offset)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_const_i64(3);
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
TCGv_i64 t2 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_shl_i64(t1, t0, offset);
|
||||
tcg_gen_not_i64(t2, t1);
|
||||
tcg_gen_and_i64(ret, t2, e2k_cs.pregs);
|
||||
|
||||
tcg_temp_free_i64(t2);
|
||||
tcg_temp_free_i64(t1);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
void e2k_gen_preg_i64(TCGv_i64 ret, int reg)
|
||||
{
|
||||
TCGv_i64 one = tcg_const_i64(1);
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
TCGv_i64 t2 = tcg_temp_new_i64();
|
||||
|
||||
gen_preg_offset(t0, reg);
|
||||
tcg_gen_shl_i64(t1, one, t0);
|
||||
tcg_gen_and_i64(t2, e2k_cs.pregs, t1);
|
||||
tcg_gen_setcondi_i64(TCG_COND_NE, ret, t2, 0);
|
||||
|
||||
tcg_temp_free_i64(t2);
|
||||
tcg_temp_free_i64(t1);
|
||||
tcg_temp_free_i64(t0);
|
||||
tcg_temp_free_i64(one);
|
||||
}
|
||||
|
||||
void e2k_gen_preg_i32(TCGv_i32 ret, int reg)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
|
||||
e2k_gen_preg_i64(t0, reg);
|
||||
tcg_gen_extrl_i64_i32(ret, t0);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
TCGv_i64 e2k_get_preg(DisasContext *dc, int reg)
|
||||
{
|
||||
TCGv_i64 ret = e2k_get_temp_i64(dc);
|
||||
e2k_gen_preg_i64(ret, reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void e2k_gen_store_preg(int idx, TCGv_i64 val)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
TCGv_i64 t2 = tcg_temp_new_i64();
|
||||
TCGv_i64 t3 = tcg_temp_new_i64();
|
||||
|
||||
gen_preg_offset(t0, idx);
|
||||
gen_preg_clear(t1, t0);
|
||||
tcg_gen_andi_i64(t2, val, 3);
|
||||
tcg_gen_shl_i64(t3, val, t0);
|
||||
tcg_gen_or_i64(e2k_cs.pregs, t1, t3);
|
||||
|
||||
tcg_temp_free_i64(t3);
|
||||
tcg_temp_free_i64(t2);
|
||||
tcg_temp_free_i64(t1);
|
||||
tcg_temp_free_i64(t0);
|
||||
}
|
||||
|
||||
static inline void gen_reg_tag_ptr(TCGv_ptr ret, TCGv_i32 idx)
|
||||
{
|
||||
TCGv_ptr t0 = tcg_temp_new_ptr();
|
||||
TCGv_ptr t1 = tcg_temp_new_ptr();
|
||||
|
||||
tcg_gen_ext_i32_ptr(t0, idx);
|
||||
tcg_gen_addi_ptr(t1, cpu_env, offsetof(CPUE2KState, tags));
|
||||
tcg_gen_add_ptr(ret, t1, t0);
|
||||
|
||||
tcg_temp_free_ptr(t1);
|
||||
tcg_temp_free_ptr(t0);
|
||||
}
|
||||
|
||||
void e2k_gen_reg_tag_read_i64(TCGv_i32 ret, TCGv_i32 idx)
|
||||
{
|
||||
TCGv_ptr t0 = tcg_temp_new_ptr();
|
||||
|
||||
gen_reg_tag_ptr(t0, idx);
|
||||
tcg_gen_ld8u_i32(ret, t0, 0);
|
||||
tcg_temp_free_ptr(t0);
|
||||
}
|
||||
|
||||
void e2k_gen_reg_tag_read_i32(TCGv_i32 ret, TCGv_i32 idx)
|
||||
{
|
||||
TCGv_ptr t0 = tcg_temp_new_ptr();
|
||||
TCGv_i32 t1 = tcg_temp_new_i32();
|
||||
|
||||
gen_reg_tag_ptr(t0, idx);
|
||||
tcg_gen_ld8u_i32(t1, t0, 0);
|
||||
tcg_gen_andi_i32(ret, t1, GEN_MASK(0, E2K_TAG_SIZE));
|
||||
tcg_temp_free_ptr(t0);
|
||||
}
|
||||
|
||||
static inline void gen_tag_check(TCGv_i32 ret, TCGv_i32 tag)
|
||||
{
|
||||
// FIXME: what CPU does if tag is greater than 1?
|
||||
tcg_gen_setcondi_i32(TCG_COND_NE, ret, tag, 0);
|
||||
}
|
||||
|
||||
void e2k_gen_reg_tag_check_i64(TCGv_i32 ret, TCGv_i32 tag)
|
||||
{
|
||||
gen_tag_check(ret, tag);
|
||||
}
|
||||
|
||||
void e2k_gen_reg_tag_check_i32(TCGv_i32 ret, TCGv_i32 tag)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
|
||||
e2k_gen_reg_tag_extract_lo(t0, tag);
|
||||
gen_tag_check(ret, t0);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
void e2k_gen_reg_tag_write_i64(TCGv_i32 value, TCGv_i32 idx)
|
||||
{
|
||||
TCGv_ptr t0 = tcg_temp_new_ptr();
|
||||
|
||||
gen_reg_tag_ptr(t0, idx);
|
||||
tcg_gen_st8_i32(value, t0, 0);
|
||||
tcg_temp_free_ptr(t0);
|
||||
}
|
||||
|
||||
void e2k_gen_reg_tag_write_i32(TCGv_i32 value, TCGv_i32 idx)
|
||||
{
|
||||
TCGv_ptr t0 = tcg_temp_new_ptr();
|
||||
TCGv_i32 t1 = tcg_temp_new_i32();
|
||||
TCGv_i32 t2 = tcg_temp_new_i32();
|
||||
|
||||
gen_reg_tag_ptr(t0, idx);
|
||||
tcg_gen_ld8u_i32(t1, t0, 0);
|
||||
tcg_gen_deposit_i32(t2, t1, value, 0, E2K_TAG_SIZE);
|
||||
tcg_gen_st8_i32(t2, t0, 0);
|
||||
|
||||
tcg_temp_free_i32(t2);
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_ptr(t0);
|
||||
}
|
||||
|
||||
static inline void gen_reg_index_from_wreg(TCGv_i32 ret, TCGv_i32 idx)
|
||||
{
|
||||
TCGLabel *l0 = gen_new_label();
|
||||
TCGv_i32 t0 = tcg_temp_local_new_i32();
|
||||
TCGv_i32 t1 = tcg_temp_new_i32();
|
||||
TCGv_i32 t2;
|
||||
|
||||
tcg_gen_mov_i32(t0, idx);
|
||||
|
||||
tcg_gen_brcond_i32(TCG_COND_LTU, t0, e2k_cs.wd_size, l0);
|
||||
e2k_gen_exception(E2K_EXCP_MAPERR);
|
||||
gen_set_label(l0);
|
||||
|
||||
tcg_gen_add_i32(t1, e2k_cs.wd_base, t0);
|
||||
tcg_temp_free_i32(t0);
|
||||
t2 = tcg_const_i32(E2K_NR_COUNT);
|
||||
tcg_gen_remu_i32(ret, t1, t2);
|
||||
tcg_temp_free_i32(t1);
|
||||
tcg_temp_free_i32(t2);
|
||||
}
|
||||
|
||||
void e2k_gen_reg_index_from_wregi(TCGv_i32 ret, int idx)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_const_i32(idx);
|
||||
gen_reg_index_from_wreg(ret, t0);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
|
||||
void e2k_gen_reg_index_from_bregi(TCGv_i32 ret, int idx)
|
||||
{
|
||||
TCGLabel *l0 = gen_new_label();
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
TCGv_i32 t1 = tcg_temp_new_i32();
|
||||
TCGv_i32 t2 = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_brcondi_i32(tcg_invert_cond(TCG_COND_LTU), e2k_cs.bsize, idx, l0);
|
||||
e2k_gen_exception(E2K_EXCP_MAPERR);
|
||||
gen_set_label(l0);
|
||||
|
||||
tcg_gen_addi_i32(t0, e2k_cs.bcur, idx);
|
||||
tcg_gen_remu_i32(t1, t0, e2k_cs.bsize);
|
||||
tcg_temp_free_i32(t0);
|
||||
tcg_gen_add_i32(t2, e2k_cs.boff, t1);
|
||||
tcg_temp_free_i32(t1);
|
||||
gen_reg_index_from_wreg(ret, t2);
|
||||
tcg_temp_free_i32(t2);
|
||||
}
|
||||
|
||||
void e2k_gen_reg_index_from_gregi(TCGv_i32 ret, int idx)
|
||||
{
|
||||
// TODO: based global registers index
|
||||
tcg_gen_movi_i32(ret, E2K_NR_COUNT + idx);
|
||||
}
|
||||
|
||||
static inline void gen_reg_ptr(TCGv_ptr ret, TCGv_i32 idx)
|
||||
{
|
||||
TCGv_ptr t0 = tcg_temp_new_ptr();
|
||||
|
||||
tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, regs));
|
||||
gen_ptr_from_index(ret, t0, idx, 8);
|
||||
tcg_temp_free_ptr(t0);
|
||||
}
|
||||
|
||||
static inline void gen_xreg_ptr(TCGv_ptr ret, TCGv_i32 idx)
|
||||
{
|
||||
TCGv_ptr t0 = tcg_temp_new_ptr();
|
||||
|
||||
tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, xregs));
|
||||
gen_ptr_from_index(ret, t0, idx, 8);
|
||||
tcg_temp_free_ptr(t0);
|
||||
}
|
||||
|
||||
#define GEN_REG_READ(name, ty, ptr_func, ld_func) \
|
||||
void name(ty ret, TCGv_i32 idx) \
|
||||
{ \
|
||||
TCGv_ptr t0 = tcg_temp_new_ptr(); \
|
||||
ptr_func(t0, idx); \
|
||||
ld_func(ret, t0, 0); \
|
||||
tcg_temp_free_ptr(t0); \
|
||||
}
|
||||
|
||||
#define GEN_REG_WRITE(name, ty, ptr_func, st_func) \
|
||||
void name(ty value, TCGv_i32 idx) \
|
||||
{ \
|
||||
TCGv_ptr t0 = tcg_temp_new_ptr(); \
|
||||
ptr_func(t0, idx); \
|
||||
st_func(value, t0, 0); \
|
||||
tcg_temp_free_ptr(t0); \
|
||||
}
|
||||
|
||||
GEN_REG_READ(e2k_gen_reg_read_i64, TCGv_i64, gen_reg_ptr, tcg_gen_ld_i64)
|
||||
GEN_REG_READ(e2k_gen_reg_read_i32, TCGv_i32, gen_reg_ptr, tcg_gen_ld_i32)
|
||||
GEN_REG_WRITE(e2k_gen_reg_write_i64, TCGv_i64, gen_reg_ptr, tcg_gen_st_i64)
|
||||
GEN_REG_WRITE(e2k_gen_reg_write_i32, TCGv_i32, gen_reg_ptr, tcg_gen_st_i32)
|
||||
|
||||
GEN_REG_READ(e2k_gen_xreg_read_i64, TCGv_i64, gen_xreg_ptr, tcg_gen_ld_i64)
|
||||
GEN_REG_READ(e2k_gen_xreg_read_i32, TCGv_i32, gen_xreg_ptr, tcg_gen_ld_i32)
|
||||
GEN_REG_READ(e2k_gen_xreg_read16u_i32, TCGv_i32, gen_xreg_ptr, tcg_gen_ld16u_i32)
|
||||
GEN_REG_WRITE(e2k_gen_xreg_write_i64, TCGv_i64, gen_xreg_ptr, tcg_gen_st_i64)
|
||||
GEN_REG_WRITE(e2k_gen_xreg_write_i32, TCGv_i32, gen_xreg_ptr, tcg_gen_st_i32)
|
||||
GEN_REG_WRITE(e2k_gen_xreg_write16u_i32, TCGv_i32, gen_xreg_ptr, tcg_gen_st16_i32)
|
@ -2,6 +2,7 @@ subdir('alpha')
|
||||
subdir('arm')
|
||||
subdir('avr')
|
||||
subdir('cris')
|
||||
subdir('e2k')
|
||||
subdir('hppa')
|
||||
subdir('i386')
|
||||
subdir('lm32')
|
||||
|
@ -1957,7 +1957,12 @@ static int32_t x86_guest_base_offset;
|
||||
# if defined(__x86_64__) && defined(__linux__)
|
||||
# include <asm/prctl.h>
|
||||
# include <sys/prctl.h>
|
||||
int arch_prctl(int code, unsigned long addr);
|
||||
# include <linux/unistd.h>
|
||||
static int arch_prctl(int code, unsigned long addr)
|
||||
{
|
||||
return syscall(__NR_arch_prctl, code, addr);
|
||||
}
|
||||
|
||||
static inline int setup_guest_base_seg(void)
|
||||
{
|
||||
if (arch_prctl(ARCH_SET_GS, guest_base) == 0) {
|
||||
|
@ -4628,7 +4628,8 @@ static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
|
||||
/* Enable this block to be able to debug the ELF image file creation.
|
||||
One can use readelf, objdump, or other inspection utilities. */
|
||||
{
|
||||
FILE *f = fopen("/tmp/qemu.jit", "w+b");
|
||||
FILE *f = fopen("@TERMUX_PREFIX@/tmp/qemu.jit", "w+b");
|
||||
|
||||
if (f) {
|
||||
if (fwrite(img, img_size, 1, f) != img_size) {
|
||||
/* Avoid stupid unused return value warning for fwrite. */
|
||||
|
@ -285,5 +285,4 @@ if not get_option('tcg').disabled()
|
||||
endif
|
||||
|
||||
subdir('qapi-schema')
|
||||
subdir('qtest')
|
||||
subdir('migration')
|
||||
|
@ -69,6 +69,7 @@ fi
|
||||
: ${cross_cc_cflags_sparc64="-m64 -mcpu=ultrasparc"}
|
||||
: ${cross_cc_x86_64="x86_64-pc-linux-gnu-gcc"}
|
||||
: ${cross_cc_cflags_x86_64="-m64"}
|
||||
: ${cross_cc_e2k="e2k-linux-cc"}
|
||||
|
||||
for target in $target_list; do
|
||||
arch=${target%%-*}
|
||||
@ -94,7 +95,7 @@ for target in $target_list; do
|
||||
xtensa|xtensaeb)
|
||||
arches=xtensa
|
||||
;;
|
||||
alpha|cris|hppa|i386|lm32|microblaze|microblazeel|m68k|openrisc|riscv64|s390x|sh4|sparc64)
|
||||
alpha|cris|hppa|i386|lm32|microblaze|microblazeel|m68k|openrisc|riscv64|s390x|sh4|sparc64|e2k)
|
||||
arches=$target
|
||||
;;
|
||||
*)
|
||||
|
15
tests/tcg/e2k/Makefile.target
Normal file
15
tests/tcg/e2k/Makefile.target
Normal file
@ -0,0 +1,15 @@
|
||||
# -*- Mode: makefile -*-
|
||||
#
|
||||
# Elbrus 2000 tests
|
||||
|
||||
E2K_SRC=$(SRC_PATH)/tests/tcg/e2k
|
||||
VPATH+=$(E2K_SRC)
|
||||
|
||||
E2K_TESTS=hello-e2k
|
||||
TESTS+=$(E2K_TESTS)
|
||||
|
||||
#
|
||||
# hello-e2k is a barebones app
|
||||
#
|
||||
hello-e2k: CFLAGS+=-ffreestanding
|
||||
hello-e2k: LDFLAGS+=-nostdlib
|
9
tests/tcg/e2k/hello-e2k.c
Normal file
9
tests/tcg/e2k/hello-e2k.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include <asm/e2k_api.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#define MSG "Hello, world!\n"
|
||||
|
||||
void _start(void) {
|
||||
__E2K_SYSCALL_3(LINUX_SYSCALL64_TRAPNUM, __NR_write, 1, MSG, sizeof(MSG));
|
||||
__E2K_SYSCALL_1(LINUX_SYSCALL64_TRAPNUM, __NR_exit, 0);
|
||||
}
|
@ -29,6 +29,8 @@
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <linux/mman.h>
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/atomic.h"
|
||||
#include "qemu/ctype.h"
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/drm.h"
|
||||
|
||||
#include <glob.h>
|
||||
#include <dirent.h>
|
||||
|
||||
int qemu_drm_rendernode_open(const char *rendernode)
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "qemu/host-utils.h"
|
||||
|
||||
#if defined CONFIG_LINUX && !defined CONFIG_MEMFD
|
||||
#include <linux/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
#ifdef __linux__
|
||||
#include <linux/mman.h>
|
||||
#else /* !CONFIG_LINUX */
|
||||
#define MAP_SYNC 0x0
|
||||
|
@ -246,7 +246,7 @@ bool module_load_one(const char *prefix, const char *lib_name, bool mayfail)
|
||||
version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION),
|
||||
G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~",
|
||||
'_');
|
||||
dirs[n_dirs++] = g_strdup_printf("/var/run/qemu/%s", version_dir);
|
||||
dirs[n_dirs++] = g_strdup_printf("@TERMUX_PREFIX@/var/run/qemu/%s", version_dir);
|
||||
#endif
|
||||
|
||||
assert(n_dirs <= ARRAY_SIZE(dirs));
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
#include <linux/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
|
@ -900,7 +900,7 @@ static int unix_listen_saddr(UnixSocketAddress *saddr,
|
||||
path = saddr->path;
|
||||
} else {
|
||||
const char *tmpdir = getenv("TMPDIR");
|
||||
tmpdir = tmpdir ? tmpdir : "/tmp";
|
||||
tmpdir = tmpdir ? tmpdir : "@TERMUX_PREFIX@/tmp";
|
||||
path = pathbuf = g_strdup_printf("%s/qemu-socket-XXXXXX", tmpdir);
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/vfio.h>
|
||||
#include <linux/mman.h>
|
||||
#include "qapi/error.h"
|
||||
#include "exec/ramlist.h"
|
||||
#include "exec/cpu-common.h"
|
||||
|
Loading…
Reference in New Issue
Block a user