Compare commits

...

384 Commits

Author SHA1 Message Date
Alibek Omarov e3304f7219 e2k: working (???) console 2021-08-26 00:42:08 +03:00
Alibek Omarov 030c8c979d e2k: restore irq setting, add custom pci bridge 2021-08-24 16:57:02 +03:00
Alibek Omarov 641c6f7e4c escc: better split escc-pci into a separate file later, for now workaround macro poisoning 2021-08-24 16:56:09 +03:00
Alibek Omarov b588f7d269 e2k: fix lmscon, add pci2pci bridge, hack pci into escc, fix compiling without werror 2021-08-23 02:37:53 +03:00
Alibek Omarov db1f69d6b3 e2k: rewrite iohub host bridge 2021-08-20 20:37:13 +03:00
Alibek Omarov 50a08921e6 e2k: exclude non existing files from meson 2021-08-20 17:23:06 +03:00
Alibek Omarov 1169f1a46a lmscon: fix __FUNCTION__ to __func__ 2021-08-20 17:22:41 +03:00
Alibek Omarov 818f96d7a5 e2k: add bootblock generation, not used anywhere yet 2021-08-20 17:22:21 +03:00
Alibek Omarov e57e16c31d e2k: fix bootblock header 2021-08-20 17:21:54 +03:00
Alibek Omarov 0fbc234be3 e2k: fix building CPU code 2021-08-20 17:21:24 +03:00
Alibek Omarov 0d8530775e e2k: sic refactoring 2021-08-20 15:16:07 +03:00
Alibek Omarov a36b8306ec e2k: delete iohub 2021-08-20 15:15:54 +03:00
Alibek Omarov b0a8c3c70a e2k: add tracing for MAS_IOADDR accesses, fix invalid pointer cast 2021-07-31 03:15:19 +03:00
Alibek Omarov 3614e16f5c e2k: implement simple bootblock generator, when we don't load firmware. TODO: find out how to load it into memory 2021-07-31 03:15:19 +03:00
Alibek Omarov 4d79fff5e6 e2k: import bootinfo.h from linux kernel source 2021-07-31 03:15:19 +03:00
Alibek Omarov 5c06474a86 e2k: stub MMU regs load/store support, add tracing functionality for CPU emu, remove unused code 2021-07-31 03:15:19 +03:00
Alibek Omarov d1adffa508 e2k: add MMU registers load/store support, WIP 2021-07-31 03:15:19 +03:00
Alibek Omarov 4b81eaa930 e2k: initialize ioapic_as 2021-07-31 03:15:19 +03:00
Alibek Omarov 2b9db04643 e2k: make load/store functions accept struct with parameters, rather than endlessly increasing argument list 2021-07-31 03:15:19 +03:00
Alibek Omarov 291dc245dc e2k: implement writing to crs registers 2021-07-31 03:15:19 +03:00
Alibek Omarov 0db316ed3c e2k: port ioapic emulation to e2k 2021-07-31 03:15:19 +03:00
Alibek Omarov dbc7cacc8d e2k: very basic SIC emulation 2021-07-31 03:15:19 +03:00
Alibek Omarov 8de04976c0 e2k: hardcode initial USD parameters 2021-07-31 03:15:19 +03:00
Alibek Omarov d2a1753138 e2k: list every SIC NBSR register used for Linux kernel early boot
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 03:15:19 +03:00
Alibek Omarov e10bb15d7a e2k: remove unnecessary logging
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 03:15:19 +03:00
Alibek Omarov 9332082768 e2k: initialize lmscon console
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 03:15:19 +03:00
Alibek Omarov f7c2c20661 e2k: move SIC NBSR to separate file
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 03:15:19 +03:00
Alibek Omarov 1dde9d43a4 char: lmscon: add primitive Elbrus Simulator console
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 03:15:19 +03:00
Alibek Omarov bd4ec67ed2 e2k: remove FIRMWARE_LOAD_ADDR
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 03:15:19 +03:00
Alibek Omarov c110f65d09 e2k: take LOAD_ADDR from firmware or kernel loading functions
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 03:15:19 +03:00
Alibek Omarov 10d1009d8a e2k: WIP work on IOHub
Compiles but does nothing yet.

Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 03:15:19 +03:00
Alibek Omarov 56ed496823 e2k: Loosely implement MAS_IOADDR.
It seems it actually does access physical memory but used for devices

Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 03:15:19 +03:00
Alibek Omarov 85fa254b25 e2k: use E2K machine type
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 03:15:19 +03:00
Alibek Omarov 30e57bf532 e2k: Kernel boot test
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 03:15:19 +03:00
Denis Drakhnia 6d1841f2b4 e2k: Boot test.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 03:15:19 +03:00
Alibek Omarov b960480b6d linux-user/e2k: place generic errno definitions, arch doesn't override them 2021-07-31 03:14:34 +03:00
Alibek Omarov 1b3e36f3e0 e2k: remove breakpoint_check, according to b5cf7428 2021-07-31 03:13:47 +03:00
Alibek Omarov a1af460416 e2k: add Kconfig 2021-07-31 03:09:01 +03:00
Alibek Omarov 4670be0fd6 tests/tcg/e2k: remove C tests, add simple assembler add test 2021-07-31 02:33:36 +03:00
Alibek Omarov 983e500241 tests/tcg: don't run multiarch tests for assembler-only targets
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 02:33:36 +03:00
Alibek Omarov 6cc82042c5 tests/tcg: allow running tests for targets that don't have C compiler
Obviously there is better way to do this.

Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 02:33:36 +03:00
Denis Drakhnia 1c19a5e42d e2k: Fix bugs after rebase.
Update pc_next for fake kernel entries.
Use enums for floatx80 rounding precision.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:36 +03:00
Alibek Omarov a2e8e1f726 e2k: pass env to do_sigaltstack
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 02:33:36 +03:00
Alibek Omarov 332652a264 gdbstub: fix e2k tag handler declaration
Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 02:33:36 +03:00
Denis Drakhnia 4b74969b55 e2k: Fix compile error.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:36 +03:00
Denis Drakhnia 3c683e8842 e2k: Increase the number of NR to 224.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:36 +03:00
Denis Drakhnia fd6b300945 e2k: Gen illopc for mirrored ld+st.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:36 +03:00
Denis Drakhnia c85a9d9088 e2k: Reorg cpu dump.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:36 +03:00
Denis Drakhnia b05aefc074 e2k: Update get/set state regs.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:36 +03:00
Denis Drakhnia aac549c645 e2k: Remove syscall helper.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:36 +03:00
Denis Drakhnia 452fc964b0 e2k: Add tags and force_save_alc_dst properties.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:36 +03:00
Denis Drakhnia 7fb91d883b e2k: Restore basic tags support.
Disabled at compile time.
2021-07-31 02:33:36 +03:00
Denis Drakhnia 652acd6dd9 e2k: Do not generate loop_end for stores outside of loops.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia 6352dbc284 e2k: Fix segfault.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia 7dcb5fa4c7 e2k: Reorg usage of registers.
Till then we had separate stage to write results of
an operations to registers. Now operations will write
result immediately to a destination register. Registers
will be saved to a temporary location if following
operations in a bundle must read them.

The change elliminates additional branches for
conditional operations in the write stage and reduces
data movements.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia 4277c82910 e2k: signals: Save and restore more state.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia 801e422045 e2k: Bug fixes.
Fix time fields in stat64.

Restore and save a breakpoint frame in a signal
handler. This will fix a segfault if a signal will
be raised while a cpu is in a breakpoint.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia 6f273d2ea4 e2k: Port f{min,max} and float2int from x86.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia 9ca3581380 e2k: Fix performance regression.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia 5647e20f76 e2k: Fix read and write probe access.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia 8d7df93656 e2k: Implement basic v6 support.
Not tested on a real hardware.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia a78054bbca e2k: Fix C++ exceptions for v5+.
v5+ has different procedure stack layout. Reading
the stack through the acees_hw_stacks syscall
requires to shuffle registers for a backward
compatibility with previous versions.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia 3a30c5edfd e2k: Implement basic v5 support.
Add gdb xml files for e2k.
Tags are partially disabled for better performance.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia afc36915fa e2k: Move TCG translation parts into single file.
The TCG translation was splitted into multiple files and
it was painful because it has a lot of cross references.

Reorg FX helpers.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia 4a4fe9fd52 e2k: Use one large array for registers.
Previously was used two separate arrays for low and
high halves of a register. Now we can pass direct
pointer to a register into helpers instead of copying
the halves into a temporary buffer and pass pointer to
that buffer.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia 5ac71836f8 e2k: Use %pfpfr for f32 and f64 operations.
%fpcr and %fpsr have been used for the operations but
%pfpfr must be used instead.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia 91b18183de e2k: Fix fxcmp{s,d}b tcg fatal errors.
Was used destroyed value of converted src2 after a branch.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia b59c0ec31e e2k: Update qemu-binfmt-conf.sh script.
Add e2k_old, e2k32 and e2k32_old user targets.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia d89de72255 e2k: Add a fake atomic execution.
QEMU has cpu_exec_step_atomic function to run
one instruction in an exclusive mode but we need
to execute multiple instructions in that mode.
I don't want to modify the function.

The solution provides a correct execution of
atomic operations like on real CPU but needs
more testing to prove that it works correctly
in all cases.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:35 +03:00
Denis Drakhnia e1796eab81 e2k: Fix signed integer division.
Do not raise an x86 exception when the minimum signed
integer is divisible by minus one.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:34 +03:00
Denis Drakhnia f7e0eecb9c e2k: Add access_hw_stacks and backtrace syscalls.
Special system calls for managing hardware stacks.
Required for C++ exceptions.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:34 +03:00
Denis Drakhnia 5693b6b04f e2k: Fix incorrect initialization of mlock.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:34 +03:00
Alibek Omarov aa67acded6 e2k: remove unnecessary e2k32 directory
It can be avoided with TARGET_ABI_DIR=e2k in e2k32-linux-user.mak

Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 02:33:34 +03:00
Denis Drakhnia 1ba1a731e8 e2k: Add e2k32 linux user files.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:32 +03:00
Denis Drakhnia 27450f6d57 e2k: Basic impl of e2k32-linux-user.
Fix target_stat64 field types in 32-bit mode.
Basic impl of getpl.
Basic impl of ldgd{b,h,w,d}.
Basic impl of stgd{b,h,w,d}.
Add e2k exceptions.
Add Dynamic hw stacks expansion.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:19 +03:00
Denis Drakhnia a3bd286307 e2k: Always SPILL/FILL in FX window mode.
It will fix 'finish' command in gdb.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:18 +03:00
Denis Drakhnia d0933819e3 e2k: Panic if it was not possible to copy CR to a new thread.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:18 +03:00
Denis Drakhnia 49c1ea254d e2k: Skip breakpoints into fake kernel address space.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:18 +03:00
Denis Drakhnia 6f5ad5ee34 e2k: Add reading of %lsr in rr{s,d}.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:18 +03:00
Denis Drakhnia 6ced6a02ea e2k: Fix args sizes for some int vec ops.
objdump prints incorrect argument sizes of some
integer vector operations from the first version
of ISA.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:18 +03:00
Denis Drakhnia f5664db54c e2k: Delete redundant unimplemented messages.
From e2k_cpu_set_pc and e2k_cpu_synchronize_from_tb.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:18 +03:00
Denis Drakhnia 7b12a1a0e4 e2k: Increase PCS and PS sizes.
Dynamically expanding the stack has not yet been
implemented, but sometimes applications require
larger stacks.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:18 +03:00
Denis Drakhnia 9f48ac64d4 e2k: Fix build of other linux-user-targets.
Forgot to wrap constants in if block.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:18 +03:00
Denis Drakhnia 9dd2d3dbf6 e2k: Add systrace print for access_hw_stacks.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:18 +03:00
Denis Drakhnia d8c92845a7 e2k: Fix vector ops with saturation.
An incorrect cast to an unsigned integer was used
instead of a signed integer.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:18 +03:00
Denis Drakhnia d7da680a99 e2k: Delete redundant unimplemented messages.
DAM has not been yet implemented. We always generate
a jump to a fixing code. All these messages are redundant.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:18 +03:00
Denis Drakhnia 4ca7a8e3fe e2k: Fix syscall restart.
We cannot just change the IP address in E2K to restart
the instruction because the same register can be read
and written in the same instruction (and many more
situations), but we can create a fake syscall instruction
and restart it.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:18 +03:00
Denis Drakhnia 19e386d72a e2k: Delete top CRs from cpu state.
Signed-off-by: Denis Drakhnya <numas13@gmail.com>
2021-07-31 02:33:18 +03:00
Alibek Omarov 4c8bbd60b5 e2k: upstream rebase fixes
This commit fixes changes our code after following upstream changes:
* cpu: Introduce TCGCpuOperations struct
* tcg: Make tb arg to synchronize_from_tb const

Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2021-07-31 02:33:18 +03:00
Denis Drakhnia b368b67760 e2k: Fix compiler warnings.
Remove unused static functions.
Replace a misused not operator by bitwise not.
2021-07-31 02:33:18 +03:00
Denis Drakhnia c7cda1f65e e2k: Set correct NR macro for pread/pwrite. 2021-07-31 02:33:17 +03:00
Denis Drakhnia 2c467eee32 e2k: Impl basic unix signals support. 2021-07-31 02:33:17 +03:00
Denis Drakhnia a717098e5f e2k: Fix getf{s,d} ops. 2021-07-31 02:33:17 +03:00
Denis Drakhnia d9a98c1a39 e2k: Add stub for pref op. 2021-07-31 02:33:17 +03:00
Denis Drakhnia aa0d172f6e e2k: Add packed float simple and combined ops. 2021-07-31 02:33:17 +03:00
Denis Drakhnia fe7ed6b222 e2k: Fix fcomb_check. 2021-07-31 02:33:17 +03:00
Denis Drakhnia ee81d8da59 e2k: Probe AAU read access once per page. 2021-07-31 02:33:17 +03:00
Denis Drakhnia 4227ac3dca e2k: Always ignore lock load. 2021-07-31 02:33:17 +03:00
Denis Drakhnia 63011818cd e2k: Fix decoding fcomb and pshufb. 2021-07-31 02:33:17 +03:00
Denis Drakhnia 687395c535 e2k: Split ALC decode/generate stages. 2021-07-31 02:33:17 +03:00
Denis Drakhnia d37d06e24d e2k: Fix movxc. 2021-07-31 02:33:17 +03:00
Denis Drakhnia 74881f8ea7 e2k: Reorg fcomb ops. 2021-07-31 02:33:17 +03:00
Denis Drakhnia ee52b186a9 e2k: Reorg icomb ops. 2021-07-31 02:33:17 +03:00
Alibek Omarov 4092f92f11 e2k: %pfpfr write stubs 2021-07-31 02:33:17 +03:00
Alibek Omarov 951b3b142b e2k: implement fsqrttd/fxsqrttxx through ignoring what fsqrtid/fxsqrt{i,u}xx does 2021-07-31 02:33:17 +03:00
Denis Drakhnia b71b381ad9 e2k: Check address before MOVA memory read. 2021-07-31 02:33:17 +03:00
Denis Drakhnia 954f026069 e2k: Do not align mova addr. 2021-07-31 02:33:17 +03:00
Denis Drakhnia 4a9acdbc7a e2k: Fix fcomb operand ordering. 2021-07-31 02:33:17 +03:00
Denis Drakhnia 26e5446eaa e2k: Impl neg src2 in fscale{s,d} and fxscalesx. 2021-07-31 02:33:16 +03:00
Denis Drakhnia 11b07b2033 e2k: Allow to execute frcps, fsqrts, frsqrts. 2021-07-31 02:33:16 +03:00
Denis Drakhnia 3bc6ba66cb e2k: Init CRs, make gcc happy. 2021-07-31 02:33:16 +03:00
Denis Drakhnia 41b1894970 e2k: Add movt{,c}{s,d,q} ops. 2021-07-31 02:33:16 +03:00
Denis Drakhnia 0cac5fc316 e2k: Add fscale{s,d} and fxscalesx ops. 2021-07-31 02:33:16 +03:00
Denis Drakhnia ca2a301752 e2k: Impl basic init thread support. 2021-07-31 02:33:16 +03:00
Alibek Omarov ac6a4f007e e2k: add fxtoi{s,d}{,tr} and i{s,d}tofx instructions 2021-07-31 02:33:16 +03:00
Alibek Omarov 62f54e580a e2k: add stringified opcodes 2021-07-31 02:33:16 +03:00
Denis Drakhnia dc3896a3bb e2k: Fix mova{b,h,w} reg tag write. 2021-07-31 02:33:16 +03:00
Denis Drakhnia e4ce9097da e2k: Fix insfd. 2021-07-31 02:33:16 +03:00
Denis Drakhnia 2a783a4c41 e2k: Fix getf{s,d}. 2021-07-31 02:33:16 +03:00
Denis Drakhnia 71fa769902 e2k: ecnt must not decrement if vlc is not set. 2021-07-31 02:33:16 +03:00
Denis Drakhnia c2d5fd78c2 e2k: Fix incorrect epilogue counter decrement. 2021-07-31 02:33:16 +03:00
Denis Drakhnia 3f4ee65a6a e2k: Add delayed window bounds static/dynamic checks. 2021-07-31 02:33:16 +03:00
Alibek Omarov 3a3878c337 e2k: implement detecting ISA version by ELF flags, throw an error for protected mode and x86 recompiled binaries for now 2021-07-31 02:33:16 +03:00
Denis Drakhnia 8c3fd2ef2d e2k: Remove control.c 2021-07-31 02:33:16 +03:00
Denis Drakhnia 382c861258 e2k: Remove pshtp and window base. 2021-07-31 02:33:16 +03:00
Denis Drakhnia 9b5889f2a3 e2k: Fix incorrect restore from a breakpoint. 2021-07-31 02:33:15 +03:00
Alibek Omarov 07c5bf6dd6 e2k: implement plog_* instructions 2021-07-31 02:33:15 +03:00
Alibek Omarov 2c6e75164d e2k: add pf{mul,add,sub,div,min,max}d instructions 2021-07-31 02:33:15 +03:00
Denis Drakhnia ebf29d0a87 e2k: Disable debug restore checks if not needed.
Do not check illtag if not needed.
2021-07-31 02:33:15 +03:00
Denis Drakhnia 2fc5c4f8e3 e2k: Remove {GET,SET}_FIELD macros. 2021-07-31 02:33:15 +03:00
Denis Drakhnia 535b0a0616 e2k: Small performance improvements.
Do not initialize alops_map for every tb.
Reduced alops size.
Delayed window bounds checks.
2021-07-31 02:33:15 +03:00
Denis Drakhnia 842c990c4c e2k: Fix decoding of ALES2/5. 2021-07-31 02:33:15 +03:00
Denis Drakhnia fd435db566 e2k: Aaincr must be executed outside of the staa pred cond. 2021-07-31 02:33:15 +03:00
Denis Drakhnia 62a6bc54d8 e2k: Restore usage of env CRs.
Fixes syscall e2k_longjmp2.
2021-07-31 02:33:15 +03:00
Denis Drakhnia fbeee5f77a e2k: Add movx{,a,c} instr. 2021-07-31 02:33:15 +03:00
Denis Drakhnia 034f16d03c e2k: Add {u,s}{div,mod}x instrs. 2021-07-31 02:33:15 +03:00
Denis Drakhnia 68c2d77603 e2k: Add mpsadbh instr. 2021-07-31 02:33:15 +03:00
Denis Drakhnia 10f5831153 e2k: Add phminposuh instr. 2021-07-31 02:33:15 +03:00
Denis Drakhnia 2fa96b18f3 e2k: Add pmulhrsh instr. 2021-07-31 02:33:15 +03:00
Denis Drakhnia c0cc80ffba e2k: Add psign{b,h,w} instrs. 2021-07-31 02:33:15 +03:00
Denis Drakhnia 135d0824fc e2k: Add phadd{,s}{h,w} and phsub{,s}{h,w} instrs. 2021-07-31 02:33:15 +03:00
Denis Drakhnia 5846530746 e2k: Add packuswh instr. 2021-07-31 02:33:14 +03:00
Denis Drakhnia 3dad8d3fa1 e2k: Add pmulubhh instr. 2021-07-31 02:33:14 +03:00
Denis Drakhnia 2c3600b282 e2k: Add pshufh instr. 2021-07-31 02:33:14 +03:00
Denis Drakhnia 333f94693e e2k: Add punpck{l,h}{bh,hw,wd} instrs. 2021-07-31 02:33:14 +03:00
Denis Drakhnia ed3ba3fdf9 e2k: Add pshufw instr. 2021-07-31 02:33:14 +03:00
Denis Drakhnia 2051e90a5c e2k: Add packsshb, packushb and packsswh instrs. 2021-07-31 02:33:14 +03:00
Denis Drakhnia 2a54fa6008 e2k: Add pmovmskps and pmovmskpd instrs. 2021-07-31 02:33:14 +03:00
Denis Drakhnia d8a54d6189 e2k: Add pextrh instr. 2021-07-31 02:33:14 +03:00
Denis Drakhnia bebca526fb e2k: Add pinsh instr. 2021-07-31 02:33:14 +03:00
Denis Drakhnia 39c8f3337c e2k: Add pmulhh, pmulhuh and pmullh instrs. 2021-07-31 02:33:14 +03:00
Denis Drakhnia 012aa4cd9d e2k: Add pavgus{b,h} instrs. 2021-07-31 02:33:14 +03:00
Denis Drakhnia 2443e57916 e2k: Add pandd, pandnd, pord and pxord instrs. 2021-07-31 02:33:14 +03:00
Denis Drakhnia 6e2130961c e2k: Add psadbw instr. 2021-07-31 02:33:14 +03:00
Denis Drakhnia 8d0a6de012 e2k: Add pmadd{h,ubsh} instrs. 2021-07-31 02:33:14 +03:00
Denis Drakhnia 6d16038d5f e2k: Add psra{h,w} instrs. 2021-07-31 02:33:14 +03:00
Denis Drakhnia e6329a2907 e2k: Add quad shifts instrs with 8-bit immediate. 2021-07-31 02:33:14 +03:00
Denis Drakhnia d39cdc07a1 e2k: Add packed shift inters. 2021-07-31 02:33:14 +03:00
Denis Drakhnia 219429efcf e2k: Add packed add and sub using saturation. 2021-07-31 02:33:13 +03:00
Denis Drakhnia 593b6ecc6d e2k: Add padd{b,h,w} and psub{b,h,w} instrs. 2021-07-31 02:33:13 +03:00
Denis Drakhnia c2afb3a4bf e2k: Add pcmp{eq,gt}{b,h,w,d} instrs. 2021-07-31 02:33:13 +03:00
Denis Drakhnia e6545e53c0 e2k: Prepare to remove CRs from env. 2021-07-31 02:33:13 +03:00
Denis Drakhnia b7a76b3b03 e2k: Impl e2k_longjmp2 syscall. 2021-07-31 02:33:13 +03:00
Alibek Omarov 62d0ba0ce8 e2k: fix dumb mistake in fcomb 64 instructions 2021-07-31 02:33:13 +03:00
Alibek Omarov e3cf268a2c e2k: add fstoifs and fdtoifd instrs 2021-07-31 02:33:13 +03:00
Alibek Omarov a727a050b0 e2k: add whole class of packed min & max 2021-07-31 02:33:13 +03:00
Alibek Omarov 9d47f0296e e2k: partially refactor helper header 2021-07-31 02:33:13 +03:00
Denis Drakhnia 5c1bfb085e e2k: Reorg alc. 2021-07-31 02:33:13 +03:00
Alibek Omarov 15a41a9d2b e2k: implement f{,x}cmp{op}{s,d,x}f instructions 2021-07-31 02:33:13 +03:00
Alibek Omarov 0b2c48563a e2k: elbrus by default have extended precision, set it 2021-07-31 02:33:13 +03:00
Denis Drakhnia 490916800d e2k: Decode/execute ct cond after alc execution. 2021-07-31 02:33:13 +03:00
Denis Drakhnia f642e9f4cc e2k: Fix address generation in mova instrs. 2021-07-31 02:33:13 +03:00
Alibek Omarov 140ff5b26d linux-user: e2k: add forgotten e2k-specific mmap flags, fix some definitions 2021-07-31 02:33:13 +03:00
Denis Drakhnia 1fa12cd1f8 e2k: Fix fcmp{op}{s,d}b instructions. 2021-07-31 02:33:13 +03:00
Denis Drakhnia 5d7892afaf e2k: Change pred type to TCGv_i32 in e2k_gen_store_preg. 2021-07-31 02:33:12 +03:00
Denis Drakhnia 8a9a5186ef e2k: Invalidate mlock after each instruction. 2021-07-31 02:33:12 +03:00
Denis Drakhnia 9ae33eb4ea e2k: Update target_stat and target_statfs structs. 2021-07-31 02:33:12 +03:00
Denis Drakhnia 6237724203 e2k: Fix operands order in icomb. 2021-07-31 02:33:12 +03:00
Denis Drakhnia fa11da01cb target: e2k: Add short, ext, ext1, ext2 alops table. 2021-07-31 02:33:12 +03:00
Alibek Omarov 4f8db27900 e2k: add fcmp{op} instructions that write into normal register 2021-07-31 02:33:12 +03:00
Denis Drakhnia ed526a6cff target: e2k: Correctly save/restore wdbl. 2021-07-31 02:33:12 +03:00
Denis Drakhnia d5cb0fb7fc target: e2k: Execute load on flush cache MAS. 2021-07-31 02:33:12 +03:00
Alibek Omarov 82bc772855 e2k: fpu: implement float combined instrs 2021-07-31 02:33:12 +03:00
Alibek Omarov 2d776db5d4 e2k: helper_fpu: fix various compiler warnings 2021-07-31 02:33:12 +03:00
Alibek Omarov 4ae0b676c5 e2k: add fxcmp{op}{type}b instructions 2021-07-31 02:33:12 +03:00
Alibek Omarov ae835d1ec9 qemu-binfmt-conf: add e2k elf header, 64-bit only as we only support it at this time 2021-07-31 02:33:12 +03:00
Denis Drakhnia a4b327f103 target: e2k: Rename alc execute fns. 2021-07-31 02:33:12 +03:00
Denis Drakhnia f132f3cace target: e2k: HACK: Unlock mem addr forces %MLOCK condition. 2021-07-31 02:33:12 +03:00
Denis Drakhnia ca375bc450 target: e2k: Add basic FX instrs. 2021-07-31 02:33:12 +03:00
Denis Drakhnia 0ebf9ead7c target: e2k: Add movfi/movif instrs. 2021-07-31 02:33:11 +03:00
Denis Drakhnia 57d2c973ca target: e2k: Move fpcr/fpsr to state reg helpers. 2021-07-31 02:33:11 +03:00
Denis Drakhnia 8be1d4a4ff target: e2k: Add get_src{1,2}_i80 funcs. 2021-07-31 02:33:11 +03:00
Denis Drakhnia e614ff56d4 target: e2k: Add xreg read/write functions. 2021-07-31 02:33:11 +03:00
Denis Drakhnia e0c19f7657 target: e2k: Add temps for FX/SIMD ops. 2021-07-31 02:33:11 +03:00
Denis Drakhnia d4c49d9093 target: e2k: Remove rptr and tptr from state. 2021-07-31 02:33:11 +03:00
Alibek Omarov 9e51b8b90b target: e2k: set disas isa version 2021-07-31 02:33:11 +03:00
Alibek Omarov 531275d0b8 target: e2k: fdiv has opc2 == 1, as well as additional fadd, fsub, fmul on e2k-v4. Fix SIGILL not generated when opce2 unrecognized for float conversion instructions 2021-07-31 02:33:11 +03:00
Alibek Omarov fbadcc486a target: e2k: add conversion instructions, handle float comparison with predicate result instrs 2021-07-31 02:33:11 +03:00
Alibek Omarov eadbb653fe target: e2k: add basic fpu instructions 2021-07-31 02:33:11 +03:00
Alibek Omarov 66711e6474 fpu: assuming e2k fp behave like x86 2021-07-31 02:33:11 +03:00
Denis Drakhnia 0a9141271a target: e2k: Delete hack for saving USD registers on proc call/ret. 2021-07-31 02:33:11 +03:00
Denis Drakhnia 8a29c4873a target: e2k: Add psubd instr. 2021-07-31 02:33:11 +03:00
Denis Drakhnia 28fb8b3363 target: e2k: Fix address generation in staa. 2021-07-31 02:33:11 +03:00
Denis Drakhnia eb74ae2832 target: e2k: Fix udivs exception hack. 2021-07-31 02:33:11 +03:00
Denis Drakhnia 4c74efa336 target: e2k: Impl restore_state_to_opc. 2021-07-31 02:33:11 +03:00
Denis Drakhnia d3e9e9e1cf target: e2k: Add e2k_todo{,_illop} macros. 2021-07-31 02:33:11 +03:00
Denis Drakhnia ca9777eb47 target: e2k: Add tlb_fill handler. 2021-07-31 02:33:11 +03:00
Denis Drakhnia d823adeef4 target: e2k: Clear registers in new allocated range of window. 2021-07-31 02:33:10 +03:00
Denis Drakhnia 50620eb6bf target: e2k: Fix incorrect registers view in gdb after exception. 2021-07-31 02:33:10 +03:00
Denis Drakhnia 53eafebe9e target: e2k: Fix gdb run till exit from func. 2021-07-31 02:33:10 +03:00
Denis Drakhnia ad4657fdd5 target: e2k: %cr0 must hold pregs and ip of previous procedure. 2021-07-31 02:33:10 +03:00
Denis Drakhnia 4461945f86 target: e2k: Remove unneeded regs array in TCG state. 2021-07-31 02:33:10 +03:00
Denis Drakhnia 9bed8ca071 target: e2k: HACK: Tag storage for procedure stack. 2021-07-31 02:33:10 +03:00
Denis Drakhnia a6f51c40d1 target: e2k: Save PC before reading it in rr{s,d}. 2021-07-31 02:33:10 +03:00
Denis Drakhnia a0f12e586f target: e2k: Select tag for taken source in merge{s,d}. 2021-07-31 02:33:10 +03:00
Denis Drakhnia 79a04c2476 target: e2k: Add dbl window modifier. 2021-07-31 02:33:10 +03:00
Denis Drakhnia 2573f2f59e target: e2k: mova{b,h,w} must write to reg64. 2021-07-31 02:33:10 +03:00
Denis Drakhnia 28d1af95ce target: e2k: Impl multiple pred for ALC exec. 2021-07-31 02:33:10 +03:00
Denis Drakhnia 601cb5098e target: e2k: Return aligned pointer from getsp. 2021-07-31 02:33:10 +03:00
Denis Drakhnia ef3754013a target: e2k: HACK: Add stack for USD registers.
CPU must restore `USD` after calls but I don't know how it should be implemented.
2021-07-31 02:33:10 +03:00
Denis Drakhnia 435b7b7b53 target: e2k: Add cmp{o,s,p}{s,d} instrs.
Fix cmpandp{s,d}b.
2021-07-31 02:33:10 +03:00
Denis Drakhnia 2c3ccb018a target: e2k: Do not account %predN for ct in loop prologue. 2021-07-31 02:33:10 +03:00
Denis Drakhnia 489074436c target: e2k: Add %pcntN condition. 2021-07-31 02:33:10 +03:00
Denis Drakhnia 1556591a51 target: e2k: Force ps pop in FX mode. 2021-07-31 02:33:10 +03:00
Denis Drakhnia 658ae276ff target: e2k: Ignore unimplemented mas opc in store. 2021-07-31 02:33:10 +03:00
Denis Drakhnia 3b7dc608ad target: e2k: Add pmovmskb instr. 2021-07-31 02:33:09 +03:00
Denis Drakhnia e01c75fcee target: e2k: Add p{min,max}{ub,sh} instrs. 2021-07-31 02:33:09 +03:00
Denis Drakhnia 1fe993ba45 target: e2k: Add staaq instr. 2021-07-31 02:33:09 +03:00
Denis Drakhnia 51828b93a0 target: e2k: Execute ALES2/5 together with others channels. 2021-07-31 02:33:09 +03:00
Denis Drakhnia fbe580d688 target: e2k: Add xregs. 2021-07-31 02:33:09 +03:00
Denis Drakhnia dba6891e25 target: e2k: Log msg if wd.fx is setted. 2021-07-31 02:33:09 +03:00
Denis Drakhnia 80fb7750f9 target: e2k: Do not save IP on every instruction. 2021-07-31 02:33:09 +03:00
Denis Drakhnia b05954919c target: e2k: Reading %ilcr for gdb. 2021-07-31 02:33:09 +03:00
Denis Drakhnia 50ea7ffe16 target: e2k: Fix setting ctpr.ipd for *disp instr. 2021-07-31 02:33:09 +03:00
Denis Drakhnia b1e6863dea target: e2k: Dec store rem in loop mode. 2021-07-31 02:33:09 +03:00
Denis Drakhnia 59bbf4cc32 target: e2k: Restricted loop_mode implementation. 2021-07-31 02:33:09 +03:00
Denis Drakhnia 4c367bc7fd target: e2k: Fix reading aadN from gdb. 2021-07-31 02:33:09 +03:00
Denis Drakhnia 4efbb14769 target: e2k: Add basic mova{b,h,w,d} impl. 2021-07-31 02:33:09 +03:00
Denis Drakhnia 09c11cc025 target: e2k: Fix ctpr size. 2021-07-31 02:33:09 +03:00
Denis Drakhnia efe2096d99 target: e2k: Remove merge condition from Instr. 2021-07-31 02:33:09 +03:00
Denis Drakhnia 92c450538b target: e2k: Add staa{b,h} instrs. 2021-07-31 02:33:09 +03:00
Alibek Omarov b1e0ff07e6 target: e2k: define CPUs we're testing against, define gdb arch 2021-07-31 02:33:09 +03:00
Denis Drakhnia ae7bdcdaf0 target: e2k: Add clarification to gen_tag funcs. 2021-07-31 02:33:08 +03:00
Alibek Omarov d10c6bb8d3 target: e2k: add umulx/smulx instrs. 2021-07-31 02:33:08 +03:00
Denis Drakhnia c541342e15 target: e2k: Fix sxt/st operand sizes. 2021-07-31 02:33:08 +03:00
Denis Drakhnia 0b95d2ac84 target: e2k: Hack delay %rN index gen for result. 2021-07-31 02:33:08 +03:00
Denis Drakhnia 9764860c49 target: e2k: Fix based preg. 2021-07-31 02:33:08 +03:00
Denis Drakhnia e6417dbafa target: e2k: Log msg if dbl is setted. 2021-07-31 02:33:08 +03:00
Denis Drakhnia f7e8b88b18 target: e2k: Add {u,s}mulhd instrs. 2021-07-31 02:33:08 +03:00
Denis Drakhnia 3d892bd2e1 target: e2k: Add mova stubs. 2021-07-31 02:33:08 +03:00
Denis Drakhnia 5e03f648d8 target: e2k: Fix uninit plu_result.reg bug. 2021-07-31 02:33:08 +03:00
Denis Drakhnia 57d037c35f target: e2k: Add combined int instructions. 2021-07-31 02:33:08 +03:00
Denis Drakhnia 661f961173 target: e2k: Add Instr struct to alc. 2021-07-31 02:33:08 +03:00
Denis Drakhnia 168685155c target: e2k: Reorganize tag usage. 2021-07-31 02:33:08 +03:00
Denis Drakhnia d4fb3ea77d target: e2k: Fix icont bug. 2021-07-31 02:33:08 +03:00
Denis Drakhnia c87d09e5c6 target: e2k: Read %idr in rrd. 2021-07-31 02:33:08 +03:00
Denis Drakhnia e0aa8d2be7 target: e2k: Increase startup window size. 2021-07-31 02:33:08 +03:00
Denis Drakhnia 978c71d6f4 target: e2k: Fix bitrev{s,d} instrs. 2021-07-31 02:33:08 +03:00
Denis Drakhnia 1973bcaf12 target: e2k: Impl reading some regs through rrd.
%wd, %pcsp.lo, %pcsp.hi, %pcshtp, %cr1.hi, %cr1.lo.
2021-07-31 02:33:08 +03:00
Alibek Omarov 264053f440 target: e2k: add reading %ip register through rrd 2021-07-31 02:33:08 +03:00
Denis Drakhnia 9197fb5473 target: e2k: Fix getsp src2 size. 2021-07-31 02:33:08 +03:00
Alibek Omarov 6ef5bd8c89 target: e2k: add lzcnt and popcnt instrs (untested!) 2021-07-31 02:33:07 +03:00
Alibek Omarov d709ccaf02 target: e2k: add bitrev instr 2021-07-31 02:33:07 +03:00
Denis Drakhnia 18c3b8e7bf target: e2k: Impl pcmpeqb. 2021-07-31 02:33:07 +03:00
Denis Drakhnia 44279d5914 target: e2k: Replace some panics with messages. 2021-07-31 02:33:07 +03:00
Denis Drakhnia b06832979a target: e2k: Add %cr1.{lo,hi} to rr{s,d}/rw{s,d}. 2021-07-31 02:33:07 +03:00
Denis Drakhnia 25538ca72b target: e2k: Impl write AL result to ctpr. 2021-07-31 02:33:07 +03:00
Denis Drakhnia 9d82f3ebe9 target: e2k: Partial staa{d,w} implementation. 2021-07-31 02:33:07 +03:00
Denis Drakhnia 86214b6bb8 target: e2k: Increase temp i32 limit. 2021-07-31 02:33:07 +03:00
Denis Drakhnia 623b9cf2d7 target: e2k: Add paddd instr. 2021-07-31 02:33:07 +03:00
Denis Drakhnia 8c6d17d57d target: e2k: Add mul{s,d} instrs. 2021-07-31 02:33:07 +03:00
Denis Drakhnia c8e5c64499 target: e2k: Add pshufb instr. 2021-07-31 02:33:07 +03:00
Denis Drakhnia 6129094288 target: e2k: Add insf{s,d} instrs. 2021-07-31 02:33:07 +03:00
Denis Drakhnia 1b9422f89d target: e2k: Add gettag{s,d} instrs. 2021-07-31 02:33:07 +03:00
Denis Drakhnia 41c16b46a1 target: e2k: Add puttag{s,d} instrs. 2021-07-31 02:33:07 +03:00
Denis Drakhnia f04f7f0106 target: e2k: Impl speculative execution. 2021-07-31 02:33:07 +03:00
Alibek Omarov e5fe02b722 target: e2k: refactor instruction decoding based on active channel 2021-07-31 02:33:07 +03:00
Denis Drakhnia 2fcc3ba89d target: e2k: Remove unneeded ip change in syscall. 2021-07-31 02:33:07 +03:00
Denis Drakhnia 26d0e12e1e target: e2k: Increace i32 temp limit. 2021-07-31 02:33:06 +03:00
Denis Drakhnia 205647fbd9 target: e2k: Reorg reg file. 2021-07-31 02:33:06 +03:00
Denis Drakhnia 284da505ff target: e2k: Add registers tags. 2021-07-31 02:33:06 +03:00
Denis Drakhnia 1768bf4cfd tcg: Increase max temps limit. 2021-07-31 02:33:06 +03:00
Denis Drakhnia c3f105c132 target: e2k: Jump to ctpr_addr if ctpr is return. 2021-07-31 02:33:06 +03:00
Denis Drakhnia 290bff3f3e target: e2k: Fix instr return. 2021-07-31 02:33:06 +03:00
Denis Drakhnia 3d1e558b19 target: e2k: Update TODO messages. 2021-07-31 02:33:06 +03:00
Denis Drakhnia 0153ea9259 target: e2k: Gen rt exception in udivs hack. 2021-07-31 02:33:06 +03:00
Denis Drakhnia db313e9236 target: e2k: Fix gen_goto_tb usage. 2021-07-31 02:33:06 +03:00
Denis Drakhnia 1001e16697 target: e2k: Fix instr start address. 2021-07-31 02:33:06 +03:00
Denis Drakhnia e307182167 target: e2k: Move int helpers to separate file. 2021-07-31 02:33:06 +03:00
Denis Drakhnia abbe9368e5 target: e2k: Make gdb happier. 2021-07-31 02:33:06 +03:00
Denis Drakhnia b3e5cd2011 target: e2k: Ps push/pop with pshtp. 2021-07-31 02:33:06 +03:00
Denis Drakhnia 72f036b1bf target: e2k: Add setwd helper. 2021-07-31 02:33:06 +03:00
Denis Drakhnia 11bd8ae0f3 target: e2k: Reorg cr1. 2021-07-31 02:33:06 +03:00
Denis Drakhnia 23cdc6fc7b target: e2k: Reorg wd. 2021-07-31 02:33:06 +03:00
Denis Drakhnia d27d954c75 target: e2k: Reorg br. 2021-07-31 02:33:06 +03:00
Denis Drakhnia fa779edcfb target: e2k: Restore udivs dump state hack. 2021-07-31 02:33:06 +03:00
Denis Drakhnia 3cae4775ad target: e2k: Reord pcsp. 2021-07-31 02:33:05 +03:00
Denis Drakhnia 0de523f9eb target: e2k: Reorg psp. 2021-07-31 02:33:05 +03:00
Denis Drakhnia 71e419504e target: e2k: Move helper_cur_dec to TCG. 2021-07-31 02:33:05 +03:00
Denis Drakhnia eb5c42659d target: e2k: Add exceptions to wregs access. 2021-07-31 02:33:05 +03:00
Denis Drakhnia e11cfa7b90 gdb: e2k: Fix memory read. 2021-07-31 02:33:05 +03:00
Denis Drakhnia 85bdff00a5 target: e2k: Fix literal loading. 2021-07-31 02:33:05 +03:00
Denis Drakhnia 3e17641dcb target: e2k: Fix control flow condition. 2021-07-31 02:33:05 +03:00
Denis Drakhnia 8da97da7f7 target: e2k: Add {s,u}div{s,d}. 2021-07-31 02:33:05 +03:00
Denis Drakhnia 8e85dc24f6 target: e2k: Fix mas array size. 2021-07-31 02:33:05 +03:00
Denis Drakhnia 1368572342 target: e2k: Remove helper unimpl. 2021-07-31 02:33:05 +03:00
Denis Drakhnia 5a19b4be08 target: e2k: Add basic setmas support. 2021-07-31 02:33:05 +03:00
Denis Drakhnia cb2d728151 target: e2k: Fix extending sign 32-bit literal. 2021-07-31 02:33:05 +03:00
Denis Drakhnia a0e1a77993 gdb: e2k: Add stub for read tags. 2021-07-31 02:33:05 +03:00
Denis Drakhnia 81b6220817 target: e2k: gdb global registers tags ids. 2021-07-31 02:33:05 +03:00
Denis Drakhnia aa3cc78ef1 target: e2k: Add %clkr. 2021-07-31 02:33:05 +03:00
Denis Drakhnia 9ea4b04c38 target: e2k: alc: Conditional execution. 2021-07-31 02:33:05 +03:00
Denis Drakhnia 505a2a1acd target: e2k: Fix extraction of lp index. 2021-07-31 02:33:05 +03:00
Denis Drakhnia f1e58bc551 target: add: Add getfs/getfd instrs. 2021-07-31 02:33:05 +03:00
Denis Drakhnia e7377e2a59 target: e2k: Add %idr. 2021-07-31 02:33:04 +03:00
Denis Drakhnia 078beec8ac target: e2k: Add cmpand{op}{s,d}b instrs. 2021-07-31 02:33:04 +03:00
Denis Drakhnia c547c22405 target: e2k: Add %upsr. 2021-07-31 02:33:04 +03:00
Denis Drakhnia e1e6588335 target: e2k: Use start+len for GET_FIELD. 2021-07-31 02:33:04 +03:00
Denis Drakhnia 3ab77d7c10 target: e2k: Add PLU instructions. 2021-07-31 02:33:04 +03:00
Denis Drakhnia 65d7a8646f target: e2k: Fix load instrs. 2021-07-31 02:33:04 +03:00
Alibek Omarov 28baa0a65d target: e2k: alc: support cmp{op}sb 2021-07-31 02:33:04 +03:00
Alibek Omarov 3708e3489c target: e2k: add %ip for rrd 2021-07-31 02:33:04 +03:00
Denis Drakhnia 212c121127 target: e2k: Fix ct in gdb. 2021-07-31 02:33:04 +03:00
Denis Drakhnia 5b828e999f target: e2k: Read NR in gdb. 2021-07-31 02:33:04 +03:00
Denis Drakhnia 47905d5d35 target: e2k: Fix e2k_cpu_gdb_read_register. 2021-07-31 02:33:04 +03:00
Denis Drakhnia dec82b41b6 target: e2k: Fix call/return. 2021-07-31 02:33:04 +03:00
Denis Drakhnia d9444952d0 target: e2k: Fix ctpr count. 2021-07-31 02:33:04 +03:00
Denis Drakhnia 45d5039496 target: e2k: Mov ct disp from helper to TCG. 2021-07-31 02:33:04 +03:00
Denis Drakhnia d2c747a497 target: e2k: Remove cond from ct helpers. 2021-07-31 02:33:04 +03:00
Denis Drakhnia 7a24df0762 target: e2k: Remove has_cond from DisasContext. 2021-07-31 02:33:04 +03:00
Denis Drakhnia 31af59b8d5 target: e2k: Move ct cond to cpu env. 2021-07-31 02:33:04 +03:00
Denis Drakhnia 17d175a2d8 target: e2k: Reorg + basic gdb debugging. 2021-07-31 02:33:03 +03:00
Denis Drakhnia 8e1c3d2401 target: e2k: gdb register ids. 2021-07-31 02:33:03 +03:00
Alibek Omarov 7db0d690b2 target: e2k: initial gdb support 2021-07-31 02:33:03 +03:00
Denis Drakhnia 6184b65812 disas: e2k: Fix alf print. 2021-07-31 02:33:03 +03:00
Denis Drakhnia a4f18c82f6 target: e2k: gen_goto_tb from SPARC. 2021-07-31 02:33:03 +03:00
Denis Drakhnia aa84842e3a target: e2k: Add exception for abn/abp instr. 2021-07-31 02:33:03 +03:00
Denis Drakhnia e0a0ea5c52 target: e2k: Fix SIGFPE error. 2021-07-31 02:33:03 +03:00
Denis Drakhnia 320e542ece target: e2k: Add procedure stack. 2021-07-31 02:33:03 +03:00
Alibek Omarov a793ec50cb tests: tcg: add basic tests for e2k 2021-07-31 02:33:03 +03:00
Denis Drakhnia a0b43c510a target: e2k: Add basic getsp instr. 2021-07-31 02:33:03 +03:00
Denis Drakhnia 6bcad20ee8 target: e2k: Rotate window registers in syscall. 2021-07-31 02:33:03 +03:00
Denis Drakhnia c88de7df16 target: e2k: Add pcs_{push,pop}. 2021-07-31 02:33:03 +03:00
Denis Drakhnia d74f15d1cf target: e2k: Add basic call (without saving regs). 2021-07-31 02:33:03 +03:00
Denis Drakhnia 17b9bc4519 target: e2k: Add %pcsp_hi and %pcsp_lo registers. 2021-07-31 02:33:03 +03:00
Denis Drakhnia 959606cda2 target: e2k: Move %br to %cr1_hi. 2021-07-31 02:33:03 +03:00
Denis Drakhnia 4b85995458 target: e2k: Reorg lcnt decrement. 2021-07-31 02:33:03 +03:00
Denis Drakhnia 1b382e3498 target: e2k: Move %br parts to %br. 2021-07-31 02:33:03 +03:00
Denis Drakhnia 67fb40bbf1 target: e2k: Fix bugs. 2021-07-31 02:33:03 +03:00
Denis Drakhnia 6cd1e55a70 target: e2k: Add loop_end/not_loop_end condition. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 4f8aec99a5 target: e2k: Impl rotated pregs. 2021-07-31 02:33:02 +03:00
Denis Drakhnia c59bd94281 target: e2k: Remove type from macro GEN_MASK. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 905fa26d0f target: e2k: Add store instrs. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 368e31db47 target: e2k: Add load instrs. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 6cd1b1b708 target: e2k: Add getsp instr. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 07f2b730fb target: e2k: Add read/write to %usd. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 8f5efae8d8 target: e2k: Add merges and merged instrs. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 5221e50edf target: e2k: Add sxt instr. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 4a2934f5a0 target: e2k: Fix crash on conditional syscall. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 3e3508f9bd target: e2k: Add basic syscall support. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 779fc80db4 target: e2k: Try to impl syscall. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 42cd4b2c56 target: e2k: Add e2k_gen get and set field. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 9caeb1a1dd target: e2k: Add disp and ct instrs support. 2021-07-31 02:33:02 +03:00
Denis Drakhnia cf066b7b00 target: e2k: Add negated predicate ct condition. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 7dfb4f0064 target: e2k: Reorg control flow. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 56c122557d target: e2k: Reorg. 2021-07-31 02:33:02 +03:00
Denis Drakhnia 4a882f6e23 target: e2k: Comment unused vars for future use. 2021-07-31 02:33:02 +03:00
Denis Drakhnia f10f86baeb target: e2k: Move TCG CPU State to translate.h. 2021-07-31 02:33:01 +03:00
Denis Drakhnia 2cb98bc101 target: e2k: Add cpu state is_jmp. 2021-07-31 02:33:01 +03:00
Denis Drakhnia a1a62134f9 target: e2k: Use win_ptr for regs. 2021-07-31 02:33:01 +03:00
Denis Drakhnia 138ef8a409 target: e2k: Add window ptr. 2021-07-31 02:33:01 +03:00
Denis Drakhnia 65f0ec0ddb target: e2k: Commit bundle instrs at the end. 2021-07-31 02:33:01 +03:00
Denis Drakhnia 1957823609 target: e2k: Simple condition jump. 2021-07-31 02:33:01 +03:00
Alibek Omarov 734a2c52ca target: e2k: fix instructions with speculative mode 2021-07-31 02:33:01 +03:00
Alibek Omarov 640e6f5795 target: e2k: implement disas_log, doesn't work at all 2021-07-31 02:33:01 +03:00
Denis Drakhnia f5f246ce2d target: e2k: Basic instruction execution. 2021-07-31 02:33:01 +03:00
Alibek Omarov 7720349e2b elf: fix wrong Elbrus elf machine id 2021-07-31 02:33:01 +03:00
Denis Drakhnia 42b90e6046 target: e2k: unpack long instructions. 2021-07-31 02:33:01 +03:00
Alibek Omarov 0d8fe3691c disas: import disassmebler from binutils 2021-07-31 02:33:01 +03:00
Alibek Omarov 68e2e890cb target: e2k: add cpu definitions 2021-07-31 02:33:01 +03:00
Alibek Omarov 7215f303c1 linux-user: add loading ELFs for e2kg 2021-07-31 02:33:01 +03:00
Alibek Omarov 4bda3b32bc softmmu: add e2k definition 2021-07-31 02:33:01 +03:00
Alibek Omarov 3d8eabf29d configs: add e2k-linux-user config 2021-07-31 02:32:59 +03:00
Alibek Omarov 0c4d9b8d1c include/elf.h: add MCST Elbrus definitions 2021-07-31 02:32:33 +03:00
96 changed files with 40838 additions and 15 deletions

View File

@ -0,0 +1,13 @@
# Default configuration for e2k-softmmu
# Dev:
#
CONFIG_APIC=y
CONFIG_IOAPIC=y
CONFIG_PCI=y
CONFIG_ELBRUS_SIM_CONSOLE=y
CONFIG_PCI_IOHUB=y
CONFIG_VGA_CIRRUS=y
CONFIG_VGA_PCI=y
CONFIG_ATI_VGA=y
CONFIG_ESCC_PCI=y

View File

@ -0,0 +1,2 @@
TARGET_ARCH=e2k
TARGET_XML_FILES= gdb-xml/e2k-v1.xml gdb-xml/e2k-v2.xml gdb-xml/e2k-v3.xml gdb-xml/e2k-v5.xml

View File

@ -0,0 +1,3 @@
TARGET_ARCH=e2k
TARGET_SUPPORTS_MTTCG=y
TARGET_XML_FILES= gdb-xml/e2k-v1.xml gdb-xml/e2k-v2.xml gdb-xml/e2k-v3.xml gdb-xml/e2k-v5.xml

View File

@ -0,0 +1,5 @@
TARGET_ARCH=e2k32
TARGET_BASE_ARCH=e2k
TARGET_ABI_DIR=e2k
TARGET_ABI32=y
TARGET_XML_FILES= gdb-xml/e2k-v1.xml gdb-xml/e2k-v2.xml gdb-xml/e2k-v3.xml gdb-xml/e2k-v5.xml

View File

@ -207,6 +207,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

File diff suppressed because it is too large Load Diff

2730
disas/e2k.c Normal file

File diff suppressed because it is too large Load Diff

556
disas/e2k.h Normal file
View 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;

View File

@ -7,6 +7,7 @@ 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_HEXAGON_DIS', if_true: files('hexagon.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_M68K_DIS', if_true: files('m68k.c'))

View File

@ -138,7 +138,7 @@ static void parts64_default_nan(FloatParts64 *p, 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;

2464
gdb-xml/e2k-v1.xml Normal file

File diff suppressed because it is too large Load Diff

6
gdb-xml/e2k-v2.xml Normal file
View File

@ -0,0 +1,6 @@
<feature name="org.mcst.gdb.elbrus-v2.linux">
<!-- 840 -->
<reg name="idr" bitsize="64" type="uint64"/>
</feature>

6
gdb-xml/e2k-v3.xml Normal file
View File

@ -0,0 +1,6 @@
<feature name="org.mcst.gdb.elbrus-v3.linux">
<!-- 841 -->
<reg name="core_mode" bitsize="64" type="uint64"/>
</feature>

86
gdb-xml/e2k-v5.xml Normal file
View File

@ -0,0 +1,86 @@
<feature name="org.mcst.gdb.elbrus-v5.linux">
<!-- This type seems to be common for %lsr1 and %ilcr1 -->
<!-- lsr1 -->
<struct id="lsr1_bits" size="8">
<field name="lcnt_lo" start="0" end="31"/>
<field name="lcnt_hi" start="32" end="63"/>
</struct>
<union id="lsr1">
<field name="dword" type="uint64"/>
<field name="" type="lsr1_bits"/>
</union>
<reg name="lsr1" bitsize="64" type="lsr1"/>
<reg name="ilcr1" bitsize="64" type="lsr1"/>
<reg name="_gext_v5_0" bitsize="16" type="uint64"/>
<reg name="_gext_v5_1" bitsize="16" type="uint64"/>
<reg name="_gext_v5_2" bitsize="16" type="uint64"/>
<reg name="_gext_v5_3" bitsize="16" type="uint64"/>
<reg name="_gext_v5_4" bitsize="16" type="uint64"/>
<reg name="_gext_v5_5" bitsize="16" type="uint64"/>
<reg name="_gext_v5_6" bitsize="16" type="uint64"/>
<reg name="_gext_v5_7" bitsize="16" type="uint64"/>
<reg name="_gext_v5_8" bitsize="16" type="uint64"/>
<reg name="_gext_v5_9" bitsize="16" type="uint64"/>
<reg name="_gext_v5_10" bitsize="16" type="uint64"/>
<reg name="_gext_v5_11" bitsize="16" type="uint64"/>
<reg name="_gext_v5_12" bitsize="16" type="uint64"/>
<reg name="_gext_v5_13" bitsize="16" type="uint64"/>
<reg name="_gext_v5_14" bitsize="16" type="uint64"/>
<reg name="_gext_v5_15" bitsize="16" type="uint64"/>
<reg name="_gext_v5_16" bitsize="16" type="uint64"/>
<reg name="_gext_v5_17" bitsize="16" type="uint64"/>
<reg name="_gext_v5_18" bitsize="16" type="uint64"/>
<reg name="_gext_v5_19" bitsize="16" type="uint64"/>
<reg name="_gext_v5_20" bitsize="16" type="uint64"/>
<reg name="_gext_v5_21" bitsize="16" type="uint64"/>
<reg name="_gext_v5_22" bitsize="16" type="uint64"/>
<reg name="_gext_v5_23" bitsize="16" type="uint64"/>
<reg name="_gext_v5_24" bitsize="16" type="uint64"/>
<reg name="_gext_v5_25" bitsize="16" type="uint64"/>
<reg name="_gext_v5_26" bitsize="16" type="uint64"/>
<reg name="_gext_v5_27" bitsize="16" type="uint64"/>
<reg name="_gext_v5_28" bitsize="16" type="uint64"/>
<reg name="_gext_v5_29" bitsize="16" type="uint64"/>
<reg name="_gext_v5_30" bitsize="16" type="uint64"/>
<reg name="_gext_v5_31" bitsize="16" type="uint64"/>
<reg name="_gtag_v5_0" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_1" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_2" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_3" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_4" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_5" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_6" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_7" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_8" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_9" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_10" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_11" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_12" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_13" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_14" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_15" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_16" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_17" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_18" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_19" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_20" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_21" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_22" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_23" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_24" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_25" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_26" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_27" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_28" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_29" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_30" bitsize="8" type="uint8"/>
<reg name="_gtag_v5_31" bitsize="8" type="uint8"/>
</feature>

View File

@ -2178,6 +2178,12 @@ static void handle_query_supported(GArray *params, 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();
}
@ -2319,6 +2325,32 @@ static void handle_set_qemu_phy_mem_mode(GArray *params, void *user_ctx)
}
#endif
#ifdef TARGET_E2K
static void handle_query_e2k_tags_read(GArray *params, void *user_ctx)
{
E2KCPU *cpu = E2K_CPU(gdbserver_state.g_cpu);
CPUE2KState *env = &cpu->env;
target_ulong addr = get_param(params, 0)->val_ull;
unsigned long len = get_param(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 * 2)) & 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 const GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
/* Order is important if has same prefix */
{
@ -2413,6 +2445,14 @@ static const 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 const GdbCmdParseEntry gdb_gen_set_table[] = {

View File

@ -1,6 +1,11 @@
config ESCC
bool
config ESCC_PCI
bool
depends on PCI
select ESCC
config HTIF
bool
@ -68,3 +73,6 @@ config SIFIVE_UART
config GOLDFISH_TTY
bool
config ELBRUS_SIM_CONSOLE
bool

View File

@ -33,6 +33,11 @@
#include "ui/console.h"
#include "trace.h"
#define CONFIG_ESCC_PCI0
#ifdef CONFIG_ESCC_PCI0
#include "hw/pci/pci.h"
#endif
/*
* Chipset docs:
* "Z80C30/Z85C30/Z80230/Z85230/Z85233 SCC/ESCC User Manual",
@ -878,9 +883,85 @@ static const TypeInfo escc_info = {
.class_init = escc_class_init,
};
#ifdef CONFIG_ESCC_PCI0
#include "hw/pci/pci_bus.h"
#define TYPE_ESCC_PCI "escc-pci"
struct ESCCPCIState {
PCIDevice dev;
ESCCState escc;
};
OBJECT_DECLARE_SIMPLE_TYPE(ESCCPCIState, ESCC_PCI)
static void escc_pci_realize(PCIDevice *dev, Error **errp)
{
ESCCPCIState *pci = ESCC_PCI(dev);
ESCCState *s = &pci->escc;
if (!sysbus_realize(SYS_BUS_DEVICE(s), errp)) {
return;
}
pci->dev.config[PCI_CLASS_PROG] = 0x02;
pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
pci_register_bar(&pci->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
memory_region_add_subregion(pci_address_space(&pci->dev), 0x1000, &s->mmio);
}
static void escc_pci_exit(PCIDevice *dev)
{
/*ESCCPCIState *pci = ESCC_PCI(dev);
ESCCState *s = &pci->escc;
sysbus_unrealize(SYS_BUS_DEVICE(s));*/
}
static void escc_pci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
pc->realize = escc_pci_realize;
pc->exit = escc_pci_exit;
pc->vendor_id = 0x1fff;
pc->device_id = 0x8019;
pc->revision = 1;
pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
/* dc->vmsd = &vmstate_pci_serial; */
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
static void escc_pci_init(Object *o)
{
ESCCPCIState *ps = ESCC_PCI(o);
object_initialize_child(o, "escc", &ps->escc, TYPE_ESCC);
qdev_alias_all_properties(DEVICE(&ps->escc), o);
}
static const TypeInfo escc_pci_info = {
.name = TYPE_ESCC_PCI,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(ESCCPCIState),
.instance_init = escc_pci_init,
.class_init = escc_pci_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
#endif /* CONFIG_ESCC_PCI */
static void escc_register_types(void)
{
type_register_static(&escc_info);
#ifdef CONFIG_ESCC_PCI0
type_register_static(&escc_pci_info);
#endif /* CONFIG_ESCC_PCI */
}
type_init(escc_register_types)

149
hw/char/lmscon.c Normal file
View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2021 Alibek Omarov
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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/log.h"
#include "exec/memory.h"
#include "exec/address-spaces.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "hw/sysbus.h"
#include "chardev/char-fe.h"
#include "hw/char/lmscon.h"
#include "trace.h"
#define LMS_CONS_DATA_PORT 0x300UL /* On READ - data from keyboard */
/* On WRITE - data to debug ouput */
/* port (console/journal) */
#define LMS_CONS_STATUS_PORT 0x301UL /* On READ - data available on 0x300 */
/* On WRITE - shift count for 0x304 */
#define LMS_NSOCK_BADDR_PORT 0x302UL /* On READ - network socket base addr*/
/* On WRITE - the same. */
#define LMS_NSOCK_DATA_PORT 0x303UL /* On READ - data from network socket*/
/* On WRITE - data to network socket*/
#define LMS_TRACE_CNTL_PORT 0x304UL /* On READ - state of the instruction*/
/* counter */
/* On WRITE - LMS tracer control */
/* (1 - start, 0 - stop) */
#define LMS_TRACE_CNTL_OFF 0
#define LMS_TRACE_CNTL_ON 1
static void lmscon_mem_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
LMSCONState *s = opaque;
trace_lmscon_write(addr, val, size);
if (!qemu_chr_fe_backend_connected(&s->chr))
return;
switch(LMS_CONS_DATA_PORT + addr)
{
case LMS_CONS_DATA_PORT:
if (size == 1) {
s->tx = val;
qemu_chr_fe_write_all(&s->chr, (uint8_t*)&s->tx, size);
} else {
qemu_log_mask(LOG_UNIMP, "%s: LMS_CONS_DATA_PORT unknown size %d\n",
__func__, size);
}
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: unimplemented lmscon packet %lx\n",
__func__, LMS_CONS_DATA_PORT + addr);
break;
}
}
static uint64_t lmscon_mem_read(void *opaque, hwaddr addr, unsigned size)
{
LMSCONState *s = opaque;
uint64_t r = 0;
switch(LMS_CONS_DATA_PORT + addr)
{
case LMS_CONS_DATA_PORT:
if (!qemu_chr_fe_backend_connected(&s->chr))
r = 0xFFFFFFFF; /* port disabled */
else qemu_chr_fe_read_all(&s->chr, (uint8_t*)&r, size);
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: unimplemented lmscon packet %lx\n",
__func__, LMS_CONS_DATA_PORT + addr);
break;
}
trace_lmscon_read(addr, r, size);
return r;
}
static const MemoryRegionOps lmscon_mem_ops = {
.read = lmscon_mem_read,
.write = lmscon_mem_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 4,
},
};
static void lmscon_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sb = SYS_BUS_DEVICE(dev);
LMSCONState *s = LMSCON(dev);
const uint64_t size = LMS_TRACE_CNTL_PORT - LMS_CONS_DATA_PORT + 1;
memory_region_init_io(&s->io, OBJECT(dev), &lmscon_mem_ops, s, "lmscon", size);
sysbus_add_io(sb, LMS_CONS_DATA_PORT, &s->io);
sysbus_init_ioports(sb, LMS_CONS_DATA_PORT, size);
}
static Property lmscon_properties[] = {
DEFINE_PROP_CHR("chr", LMSCONState, chr),
DEFINE_PROP_END_OF_LIST(),
};
static void lmscon_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = lmscon_realize;
device_class_set_props(dc, lmscon_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
static TypeInfo lmscon_info = {
.name = TYPE_LMSCON,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(LMSCONState),
.class_init = lmscon_class_init
};
static void lmscon_register_types(void)
{
type_register_static(&lmscon_info);
}
type_init(lmscon_register_types)

View File

@ -32,6 +32,7 @@ softmmu_ss.add(when: 'CONFIG_SIFIVE_UART', if_true: files('sifive_uart.c'))
softmmu_ss.add(when: 'CONFIG_SH_SCI', if_true: files('sh_serial.c'))
softmmu_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_usart.c'))
softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_MMUART', if_true: files('mchp_pfsoc_mmuart.c'))
softmmu_ss.add(when: 'CONFIG_ELBRUS_SIM_CONSOLE', if_true: files('lmscon.c'))
specific_ss.add(when: 'CONFIG_HTIF', if_true: files('riscv_htif.c'))
specific_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('terminal3270.c'))

View File

@ -99,3 +99,7 @@ exynos_uart_rx_timeout(uint32_t channel, uint32_t stat, uint32_t intsp) "UART%d:
# cadence_uart.c
cadence_uart_baudrate(unsigned baudrate) "baudrate %u"
# lmscon.c
lmscon_read(uint64_t addr, uint64_t r, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u"
lmscon_write(uint64_t addr, uint64_t val, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u"

0
hw/e2k/Kconfig Normal file
View File

322
hw/e2k/e2k.c Normal file
View File

@ -0,0 +1,322 @@
/*
* Copyright (c) 2021 Denis Drakhnya
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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/datadir.h"
#include "qemu/log.h"
#include "qapi/error.h"
#include "trace.h"
#include "chardev/char-fe.h"
#include "sysemu/sysemu.h"
#include "sysemu/cpus.h"
#include "sysemu/reset.h"
#include "hw/irq.h"
#include "hw/loader.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "hw/pci/pci_bridge.h"
#include "hw/e2k/e2k.h"
#include "hw/e2k/bootinfo.h"
#include "target/e2k/cpu.h"
#include "elf.h"
#include "hw/char/escc.h"
#include "hw/char/lmscon.h"
struct
{
target_ulong loadaddr;
} reset_params;
DeviceState *cpu_get_current_apic(void)
{
if (current_cpu) {
E2KCPU *cpu = E2K_CPU(current_cpu);
return cpu->apic_state;
} else {
return NULL;
}
}
int pci_e2k_map_irq(PCIDevice *pci_dev, int irq_num)
{
return (irq_num + (pci_dev->devfn >> 3)) & 3;
}
static void e2k_cpu_reset(void *opaque)
{
E2KCPU *cpu = opaque;
CPUState *cs = CPU(cpu);
cpu_reset(cs);
cpu_set_pc(cs, reset_params.loadaddr);
}
static void cpus_init(E2KMachineState *e2kms)
{
MachineState *ms = MACHINE(e2kms);
int i;
for (i = 0; i < ms->smp.cpus; i++) {
Object *cpu = object_new(ms->cpu_type);
if (!qdev_realize(DEVICE(cpu), NULL, &error_fatal)) {
error_report("failed to create cpu");
exit(1);
}
qemu_register_reset(e2k_cpu_reset, cpu);
}
}
/*
static void lmscon_init(E2KMachineState *e2kms)
{
DeviceState *dev;
dev = qdev_new(TYPE_LMSCON);
qdev_prop_set_chr(dev, "chr", serial_hd(0));
if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal)) {
error_report("failed to create lmscon");
exit(1);
}
}
*/
static bootblock_struct_t *generate_bootblock(E2KMachineState *e2kms,
ram_addr_t kernel_base, long kernel_size)
{
static bootblock_struct_t bootblock;
boot_info_t *const bootinfo = &bootblock.info;
MachineState *ms = MACHINE(e2kms);
memset(&bootblock, 0, sizeof(bootblock));
/* Set signature */
bootinfo->signature = bootblock.x86_marker = X86BOOT_SIGNATURE;
bootblock.bootblock_ver = BOOTBLOCK_VER;
/* Init CPU info */
bootinfo->num_of_nodes = 1; /* TODO: numa */
bootinfo->nodes_map = 0x1;
bootinfo->num_of_cpus = ms->smp.cpus;
/* Init RAM banks */
if(ms->ram_size > E2K_MLO_SIZE) {
/* high mem */
bootinfo->num_of_banks = 2;
bootinfo->nodes_mem[0].banks[0].address = 0;
bootinfo->nodes_mem[0].banks[0].size = E2K_MLO_SIZE;
bootinfo->nodes_mem[0].banks[1].address = E2K_HIMEM_BASE;
bootinfo->nodes_mem[0].banks[1].size = ms->ram_size - E2K_MLO_SIZE;
} else {
/* low mem only */
bootinfo->num_of_banks = 1;
bootinfo->nodes_mem[0].banks[0].address = 0;
bootinfo->nodes_mem[0].banks[0].size = ms->ram_size;
}
bootinfo->kernel_base = kernel_base;
bootinfo->kernel_size = kernel_size;
strncpy(bootinfo->kernel_args_string, ms->kernel_cmdline, sizeof(*bootinfo->kernel_args_string));
bootinfo->kernel_args_string[sizeof(*bootinfo->kernel_args_string)] = 0;
return &bootblock;
}
static bool e2k_kernel_init(E2KMachineState *e2kms, MemoryRegion *rom_memory)
{
MachineState *ms = MACHINE(e2kms);
uint64_t entry, kernel_high;
long size;
MemoryRegion *kernel;
if (!ms->kernel_filename)
return false;
/* FIXME: set ip to entry, for now it just equals to FIRMWARE_LOAD_ADDR */
size = load_elf(ms->kernel_filename, NULL, NULL, NULL,
&entry, NULL, &kernel_high, NULL, 0, EM_MCST_ELBRUS,
0, 0);
if (size <= 0) {
error_report("could not load kernel '%s': %s",
ms->kernel_filename, load_elf_strerror(size));
return false;
}
e2kms->bootblock = generate_bootblock(e2kms, entry, size);
/* TODO: load initrd */
kernel = g_malloc(sizeof(*kernel));
memory_region_init_ram(kernel, NULL, "e2k.kernel", size, &error_fatal);
memory_region_add_subregion(rom_memory, entry, kernel);
reset_params.loadaddr = entry;
return true;
}
static void firmware_init(E2KMachineState *e2kms, const char *default_filename,
MemoryRegion *rom_memory)
{
MachineState *ms = MACHINE(e2kms);
const char *firmware_name;
char *filename;
int size;
MemoryRegion *firmware;
firmware_name = ms->firmware ?: default_filename;
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware_name);
if (filename == NULL) {
error_report("no firmware provided");
exit(1);
}
size = get_image_size(filename);
if (size < 0) {
error_report("failed to get firmware size '%s'", filename);
exit(1);
}
if (rom_add_file_fixed(firmware_name,
E2K_BIOS_AREA_BASE, -1) != 0) {
error_report("could not load firmware '%s'", firmware_name);
exit(1);
}
g_free(filename);
firmware = g_malloc(sizeof(*firmware));
memory_region_init_ram(firmware, NULL, "e2k.firmware",
E2K_BIOS_AREA_SIZE, &error_fatal);
memory_region_add_subregion(rom_memory,
E2K_BIOS_AREA_BASE, firmware);
reset_params.loadaddr = E2K_BIOS_AREA_BASE;
}
static void e2k_gsi_handler(void *opaque, int n, int level)
{
GSIState *s = opaque;
qemu_set_irq(s->ioapic_irq[n], level);
}
#define ESCC_CLOCK 2457600
static PCIDevice *pci_init(E2KMachineState *e2kms, qemu_irq *pic)
{
PCIDevice *d;
PCIBridge *br;
e2kms->bus = iohub_init(TYPE_IOHUB_PCI_HOST_BRIDGE, TYPE_IOHUB_PCI_DEVICE,
&e2kms->iohub,
get_system_memory(), get_system_io(), pic);
d = pci_new_multifunction(PCI_DEVFN(0, 0), true, TYPE_IOHUB_PCI_BRIDGE);
br = PCI_BRIDGE(d);
br->bus_name = "pci";
pci_bridge_map_irq(br, TYPE_IOHUB_PCI_BRIDGE, pci_e2k_map_irq);
pci_realize_and_unref(d, e2kms->bus, &error_fatal);
d = pci_new_multifunction(PCI_DEVFN(2, 2), true, "escc-pci");
qdev_prop_set_uint32(DEVICE(d), "frequency", ESCC_CLOCK);
qdev_prop_set_uint32(DEVICE(d), "it_shift", 0);
qdev_prop_set_chr(DEVICE(d), "chrA", serial_hd(0));
qdev_prop_set_chr(DEVICE(d), "chrB", serial_hd(1));
qdev_prop_set_uint32(DEVICE(d), "chnBtype", escc_serial);
qdev_prop_set_uint32(DEVICE(d), "chnAtype", escc_serial);
pci_realize_and_unref(d, e2kms->bus, &error_fatal);
return PCI_DEVICE(br);
}
static void e2k_machine_init(MachineState *ms)
{
E2KMachineState *e2kms = E2K_MACHINE(ms);
MemoryRegion *rom_memory;
MemoryRegion *ram_below_4g, *ram_above_4g;
qemu_irq *pic;
rom_memory = get_system_memory();
/* Init RAM banks */
if(ms->ram_size > E2K_MLO_SIZE) {
e2kms->above_4g_mem_size = ms->ram_size - E2K_MLO_SIZE;
e2kms->below_4g_mem_size = E2K_MLO_SIZE;
} else {
e2kms->above_4g_mem_size = E2K_MLO_BASE;
e2kms->below_4g_mem_size = ms->ram_size;
}
ram_below_4g = g_malloc(sizeof(*ram_below_4g));
memory_region_init_alias(ram_below_4g, NULL, "ram-below-4g", ms->ram,
0, e2kms->below_4g_mem_size);
memory_region_add_subregion(rom_memory, 0, ram_below_4g);
if(e2kms->above_4g_mem_size > 0) {
ram_above_4g = g_malloc(sizeof(*ram_above_4g));
memory_region_init_alias(ram_above_4g, NULL, "ram-above-4g",
ms->ram,
e2kms->below_4g_mem_size,
e2kms->above_4g_mem_size);
memory_region_add_subregion(rom_memory, E2K_HIMEM_BASE, ram_above_4g);
}
e2kms->ioapic_as = &address_space_memory;
if (!e2k_kernel_init(e2kms, rom_memory))
firmware_init(e2kms, "e2k.bin", rom_memory);
e2kms->gsi_state = g_new0(GSIState, 1);
pic = qemu_allocate_irqs(e2k_gsi_handler, e2kms->gsi_state, IOAPIC_NUM_PINS);
cpus_init(e2kms);
/* lmscon_init(e2kms); */
sic_init(e2kms);
pci_init(e2kms, pic);
}
static void e2k_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Generic E2K Machine";
mc->init = e2k_machine_init;
mc->default_machine_opts = "firmware=e2k.bin";
mc->is_default = true;
mc->max_cpus = 8;
mc->default_cpu_type = "e8c"; // TODO
mc->default_ram_id = "e2k.ram";
}
static const TypeInfo e2k_machine_info = {
.name = TYPE_E2K_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(E2KMachineState),
.class_init = e2k_machine_class_init,
};
static void e2k_machine_register_types(void)
{
type_register_static(&e2k_machine_info);
}
type_init(e2k_machine_register_types)

6
hw/e2k/meson.build Normal file
View File

@ -0,0 +1,6 @@
e2k_ss = ss.source_set()
e2k_ss.add(files('e2k.c', 'sic.c'))
#e2k_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-common.c'))
hw_arch += {'e2k': e2k_ss}

461
hw/e2k/sic.c Normal file
View File

@ -0,0 +1,461 @@
/*
* Copyright (c) 2021 Alibek Omarov
*
* System Interchange Controller emulation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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/datadir.h"
#include "qemu/log.h"
#include "qapi/error.h"
#include "trace.h"
#include "sysemu/cpus.h"
#include "sysemu/reset.h"
#include "hw/loader.h"
#include "hw/e2k/e2k.h"
#include "target/e2k/cpu.h"
#include "elf.h"
struct SICState *sicregs;
#define SIC_rt_lcfg0 0x10
#define SIC_rt_lcfg1 0x14
#define SIC_rt_lcfg2 0x18
#define SIC_rt_lcfg3 0x1c
#define SIC_rt_mhi0 0x20
#define SIC_rt_mhi1 0x24
#define SIC_rt_mhi2 0x28
#define SIC_rt_mhi3 0x2c
#define SIC_rt_mlo0 0x30
#define SIC_rt_mlo1 0x34
#define SIC_rt_mlo2 0x38
#define SIC_rt_mlo3 0x3c
#define SIC_rt_msi 0xb0
#define SIC_rt_msi_h 0xb4
#define SIC_rt_pcim0 0x40
#define SIC_rt_pcim1 0x44
#define SIC_rt_pcim2 0x48
#define SIC_rt_pcim3 0x4c
#define SIC_rt_pciio0 0x50
#define SIC_rt_pciio1 0x54
#define SIC_rt_pciio2 0x58
#define SIC_rt_pciio3 0x5c
#define SIC_rt_pcimp_b0 0x70
#define SIC_rt_pcimp_b1 0x74
#define SIC_rt_pcimp_b2 0x78
#define SIC_rt_pcimp_b3 0x7c
#define SIC_rt_pcimp_e0 0x80
#define SIC_rt_pcimp_e1 0x84
#define SIC_rt_pcimp_e2 0x88
#define SIC_rt_pcimp_e3 0x8c
#define SIC_rt_pcicfgb 0x90
#define SIC_prepic_ctrl2 0x8030
#define SIC_prepic_err_stat 0x8040
#define SIC_prepic_err_int 0x8060
#define SIC_prepic_linp0 0x8c00
#define SIC_prepic_linp1 0x8c04
#define SIC_prepic_linp2 0x8c08
#define SIC_prepic_linp3 0x8c0c
#define SIC_prepic_linp4 0x8c10
#define SIC_prepic_linp5 0x8c14
#define SIC_iommu_ctrl 0x0380
#define SIC_iommu_ba_lo 0x0390
#define SIC_iommu_dtba_lo 0x0398
#define SIC_iommu_err 0x03b0
#define SIC_iommu_err_info_lo 0x03b8
static uint64_t sic_mem_read(void *opaque, hwaddr addr, unsigned size)
{
E2KMachineState *ms = opaque;
SICState *regs = &ms->sicregs;
uint64_t ret;
int index;
index = addr & (E2K_SICREGS_SIZE - 1);
switch (index) {
case SIC_rt_lcfg0:
ret = regs->rt_lcfg0;
break;
case SIC_rt_lcfg1:
ret = regs->rt_lcfg1;
break;
case SIC_rt_lcfg2:
ret = regs->rt_lcfg2;
break;
case SIC_rt_lcfg3:
ret = regs->rt_lcfg3;
break;
case SIC_rt_mhi0:
ret = regs->rt_mhi0.word;
break;
case SIC_rt_mhi1:
ret = regs->rt_mhi1.word;
break;
case SIC_rt_mhi2:
ret = regs->rt_mhi2.word;
break;
case SIC_rt_mhi3:
ret = regs->rt_mhi3.word;
break;
case SIC_rt_mlo0:
ret = regs->rt_mlo0.word;
break;
case SIC_rt_mlo1:
ret = regs->rt_mlo1.word;
break;
case SIC_rt_mlo2:
ret = regs->rt_mlo2.word;
break;
case SIC_rt_mlo3:
ret = regs->rt_mlo3.word;
break;
case SIC_rt_msi:
ret = regs->rt_msi & 0xffffffff;
break;
case SIC_rt_msi_h:
ret = regs->rt_msi >> 32;
break;
case SIC_rt_pcim0:
ret = regs->rt_pcim0.word;
break;
case SIC_rt_pcim1:
ret = regs->rt_pcim1.word;
break;
case SIC_rt_pcim2:
ret = regs->rt_pcim2.word;
break;
case SIC_rt_pcim3:
ret = regs->rt_pcim3.word;
break;
case SIC_rt_pciio0:
ret = regs->rt_pciio0.word;
break;
case SIC_rt_pciio1:
ret = regs->rt_pciio1.word;
break;
case SIC_rt_pciio2:
ret = regs->rt_pciio2.word;
break;
case SIC_rt_pciio3:
ret = regs->rt_pciio3.word;
break;
case SIC_rt_pcimp_b0:
ret = regs->rt_pcimp_b0.addr;
break;
case SIC_rt_pcimp_b1:
ret = regs->rt_pcimp_b1.addr;
break;
case SIC_rt_pcimp_b2:
ret = regs->rt_pcimp_b2.addr;
break;
case SIC_rt_pcimp_b3:
ret = regs->rt_pcimp_b3.addr;
break;
case SIC_rt_pcimp_e0:
ret = regs->rt_pcimp_e0.addr;
break;
case SIC_rt_pcimp_e1:
ret = regs->rt_pcimp_e1.addr;
break;
case SIC_rt_pcimp_e2:
ret = regs->rt_pcimp_e2.addr;
break;
case SIC_rt_pcimp_e3:
ret = regs->rt_pcimp_e3.addr;
break;
case SIC_rt_pcicfgb:
ret = regs->rt_pcicfgb.word;
break;
case SIC_prepic_ctrl2:
ret = regs->prepic_ctrl2;
break;
case SIC_prepic_err_stat:
ret = regs->prepic_err_stat;
break;
case SIC_prepic_err_int:
ret = regs->prepic_err_int;
break;
case SIC_prepic_linp0:
ret = regs->prepic_linp0;
break;
case SIC_prepic_linp1:
ret = regs->prepic_linp1;
break;
case SIC_prepic_linp2:
ret = regs->prepic_linp2;
break;
case SIC_prepic_linp3:
ret = regs->prepic_linp3;
break;
case SIC_prepic_linp4:
ret = regs->prepic_linp4;
break;
case SIC_prepic_linp5:
ret = regs->prepic_linp5;
break;
case SIC_iommu_err:
ret = regs->iommu_err;
break;
case SIC_iommu_err_info_lo:
ret = regs->iommu_err_info;
;
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: unknown SIC register 0x%x\n", __func__, index);
ret = 0;
break;
}
trace_sic_mem_readl(addr, ret);
return ret;
}
static void sic_mem_write(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
{
E2KMachineState *ms = opaque;
SICState *regs = &ms->sicregs;
int index;
index = addr & (E2K_SICREGS_SIZE - 1);
switch (index) {
case SIC_rt_msi:
regs->rt_msi = (regs->rt_msi & 0xffffffff00000000) | val;
break;
case SIC_rt_msi_h:
regs->rt_msi = (regs->rt_msi & 0x00000000ffffffff) | (val << 32);
break;
case SIC_rt_mhi0:
regs->rt_mhi0.word = val;
break;
case SIC_rt_mhi1:
regs->rt_mhi1.word = val;
break;
case SIC_rt_mhi2:
regs->rt_mhi2.word = val;
break;
case SIC_rt_mhi3:
regs->rt_mhi3.word = val;
break;
case SIC_rt_mlo0:
regs->rt_mlo0.word = val;
break;
case SIC_rt_mlo1:
regs->rt_mlo1.word = val;
break;
case SIC_rt_mlo2:
regs->rt_mlo2.word = val;
break;
case SIC_rt_mlo3:
regs->rt_mlo3.word = val;
break;
case SIC_rt_pcim0:
regs->rt_pcim0.word = val;
break;
case SIC_rt_pcim1:
regs->rt_pcim1.word = val;
break;
case SIC_rt_pcim2:
regs->rt_pcim2.word = val;
break;
case SIC_rt_pcim3:
regs->rt_pcim3.word = val;
break;
case SIC_rt_pciio0:
regs->rt_pciio0.word = val;
break;
case SIC_rt_pciio1:
regs->rt_pciio1.word = val;
break;
case SIC_rt_pciio2:
regs->rt_pciio2.word = val;
break;
case SIC_rt_pciio3:
regs->rt_pciio3.word = val;
break;
case SIC_rt_pcimp_b0:
regs->rt_pcimp_b0.addr = val;
break;
case SIC_rt_pcimp_b1:
regs->rt_pcimp_b1.addr = val;
break;
case SIC_rt_pcimp_b2:
regs->rt_pcimp_b2.addr = val;
break;
case SIC_rt_pcimp_b3:
regs->rt_pcimp_b3.addr = val;
break;
case SIC_rt_pcimp_e0:
regs->rt_pcimp_e0.addr = val;
break;
case SIC_rt_pcimp_e1:
regs->rt_pcimp_e1.addr = val;
break;
case SIC_rt_pcimp_e2:
regs->rt_pcimp_e2.addr = val;
break;
case SIC_rt_pcimp_e3:
regs->rt_pcimp_e3.addr = val;
break;
case SIC_rt_pcicfgb:
regs->rt_pcicfgb.word = val;
break;
case SIC_prepic_ctrl2:
regs->prepic_ctrl2 = val;
break;
case SIC_prepic_err_stat:
regs->prepic_err_stat = val;
break;
case SIC_prepic_err_int:
regs->prepic_err_int = val;
break;
case SIC_prepic_linp0:
regs->prepic_linp0 = val;
break;
case SIC_prepic_linp1:
regs->prepic_linp1 = val;
break;
case SIC_prepic_linp2:
regs->prepic_linp2 = val;
break;
case SIC_prepic_linp3:
regs->prepic_linp3 = val;
break;
case SIC_prepic_linp4:
regs->prepic_linp4 = val;
break;
case SIC_prepic_linp5:
regs->prepic_linp5 = val;
break;
case SIC_iommu_ctrl:
regs->iommu_ctrl = val;
break;
case SIC_iommu_ba_lo:
regs->iommu_ptbar = val;
break;
case SIC_iommu_dtba_lo:
regs->iommu_dtbar = val;
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: unknown SIC register 0x%x\n", __func__, index);
break;
}
trace_sic_mem_writel(addr, val);
}
static const MemoryRegionOps sic_io_ops = {
.read = sic_mem_read,
.write = sic_mem_write,
.impl = {
.min_access_size = 1,
.max_access_size = 4,
},
.valid = {
.min_access_size = 1,
.max_access_size = 4,
},
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void sic_reset(SICState *sic)
{
memset(sic, 0, sizeof(*sic));
sic->rt_lcfg0 = 0xb; /* BSP node */
sic->rt_lcfg1 = 0x30;
sic->rt_lcfg2 = 0x30;
sic->rt_lcfg3 = 0x30;
sic->rt_mhi0.E2K_RT_MHI_reg =
sic->rt_mhi1.E2K_RT_MHI_reg =
sic->rt_mhi2.E2K_RT_MHI_reg =
sic->rt_mhi3.E2K_RT_MHI_reg = 0;
sic->rt_mhi0.E2K_RT_MHI_bgn =
sic->rt_mhi1.E2K_RT_MHI_bgn =
sic->rt_mhi2.E2K_RT_MHI_bgn =
sic->rt_mhi3.E2K_RT_MHI_bgn = ~0;
sic->rt_mhi0.E2K_RT_MHI_end =
sic->rt_mhi1.E2K_RT_MHI_end =
sic->rt_mhi2.E2K_RT_MHI_end =
sic->rt_mhi3.E2K_RT_MHI_end = 0;
sic->rt_mlo0.E2K_RT_MLO_reg =
sic->rt_mlo1.E2K_RT_MLO_reg =
sic->rt_mlo2.E2K_RT_MLO_reg =
sic->rt_mlo3.E2K_RT_MLO_reg = 0;
sic->rt_mlo0.E2K_RT_MLO_bgn =
sic->rt_mlo1.E2K_RT_MLO_bgn =
sic->rt_mlo2.E2K_RT_MLO_bgn =
sic->rt_mlo3.E2K_RT_MLO_bgn = ~0;
sic->rt_mlo0.E2K_RT_MLO_end =
sic->rt_mlo1.E2K_RT_MLO_end =
sic->rt_mlo2.E2K_RT_MLO_end =
sic->rt_mlo3.E2K_RT_MLO_end = 0;
sic->rt_pcim0.E2K_RT_PCIM_reg =
sic->rt_pcim1.E2K_RT_PCIM_reg =
sic->rt_pcim2.E2K_RT_PCIM_reg =
sic->rt_pcim3.E2K_RT_PCIM_reg = 0;
sic->rt_pcim0.E2K_RT_PCIM_bgn =
sic->rt_pcim1.E2K_RT_PCIM_bgn =
sic->rt_pcim2.E2K_RT_PCIM_bgn =
sic->rt_pcim3.E2K_RT_PCIM_bgn = ~0;
sic->rt_pcim0.E2K_RT_PCIM_end =
sic->rt_pcim1.E2K_RT_PCIM_end =
sic->rt_pcim2.E2K_RT_PCIM_end =
sic->rt_pcim3.E2K_RT_PCIM_end = 0;
sic->rt_pciio0.E2K_RT_PCIIO_reg =
sic->rt_pciio1.E2K_RT_PCIIO_reg =
sic->rt_pciio2.E2K_RT_PCIIO_reg =
sic->rt_pciio3.E2K_RT_PCIIO_reg = 0;
sic->rt_pciio0.E2K_RT_PCIIO_bgn =
sic->rt_pciio1.E2K_RT_PCIIO_bgn =
sic->rt_pciio2.E2K_RT_PCIIO_bgn =
sic->rt_pciio3.E2K_RT_PCIIO_bgn = ~0;
sic->rt_pciio0.E2K_RT_PCIIO_end =
sic->rt_pciio1.E2K_RT_PCIIO_end =
sic->rt_pciio2.E2K_RT_PCIIO_end =
sic->rt_pciio3.E2K_RT_PCIIO_end = 0;
sic->rt_pcimp_b0.E2K_RT_PCIMP_reg =
sic->rt_pcimp_b1.E2K_RT_PCIMP_reg =
sic->rt_pcimp_b2.E2K_RT_PCIMP_reg =
sic->rt_pcimp_b3.E2K_RT_PCIMP_reg = 0;
sic->rt_pcimp_b0.E2K_RT_PCIMP_bgn =
sic->rt_pcimp_b1.E2K_RT_PCIMP_bgn =
sic->rt_pcimp_b2.E2K_RT_PCIMP_bgn =
sic->rt_pcimp_b3.E2K_RT_PCIMP_bgn = ~0;
sic->rt_pcimp_e0.E2K_RT_PCIMP_reg =
sic->rt_pcimp_e1.E2K_RT_PCIMP_reg =
sic->rt_pcimp_e2.E2K_RT_PCIMP_reg =
sic->rt_pcimp_e3.E2K_RT_PCIMP_reg = 0;
sic->rt_pcicfgb.E2K_RT_PCICFGB_bgn = 0x8; /* see E2K_PCICFG_BASE */
}
void sic_init(E2KMachineState *ms)
{
sic_reset(&ms->sicregs);
memory_region_init_io(&ms->sicregion, OBJECT(ms), &sic_io_ops, ms, "sic-nbsr",
E2K_SICREGS_SIZE);
memory_region_add_subregion(get_system_memory(), E2K_SICREGS_BASE, &ms->sicregion);
}

7
hw/e2k/trace-events Normal file
View File

@ -0,0 +1,7 @@
# See docs/devel/tracing.txt for syntax documentation.
# e2k.c
e2k_gsi_interrupt(int irqn, int level) "GSI interrupt #%d level:%d"
sic_mem_readl(uint64_t addr, uint32_t val) "0x%"PRIx64" = 0x%08x"
sic_mem_writel(uint64_t addr, uint32_t val) "0x%"PRIx64" = 0x%08x"

1
hw/e2k/trace.h Normal file
View File

@ -0,0 +1 @@
#include "trace/trace-hw_e2k.h"

View File

@ -18,9 +18,15 @@
*/
#include "qemu/osdep.h"
#include "qemu/thread.h"
#include "hw/i386/apic_internal.h"
#include "hw/i386/apic.h"
#include "hw/i386/ioapic.h"
#if defined(TARGET_E2K)
# include "hw/e2k/apic_internal.h"
# include "hw/e2k/apic.h"
# include "hw/e2k/ioapic.h"
#else
# include "hw/i386/apic_internal.h"
# include "hw/i386/apic.h"
# include "hw/i386/ioapic.h"
#endif
#include "hw/intc/i8259.h"
#include "hw/pci/msi.h"
#include "qemu/host-utils.h"
@ -497,6 +503,10 @@ static void apic_startup(APICCommonState *s, int vector_num)
void apic_sipi(DeviceState *dev)
{
#if defined(TARGET_E2K)
/* TODO: e2k */
abort();
#else
APICCommonState *s = APIC(dev);
cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
@ -505,6 +515,7 @@ void apic_sipi(DeviceState *dev)
return;
cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector);
s->wait_for_sipi = 0;
#endif
}
static void apic_deliver(DeviceState *dev, uint8_t dest, uint8_t dest_mode,
@ -653,6 +664,11 @@ static uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size)
index = (addr >> 4) & 0xff;
switch(index) {
#ifdef TARGET_E2K
case 0x01: /* base */
val = cpu_get_apic_base(dev);
break;
#endif
case 0x02: /* id */
val = s->id << 24;
break;
@ -766,6 +782,11 @@ static void apic_mem_write(void *opaque, hwaddr addr, uint64_t val,
trace_apic_mem_writel(addr, val);
switch(index) {
#ifdef TARGET_E2K
case 0x01: /* base */
cpu_set_apic_base(dev, val);
break;
#endif
case 0x02:
s->id = (val >> 24);
break;

View File

@ -23,8 +23,13 @@
#include "qemu/module.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "hw/i386/apic.h"
#include "hw/i386/apic_internal.h"
#if defined(TARGET_E2K)
# include "hw/e2k/apic.h"
# include "hw/e2k/apic_internal.h"
#else
# include "hw/i386/apic.h"
# include "hw/i386/apic_internal.h"
#endif
#include "trace.h"
#include "hw/boards.h"
#include "sysemu/hax.h"
@ -117,9 +122,14 @@ void apic_enable_vapic(DeviceState *dev, hwaddr paddr)
void apic_handle_tpr_access_report(DeviceState *dev, target_ulong ip,
TPRAccess access)
{
#if defined(TARGET_E2K)
/* TODO: e2k */
abort();
#else
APICCommonState *s = APIC_COMMON(dev);
vapic_report_tpr_access(s->vapic, CPU(s->cpu), ip, access);
#endif
}
void apic_report_irq_delivered(int delivered)
@ -286,7 +296,6 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
{
APICCommonState *s = APIC_COMMON(dev);
APICCommonClass *info;
static DeviceState *vapic;
uint32_t instance_id = s->initial_apic_id;
/* Normally initial APIC ID should be no more than hundreds */
@ -295,6 +304,9 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
info = APIC_COMMON_GET_CLASS(s);
info->realize(dev, errp);
#if !defined(TARGET_E2K)
static DeviceState *vapic;
/* Note: We need at least 1M to map the VAPIC option ROM */
if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
!hax_enabled() && current_machine->ram_size >= 1024 * 1024) {
@ -310,6 +322,7 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
}
vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common,
s, -1, 0, NULL);
#endif
}
static void apic_common_unrealize(DeviceState *dev)

View File

@ -23,10 +23,17 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "monitor/monitor.h"
#if defined(TARGET_E2K)
#include "hw/e2k/apic.h"
#include "hw/e2k/ioapic.h"
#include "hw/e2k/e2k.h"
#else
#include "hw/i386/apic.h"
#include "hw/i386/ioapic.h"
#include "hw/i386/ioapic_internal.h"
#include "hw/i386/x86.h"
#endif
#include "hw/i386/ioapic_internal.h"
#include "hw/intc/i8259.h"
#include "hw/pci/msi.h"
#include "hw/qdev-properties.h"
@ -90,7 +97,11 @@ static void ioapic_entry_parse(uint64_t entry, struct ioapic_entry_info *info)
static void ioapic_service(IOAPICCommonState *s)
{
#ifdef TARGET_E2K
AddressSpace *ioapic_as = E2K_MACHINE(qdev_get_machine())->ioapic_as;
#else
AddressSpace *ioapic_as = X86_MACHINE(qdev_get_machine())->ioapic_as;
#endif
struct ioapic_entry_info info;
uint8_t i;
uint32_t mask;

View File

@ -47,6 +47,7 @@ subdir('alpha')
subdir('arm')
subdir('avr')
subdir('cris')
subdir('e2k')
subdir('hppa')
subdir('i386')
subdir('m68k')

View File

@ -77,3 +77,7 @@ config MV64361
bool
select PCI
select I8259
config PCI_IOHUB
bool
select PCI

302
hw/pci-host/iohub.c Normal file
View File

@ -0,0 +1,302 @@
/*
* QEMU IOHUB PCI Bridge Emulation
*
* Copyright (c) 2021 Alibek Omarov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "hw/e2k/e2k.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_host.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci-host/iohub.h"
#include "hw/qdev-properties.h"
#include "hw/irq.h"
#include "hw/sysbus.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "qemu/error-report.h"
#include "qom/object.h"
#include "trace.h"
OBJECT_DECLARE_SIMPLE_TYPE(IOHUBState, IOHUB_PCI_HOST_BRIDGE)
struct IOHUBState {
PCIHostState parent_obj;
qemu_irq *pic;
};
/* PCI config address are 27-bit in length.
* bit 20-27: bus number
* bit 12-19: devfn
* bit 0-11: device register address
*/
#define IOHUB_CONFIG_ADDR_BUS(addr) (((addr) >> 20) & 0xff)
#define IOHUB_CONFIG_ADDR_DEVFN(addr) (((addr) >> 12) & 0xff)
#define IOHUB_CONFIG_ADDR_REG(addr) (((addr) >> 0) & 0xfff)
#define TO_IOHUB_CONFIG_ADDR(bus, devfn, where) ((((bus) & 0xff) << 20) | (((devfn) & 0xff) << 12) | ((where) & 0xfff))
#define TO_PCI_CONFIG_ADDR(bus, devfn, reg) ((((bus) & 0xff) << 16) | (((devfn) & 0xff) << 8) | (((reg) & 0xff) << 0))
static void pci_e2k_set_irq(void *opaque, int irq_num, int level)
{
IOHUBState *s = opaque;
qemu_irq *pic = s->pic;
int npic = irq_num + ISA_NUM_IRQS - 1;
if(npic == 15)
{
npic = 19;
}
qemu_set_irq(pic[npic], level);
}
static inline uint32_t
iohub_pci_config_addr(hwaddr addr, uint8_t *bus, uint8_t *devfn, uint16_t *reg)
{
*bus = IOHUB_CONFIG_ADDR_BUS(addr);
*devfn = IOHUB_CONFIG_ADDR_DEVFN(addr);
*reg = IOHUB_CONFIG_ADDR_REG(addr);
return TO_PCI_CONFIG_ADDR(*bus, *devfn, *reg);
}
static uint64_t iohub_pci_config_read(void *opaque, hwaddr addr, unsigned size)
{
uint8_t bus, devfn;
uint16_t reg;
uint64_t val;
hwaddr conf_addr = iohub_pci_config_addr(addr, &bus, &devfn, &reg);
val = pci_data_read(opaque, conf_addr, size);
trace_iohub_pci_config_read(addr, conf_addr, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), reg, val);
return val;
}
static void iohub_pci_config_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
uint8_t bus, devfn;
uint16_t reg;
hwaddr conf_addr = iohub_pci_config_addr(addr, &bus, &devfn, &reg);
trace_iohub_pci_config_write(addr, conf_addr, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), reg, val);
pci_data_write(opaque, conf_addr, val, size);
}
static const MemoryRegionOps iohub_pci_config_ops = {
.read = iohub_pci_config_read,
.write = iohub_pci_config_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
PCIBus *iohub_init(const char *host_type, const char *pci_type,
PCIIOHUBState **piohub_state,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
qemu_irq *pic)
{
DeviceState *dev;
SysBusDevice *sb;
PCIDevice *d;
PCIHostState *s;
PCIBus *b;
PCIIOHUBState *f;
MemoryRegion *pci_address_space, *pci_config_as;
dev = qdev_new(host_type);
s = PCI_HOST_BRIDGE(dev);
sb = SYS_BUS_DEVICE(dev);
IOHUB_PCI_HOST_BRIDGE(dev)->pic = pic;
pci_address_space = g_malloc(sizeof(*pci_address_space));
memory_region_init_io(pci_address_space, OBJECT(dev), NULL, NULL, "pcimem", E2K_PCIMEM_SIZE);
memory_region_add_subregion(address_space_mem, E2K_PCIMEM_BASE, pci_address_space);
s->bus = b = pci_root_bus_new(dev, NULL,
pci_address_space,
address_space_io,
0, TYPE_PCI_BUS);
pci_bus_irqs(b, pci_e2k_set_irq, pci_e2k_map_irq, pic, 4);
object_property_add_child(qdev_get_machine(), "iohub", OBJECT(dev));
sysbus_realize_and_unref(sb, &error_fatal);
pci_config_as = g_malloc(sizeof(*pci_config_as));
memory_region_init_io(pci_config_as, OBJECT(dev), &iohub_pci_config_ops, s->bus, "pcicfg", E2K_PCICFG_SIZE);
sysbus_init_mmio(sb, pci_config_as);
sysbus_mmio_map(sb, 0, E2K_PCICFG_BASE);
d = pci_create_simple(b, PCI_DEVFN(1, 0), pci_type);
f = *piohub_state = IOHUB_PCI_DEVICE(d);
f->system_memory = address_space_mem;
f->pci_address_space = pci_address_space;
return b;
}
static void iohub_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *k = PCI_DEVICE_CLASS(oc);
k->vendor_id = 0x1fff;
k->device_id = 0x8017;
k->revision = 0x02;
k->class_id = PCI_CLASS_BRIDGE_HOST;
dc->desc = "IOHUB Host Bridge";
dc->user_creatable = false;
dc->hotpluggable = false;
}
static const TypeInfo iohub_info = {
.name = TYPE_IOHUB_PCI_DEVICE,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIIOHUBState),
.class_init = iohub_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void iohub_pcihost_initfn(Object *obj)
{
PCIHostState *s = PCI_HOST_BRIDGE(obj);
memory_region_init_io(&s->conf_mem, obj, &pci_host_conf_le_ops, s,
"pci-conf-idx", 4);
memory_region_init_io(&s->data_mem, obj, &pci_host_data_le_ops, s,
"pci-conf-data", 4);
}
static void iohub_pcihost_realize(DeviceState *dev, Error **errp)
{
PCIHostState *s = PCI_HOST_BRIDGE(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
sysbus_add_io(sbd, 0xcf8, &s->conf_mem);
sysbus_init_ioports(sbd, 0xcf8, 4);
sysbus_add_io(sbd, 0xcfc, &s->data_mem);
sysbus_init_ioports(sbd, 0xcfc, 4);
/* register iohub 0xcf8 port as coalesced pio */
memory_region_set_flush_coalesced(&s->data_mem);
memory_region_add_coalescing(&s->conf_mem, 0, 4);
}
static void iohub_pcihost_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = iohub_pcihost_realize;
dc->fw_name = "pci";
dc->user_creatable = false;
}
static const TypeInfo iohub_pcihost_info = {
.name = TYPE_IOHUB_PCI_HOST_BRIDGE,
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(IOHUBState),
.instance_init = iohub_pcihost_initfn,
.class_init = iohub_pcihost_class_init,
};
static void iohub_pcibridge_realize(PCIDevice *dev, Error **errp)
{
pci_set_word(dev->config + PCI_COMMAND, PCI_COMMAND_MEMORY);
pci_bridge_initfn(dev, TYPE_PCI_BUS);
/*
* command register:
* According to PCI bridge spec, after reset
* bus master bit is off
* PCI_COMMAND_MEMORY is ON
*/
pci_set_word(dev->config + PCI_STATUS,
PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
PCI_STATUS_DEVSEL_MEDIUM);
}
static uint32_t iohub_pcibridge_read_config(PCIDevice *d, uint32_t addr, int size)
{
uint8_t bus, devfn;
uint16_t reg;
uint32_t val;
hwaddr conf_addr = iohub_pci_config_addr(addr, &bus, &devfn, &reg);
val = pci_default_read_config(d, conf_addr, size);
return val;
}
static void iohub_pcibridge_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int size)
{
uint8_t bus, devfn;
uint16_t reg;
hwaddr conf_addr = iohub_pci_config_addr(addr, &bus, &devfn, &reg);
pci_bridge_write_config(d, conf_addr, val, size);
}
static void iohub_pcibridge_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
PCIDeviceClass *k = PCI_DEVICE_CLASS(oc);
k->realize = iohub_pcibridge_realize;
k->exit = pci_bridge_exitfn;
k->vendor_id = 0x1fff;
k->device_id = 0x8000;
k->revision = 0x10;
k->class_id = PCI_CLASS_BRIDGE_PCI;
k->config_write = iohub_pcibridge_write_config;
k->config_read = iohub_pcibridge_read_config;
k->is_bridge = true;
dc->desc = "IOHUB PCI2PCI Bridge";
dc->reset = pci_bridge_reset;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
}
static const TypeInfo iohub_pcibridge_info = {
.name = TYPE_IOHUB_PCI_BRIDGE,
.parent = TYPE_PCI_BRIDGE,
.instance_size = sizeof(PCIBridge),
.class_init = iohub_pcibridge_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
}
};
static void iohub_register_types(void)
{
type_register_static(&iohub_info);
type_register_static(&iohub_pcihost_info);
type_register_static(&iohub_pcibridge_info);
}
type_init(iohub_register_types);

View File

@ -12,6 +12,9 @@ pci_ss.add(when: 'CONFIG_XEN_IGD_PASSTHROUGH', if_true: files('xen_igd_pt.c'))
pci_ss.add(when: 'CONFIG_REMOTE_PCIHOST', if_true: files('remote.c'))
pci_ss.add(when: 'CONFIG_SH_PCI', if_true: files('sh_pci.c'))
# E2K/E90S devices
pci_ss.add(when: 'CONFIG_PCI_IOHUB', if_true: files('iohub.c'))
# PPC devices
pci_ss.add(when: 'CONFIG_RAVEN_PCI', if_true: files('raven.c'))
pci_ss.add(when: 'CONFIG_GRACKLE_PCI', if_true: files('grackle.c'))

View File

@ -6,6 +6,10 @@ bonito_spciconf_small_access(uint64_t addr, unsigned size) "PCI config address i
# grackle.c
grackle_set_irq(int irq_num, int level) "set_irq num %d level %d"
# iohub.c
iohub_pci_config_write(uint64_t addr, uint64_t confaddr, uint8_t bus, uint8_t slot, uint8_t func, uint16_t reg, uint64_t val) "addr 0x%"PRIx64" 0x%"PRIx64" dev %02x:%02x.%01d reg 0x%x val 0x%"PRIx64
iohub_pci_config_read(uint64_t addr, uint64_t confaddr, uint8_t bus, uint8_t slot, uint8_t func, uint16_t reg, uint64_t val) "addr 0x%"PRIx64" 0x%"PRIx64" dev %02x:%02x.%01d reg 0x%x val 0x%"PRIx64
# mv64361.c
mv64361_region_map(const char *name, uint64_t poffs, uint64_t size, uint64_t moffs) "Mapping %s 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64
mv64361_region_enable(const char *op, int num) "Should %s region %d"

View File

@ -373,6 +373,8 @@ void pci_bridge_initfn(PCIDevice *dev, const char *typename)
if (!br->bus_name && dev->qdev.id && *dev->qdev.id) {
br->bus_name = dev->qdev.id;
}
printf("%s\n", br->bus_name);
qbus_create_inplace(sec_bus, sizeof(br->sec_bus), typename, DEVICE(dev),
br->bus_name);

View File

@ -241,6 +241,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
@ -407,6 +424,14 @@ typedef struct disassemble_info {
int cap_mode;
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;
@ -462,6 +487,7 @@ 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_hexagon(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);

View File

@ -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 */
@ -1417,6 +1420,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;

View File

@ -13,6 +13,8 @@
#pragma GCC poison TARGET_ARM
#pragma GCC poison TARGET_CRIS
#pragma GCC poison TARGET_HEXAGON
#pragma GCC poison TARGET_E2K
#pragma GCC poison TARGET_E2K32
#pragma GCC poison TARGET_HPPA
#pragma GCC poison TARGET_M68K
#pragma GCC poison TARGET_MICROBLAZE

32
include/hw/char/lmscon.h Normal file
View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2021 Alibek Omarov
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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/>.
*/
#ifndef HW_LMSCON_H
#define HW_LMSCON_H
#define TYPE_LMSCON "lmscon"
OBJECT_DECLARE_SIMPLE_TYPE(LMSCONState, LMSCON)
struct LMSCONState {
SysBusDevice parent;
MemoryRegion io;
CharBackend chr;
uint8_t tx;
};
#endif /* HW_LMSCON_H */

27
include/hw/e2k/apic.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef APIC_H
#define APIC_H
/* apic.c */
void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
uint8_t vector_num, uint8_t trigger_mode);
int apic_accept_pic_intr(DeviceState *s);
void apic_deliver_pic_intr(DeviceState *s, int level);
void apic_deliver_nmi(DeviceState *d);
int apic_get_interrupt(DeviceState *s);
void apic_reset_irq_delivered(void);
int apic_get_irq_delivered(void);
void cpu_set_apic_base(DeviceState *s, uint64_t val);
uint64_t cpu_get_apic_base(DeviceState *s);
void cpu_set_apic_tpr(DeviceState *s, uint8_t val);
uint8_t cpu_get_apic_tpr(DeviceState *s);
void apic_init_reset(DeviceState *s);
void apic_sipi(DeviceState *s);
void apic_poll_irq(DeviceState *d);
void apic_designate_bsp(DeviceState *d, bool bsp);
int apic_get_highest_priority_irr(DeviceState *dev);
/* pc.c */
DeviceState *cpu_get_current_apic(void);
#endif

View File

@ -0,0 +1,231 @@
/*
* APIC support - internal interfaces
*
* Copyright (c) 2004-2005 Fabrice Bellard
* Copyright (c) 2011 Jan Kiszka, Siemens AG
*
* 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/>
*/
#ifndef QEMU_APIC_INTERNAL_H
#define QEMU_APIC_INTERNAL_H
#include "cpu.h"
#include "exec/memory.h"
#include "qemu/timer.h"
#include "target/e2k/cpu-qom.h"
#include "qom/object.h"
/* APIC Local Vector Table */
#define APIC_LVT_TIMER 0
#define APIC_LVT_THERMAL 1
#define APIC_LVT_PERFORM 2
#define APIC_LVT_LINT0 3
#define APIC_LVT_LINT1 4
#define APIC_LVT_ERROR 5
#define APIC_LVT_NB 6
/* APIC delivery modes */
#define APIC_DM_FIXED 0
#define APIC_DM_LOWPRI 1
#define APIC_DM_SMI 2
#define APIC_DM_NMI 4
#define APIC_DM_INIT 5
#define APIC_DM_SIPI 6
#define APIC_DM_EXTINT 7
/* APIC destination mode */
#define APIC_DESTMODE_FLAT 0xf
#define APIC_DESTMODE_CLUSTER 1
#define APIC_TRIGGER_EDGE 0
#define APIC_TRIGGER_LEVEL 1
#define APIC_VECTOR_MASK 0xff
#define APIC_DCR_MASK 0xf
#define APIC_LVT_TIMER_SHIFT 17
#define APIC_LVT_MASKED_SHIFT 16
#define APIC_LVT_LEVEL_TRIGGER_SHIFT 15
#define APIC_LVT_REMOTE_IRR_SHIFT 14
#define APIC_LVT_INT_POLARITY_SHIFT 13
#define APIC_LVT_DELIV_STS_SHIFT 12
#define APIC_LVT_DELIV_MOD_SHIFT 8
#define APIC_LVT_TIMER_TSCDEADLINE (2 << APIC_LVT_TIMER_SHIFT)
#define APIC_LVT_TIMER_PERIODIC (1 << APIC_LVT_TIMER_SHIFT)
#define APIC_LVT_MASKED (1 << APIC_LVT_MASKED_SHIFT)
#define APIC_LVT_LEVEL_TRIGGER (1 << APIC_LVT_LEVEL_TRIGGER_SHIFT)
#define APIC_LVT_REMOTE_IRR (1 << APIC_LVT_REMOTE_IRR_SHIFT)
#define APIC_LVT_INT_POLARITY (1 << APIC_LVT_INT_POLARITY_SHIFT)
#define APIC_LVT_DELIV_STS (1 << APIC_LVT_DELIV_STS_SHIFT)
#define APIC_LVT_DELIV_MOD (7 << APIC_LVT_DELIV_MOD_SHIFT)
#define APIC_ESR_ILL_ADDRESS_SHIFT 7
#define APIC_ESR_RECV_ILL_VECT_SHIFT 6
#define APIC_ESR_SEND_ILL_VECT_SHIFT 5
#define APIC_ESR_RECV_ACCEPT_SHIFT 3
#define APIC_ESR_SEND_ACCEPT_SHIFT 2
#define APIC_ESR_RECV_CHECK_SUM_SHIFT 1
#define APIC_ESR_ILLEGAL_ADDRESS (1 << APIC_ESR_ILL_ADDRESS_SHIFT)
#define APIC_ESR_RECV_ILLEGAL_VECT (1 << APIC_ESR_RECV_ILL_VECT_SHIFT)
#define APIC_ESR_SEND_ILLEGAL_VECT (1 << APIC_ESR_SEND_ILL_VECT_SHIFT)
#define APIC_ESR_RECV_ACCEPT (1 << APIC_ESR_RECV_ACCEPT_SHIFT)
#define APIC_ESR_SEND_ACCEPT (1 << APIC_ESR_SEND_ACCEPT_SHIFT)
#define APIC_ESR_RECV_CHECK_SUM (1 << APIC_ESR_RECV_CHECK_SUM_SHIFT)
#define APIC_ESR_SEND_CHECK_SUM 1
#define APIC_ICR_DEST_SHIFT 24
#define APIC_ICR_DEST_SHORT_SHIFT 18
#define APIC_ICR_TRIGGER_MOD_SHIFT 15
#define APIC_ICR_LEVEL_SHIFT 14
#define APIC_ICR_DELIV_STS_SHIFT 12
#define APIC_ICR_DEST_MOD_SHIFT 11
#define APIC_ICR_DELIV_MOD_SHIFT 8
#define APIC_ICR_DEST_SHORT (3 << APIC_ICR_DEST_SHORT_SHIFT)
#define APIC_ICR_TRIGGER_MOD (1 << APIC_ICR_TRIGGER_MOD_SHIFT)
#define APIC_ICR_LEVEL (1 << APIC_ICR_LEVEL_SHIFT)
#define APIC_ICR_DELIV_STS (1 << APIC_ICR_DELIV_STS_SHIFT)
#define APIC_ICR_DEST_MOD (1 << APIC_ICR_DEST_MOD_SHIFT)
#define APIC_ICR_DELIV_MOD (7 << APIC_ICR_DELIV_MOD_SHIFT)
#define APIC_PR_CLASS_SHIFT 4
#define APIC_PR_SUB_CLASS 0xf
#define APIC_LOGDEST_XAPIC_SHIFT 4
#define APIC_LOGDEST_XAPIC_ID 0xf
#define APIC_LOGDEST_X2APIC_SHIFT 16
#define APIC_LOGDEST_X2APIC_ID 0xffff
#define APIC_SPURIO_FOCUS_SHIFT 9
#define APIC_SPURIO_ENABLED_SHIFT 8
#define APIC_SPURIO_FOCUS (1 << APIC_SPURIO_FOCUS_SHIFT)
#define APIC_SPURIO_ENABLED (1 << APIC_SPURIO_ENABLED_SHIFT)
#define APIC_SV_DIRECTED_IO (1 << 12)
#define APIC_SV_ENABLE (1 << 8)
#define VAPIC_ENABLE_BIT 0
#define VAPIC_ENABLE_MASK (1 << VAPIC_ENABLE_BIT)
typedef struct APICCommonState APICCommonState;
#define TYPE_APIC_COMMON "apic-common"
typedef struct APICCommonClass APICCommonClass;
DECLARE_OBJ_CHECKERS(APICCommonState, APICCommonClass,
APIC_COMMON, TYPE_APIC_COMMON)
struct APICCommonClass {
DeviceClass parent_class;
DeviceRealize realize;
DeviceUnrealize unrealize;
void (*set_base)(APICCommonState *s, uint64_t val);
void (*set_tpr)(APICCommonState *s, uint8_t val);
uint8_t (*get_tpr)(APICCommonState *s);
void (*enable_tpr_reporting)(APICCommonState *s, bool enable);
void (*vapic_base_update)(APICCommonState *s);
void (*external_nmi)(APICCommonState *s);
void (*pre_save)(APICCommonState *s);
void (*post_load)(APICCommonState *s);
void (*reset)(APICCommonState *s);
/* send_msi emulates an APIC bus and its proper place would be in a new
* device, but it's convenient to have it here for now.
*/
void (*send_msi)(MSIMessage *msi);
};
struct APICCommonState {
/*< private >*/
DeviceState parent_obj;
/*< public >*/
MemoryRegion io_memory;
E2KCPU *cpu;
uint32_t apicbase;
uint8_t id; /* legacy APIC ID */
uint32_t initial_apic_id;
uint8_t version;
uint8_t arb_id;
uint8_t tpr;
uint32_t spurious_vec;
uint8_t log_dest;
uint8_t dest_mode;
uint32_t isr[8]; /* in service register */
uint32_t tmr[8]; /* trigger mode register */
uint32_t irr[8]; /* interrupt request register */
uint32_t lvt[APIC_LVT_NB];
uint32_t esr; /* error register */
uint32_t icr[2];
uint32_t divide_conf;
int count_shift;
uint32_t initial_count;
int64_t initial_count_load_time;
int64_t next_time;
QEMUTimer *timer;
int64_t timer_expiry;
int sipi_vector;
int wait_for_sipi;
uint32_t vapic_control;
DeviceState *vapic;
hwaddr vapic_paddr; /* note: persistence via kvmvapic */
bool legacy_instance_id;
};
typedef struct VAPICState {
uint8_t tpr;
uint8_t isr;
uint8_t zero;
uint8_t irr;
uint8_t enabled;
} QEMU_PACKED VAPICState;
extern bool apic_report_tpr_access;
void apic_report_irq_delivered(int delivered);
bool apic_next_timer(APICCommonState *s, int64_t current_time);
void apic_enable_tpr_access_reporting(DeviceState *d, bool enable);
void apic_enable_vapic(DeviceState *d, hwaddr paddr);
void vapic_report_tpr_access(DeviceState *dev, CPUState *cpu, target_ulong ip,
TPRAccess access);
int apic_get_ppr(APICCommonState *s);
uint32_t apic_get_current_count(APICCommonState *s);
static inline void apic_set_bit(uint32_t *tab, int index)
{
int i, mask;
i = index >> 5;
mask = 1 << (index & 0x1f);
tab[i] |= mask;
}
static inline int apic_get_bit(uint32_t *tab, int index)
{
int i, mask;
i = index >> 5;
mask = 1 << (index & 0x1f);
return !!(tab[i] & mask);
}
APICCommonClass *apic_get_class(void);
#endif /* QEMU_APIC_INTERNAL_H */

455
include/hw/e2k/bootinfo.h Normal file
View File

@ -0,0 +1,455 @@
/*
* Copyright (c) 2021 Alibek Omarov
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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/>.
*/
#ifndef HW_E2K_BOOTINFO
#define HW_E2K_BOOTINFO
/*
* Ripped from Linux MCST fork
*/
/*
* 0x0:
* 0x1: extended command line
*/
#define BOOTBLOCK_VER 0x1
#define KSTRMAX_SIZE 128
#define KSTRMAX_SIZE_EX 512
#define BIOS_INFO_SIGN_SIZE 8
#define KERNEL_ARGS_STRING_EX_SIGN_SIZE 22
#define BOOT_VER_STR_SIZE 128
#define BOOTBLOCK_SIZE 0x1000 /* 1 PAGE_SIZE */
#define X86BOOT_SIGNATURE 0x8086
#define ROMLOADER_SIGNATURE 0xe200
#define KVM_GUEST_SIGNATURE 0x20e2
#define BIOS_INFO_SIGNATURE "E2KBIOS"
#define KVM_INFO_SIGNATURE "E2KKVM"
#define KERNEL_ARGS_STRING_EX_SIGNATURE "KERNEL_ARGS_STRING_EX"
#define BOOT_KERNEL_ARGS_STRING_EX_SIGNATURE \
boot_va_to_pa(KERNEL_ARGS_STRING_EX_SIGNATURE)
/*
* Below is boot information that comes out of the x86 code of Linux/E2K
* loader proto.
*/
/* L_MAX_NODE_PHYS_BANKS = 4 sometimes is not enough, so we increase it to
* an arbitary value (8 now). The old L_MAX_NODE_PHYS_BANKS we rename to
* L_MAX_NODE_PHYS_BANKS_FUSTY and take in mind for boot_info compatibility.
*
* L_MAX_NODE_PHYS_BANKS_FUSTY and L_MAX_MEM_NUMNODES describe max size of
* array of memory banks on all nodes and should be in accordance with old value
* of L_MAX_PHYS_BANKS for compatibility with boot_info old structure (bank)
* size, so L_MAX_NODE_PHYS_BANKS_FUSTY * L_MAX_MEM_NUMNODES should be
* equal to 32.
*/
#define L_MAX_NODE_PHYS_BANKS 64 /* max number of memory banks */
/* on one node */
#define L_MAX_NODE_PHYS_BANKS_FUSTY 4 /* fusty max number of memory */
/* banks on one node */
#define L_MAX_PHYS_BANKS_EX 64 /* max number of memory banks */
/* in banks_ex field of */
/* boot_info */
#define L_MAX_MEM_NUMNODES 8 /* max number of nodes in the */
/* list of memory banks on */
/* each node */
#define L_MAX_BUSY_AREAS 4 /* max number of busy areas */
/* occupied by BIOS and should be */
/* kept unchanged by kernel to */
/* support recovery mode */
#ifndef __ASSEMBLY__
typedef struct bank_info {
uint64_t address; /* start address of bank */
uint64_t size; /* size of bank in bytes */
} bank_info_t;
typedef struct node_banks {
bank_info_t banks[L_MAX_NODE_PHYS_BANKS_FUSTY]; /* memory banks array */
/* of a node */
} node_banks_t;
typedef struct boot_times {
uint64_t arch;
uint64_t unpack;
uint64_t pci;
uint64_t drivers1;
uint64_t drivers2;
uint64_t menu;
uint64_t sm;
uint64_t kernel;
uint64_t reserved[8];
} boot_times_t;
typedef struct bios_info {
uint8_t signature[BIOS_INFO_SIGN_SIZE]; /* signature, */
/* 'E2KBIOS' */
uint8_t boot_ver[BOOT_VER_STR_SIZE]; /* boot version */
uint8_t mb_type; /* mother board type */
uint8_t chipset_type; /* chipset type */
uint8_t cpu_type; /* cpu type */
uint8_t kernel_args_string_ex[KSTRMAX_SIZE_EX]; /* extended command */
/* line of kernel */
/* used to pass */
/* command line */
/* from e2k BIOS */
uint8_t reserved1; /* reserved1 */
uint32_t cache_lines_damaged; /* number of damaged */
/* cache lines */
uint64_t nodes_mem_slabs_deprecated[52]; /* array of slabs */
/* accessible memory */
/* on each node */
/* accessible memory */
/* on each node */
bank_info_t banks_ex[L_MAX_PHYS_BANKS_EX]; /* extended array of */
/* descriptors of */
/* banks of available */
/* physical memory */
uint64_t devtree; /* devtree pointer */
uint32_t bootlog_addr; /* bootlog address */
uint32_t bootlog_len; /* bootlog length */
uint8_t uuid[16]; /* UUID boot device */
} bios_info_t;
typedef struct boot_info {
uint16_t signature; /* signature, 0x8086 */
uint8_t target_mdl; /* target cpu model number */
uint8_t reserved1; /* reserved1 */
uint16_t reserved2; /* reserved2 */
uint8_t vga_mode; /* vga mode */
uint8_t num_of_banks; /* number of available physical memory banks */
/* see below bank array */
/* total number on all nodes or 0 */
uint64_t kernel_base; /* base address to load kernel image */
/* if 0 then BIOS can load at any address */
/* but address should be large page size */
/* aligned - 4 Mb */
uint64_t kernel_size; /* kernel image byte's size */
uint64_t ramdisk_base; /* base address to load RAM-disk */
/* now not used */
uint64_t ramdisk_size; /* RAM-disk byte's size */
uint16_t num_of_cpus; /* number of started physical CPU(s) */
uint16_t mach_flags; /* machine identifacition flags */
/* should be set by our romloader and BIOS */
uint16_t num_of_busy; /* number of busy areas occupied by BIOS */
/* see below busy array */
uint16_t num_of_nodes; /* number of nodes on NUMA system */
uint64_t mp_table_base; /* MP-table base address */
uint64_t serial_base; /* base address of serial port for Am85c30 */
/* Used for debugging purpose */
uint64_t nodes_map; /* online nodes map */
uint64_t mach_serialn; /* serial number of the machine */
uint8_t mac_addr[6]; /* base MAC address for ethernet cards */
uint16_t reserved3; /* reserved3 */
char kernel_args_string[KSTRMAX_SIZE]; /* command line of kernel */
/* used to pass command line */
/* from e2k BIOS */
node_banks_t nodes_mem[L_MAX_MEM_NUMNODES]; /* array of */
/* descriptors of banks of */
/* available physical memory */
/* on each node */
bank_info_t busy[L_MAX_BUSY_AREAS]; /* descriptors of areas */
/* occupied by BIOS, all this */
/* shoud be kept in system */
/* recovery mode */
uint64_t cntp_info_deprecated[32]; /* control points */
/* info to save and */
/* restore them state */
uint64_t dmp_deprecated[20]; /* Info for future work of */
/* dump analyzer */
uint64_t reserved4[13]; /* reserved4 */
uint8_t mb_name[16]; /* Motherboard product name */
uint32_t reserved5; /* reserved5 */
uint32_t kernel_csum; /* kernel image control sum */
bios_info_t bios; /* extended BIOS info */
/* SHOULD BE LAST ITEM into this */
/* structure */
} boot_info_t;
typedef struct bootblock_struct {
boot_info_t info; /* general kernel<->BIOS info */
uint8_t /* zip area to make size of */
/* bootblock struct - constant */
gap[BOOTBLOCK_SIZE -
sizeof (boot_info_t) -
sizeof (boot_times_t) -
1 - /* u8 : bootblock_ver */
4 - /* u32 : reserved1 */
2 - /* u16 : kernel_flags */
1 - /* u8 : reserved2 */
5 - /* u8 : number of cnt points */
/* u8 : current # of cnt point */
/* u8 : number of cnt points */
/* ready in the memory */
/* u8 : number of cnt points */
/* saved on the disk */
/* u8 : all control points */
/* is created */
8 - /* u64 : dump sector */
8 - /* u64 : cnt point sector */
2 - /* u16 : dump device */
2 - /* u16 : cnt point device */
2 - /* u16 : boot_flags */
2]; /* u16 : x86_marker */
uint8_t bootblock_ver; /* bootblock version number */
uint32_t reserved1; /* reserved1 */
boot_times_t boot_times; /* boot load times */
uint16_t kernel_flags; /* kernel flags, boot should */
/* not modify it */
uint8_t reserved2; /* reserved2 */
uint8_t cnt_points_num_deprecated; /* number of control points */
/* all memory will be devided */
/* on this number of parts */
uint8_t cur_cnt_point_deprecated; /* current # of active */
/* control point (running */
/* part) */
uint8_t mem_cnt_points_deprecated; /* number of started control */
/* points (ready in the memory) */
uint8_t disk_cnt_points_deprecated; /* number of control points */
/* saved on the disk (ready */
/* to be loaded from disk) */
uint8_t cnt_points_created_deprecated; /* all control points created */
/* in the memory and on disk */
uint64_t dump_sector_deprecated; /* start sector # to dump */
/* physical memory */
uint64_t cnt_point_sector_deprecated; /* start sector # to save */
/* restore control points */
uint16_t dump_dev_deprecated; /* disk # to dump memory */
uint16_t cnt_point_dev_deprecated; /* disk # for save/restore */
/* control point */
uint16_t boot_flags; /* boot flags: if non */
/* zero then this structure */
/* is recovery info */
/* structure instead of boot */
/* info structure */
uint16_t x86_marker; /* marker of the end of x86 */
/* boot block (0xAA55) */
} bootblock_struct_t;
#endif /* __ASSEMBLY__ */
/*
* The mother board types
*/
#define MB_TYPE_MIN 0
#define MB_TYPE_E2K_BASE 0x00
#define MB_TYPE_ES2_BASE (MB_TYPE_E2K_BASE + 20)
#define MB_TYPE_E1CP_BASE (MB_TYPE_E2K_BASE + 50)
#define MB_TYPE_ES4_BASE (MB_TYPE_E2K_BASE + 70)
#define MB_TYPE_E8C_BASE (MB_TYPE_E2K_BASE + 80)
#define MB_TYPE_MAX a0
#define MB_TYPE_ES2_PLATO1 (MB_TYPE_ES2_BASE + 0)
#define MB_TYPE_ES2_BUTTERFLY (MB_TYPE_ES2_BASE + 1)
#define MB_TYPE_ES2_RTC_FM33256 (MB_TYPE_ES2_BASE + 2) /* FM332aa56 rtc */
#define MB_TYPE_ES2_RTC_CY14B101P (MB_TYPE_ES2_BASE + 3) /* CY14B101P rtc */
#define MB_TYPE_ES2_APORIA (MB_TYPE_ES2_BASE + 5) /* APORIA */
#define MB_TYPE_ES2_NT (MB_TYPE_ES2_BASE + 6) /* Nosimyi terminal */
/* Use this when CLKRs are not synchronized across the system */
#define MB_TYPE_ES2_RTC_CY14B101P_MULTICLOCK (MB_TYPE_ES2_BASE + 7)
#define MB_TYPE_ES2_CUB_COM (MB_TYPE_ES2_BASE + 8)
#define MB_TYPE_ES2_MBCUB_C (MB_TYPE_ES2_BASE + 11)
#define MB_TYPE_ES2_MB3S1_C (MB_TYPE_ES2_BUTTERFLY)
#define MB_TYPE_ES2_MB3S_C_K (MB_TYPE_ES2_BASE + 14)
#define MB_TYPE_ES2_MGA3D (MB_TYPE_ES2_BASE + 15)
#define MB_TYPE_ES2_BC_M4211 (MB_TYPE_ES2_BASE + 16)
#define MB_TYPE_ES2_EL2S4 (MB_TYPE_ES2_BASE + 17)
/* By default all mb_versions > MB_TYPE_ES2_EL2S4
* have cy14b101p rt clock. If no - fix is_cy14b101p_exist()
* in arch/l/kernel/i2c-spi/core.c
*/
#define MB_TYPE_E1CP_PMC (MB_TYPE_E1CP_BASE + 0) /* E1CP with PMC */
#define MB_TYPE_E1CP_IOHUB2_RAZBRAKOVSCHIK /* IOHUB2 razbrakovschik */ \
(MB_TYPE_E1CP_BASE + 1)
#define MB_TYPE_MBE1C_PC (MB_TYPE_E1CP_BASE + 2) /* E1CP with PMC */
#define MB_TYPE_ES4_MBE2S_PC (MB_TYPE_ES4_BASE + 0)
#define MB_TYPE_ES4_PC401 (MB_TYPE_ES4_BASE + 1)
#define MB_TYPE_E8C (MB_TYPE_E8C_BASE + 0)
/*
* The cpu types
*/
#define CPU_TYPE_E2S 0x03 /* E2S */
#define CPU_TYPE_ES2_DSP 0x04 /* E2C+ */
#define CPU_TYPE_ES2_RU 0x06 /* E2C Micron */
#define CPU_TYPE_E8C 0x07 /* E8C */
#define CPU_TYPE_E1CP 0x08 /* E1C+ */
#define CPU_TYPE_E8C2 0x09 /* E8C */
#define CPU_TYPE_E12C 0xa /* E12C */
#define CPU_TYPE_E16C 0xb /* E16C */
#define CPU_TYPE_E2C3 0xc /* E2C3 */
#define CPU_TYPE_SIMUL 0x3e /* simulator */
#define CPU_TYPE_MASK 0x3f /* mask of CPU type */
#define PROC_TYPE_MASK 0xc0 /* mask of MicroProcessor type */
#define GET_CPU_TYPE(type) (((type) & CPU_TYPE_MASK) >> 0)
/*
* The cpu types names
*/
#define GET_CPU_TYPE_NAME(type_field) \
({ \
unsigned char type = GET_CPU_TYPE(type_field); \
char *name; \
\
switch (type) { \
case CPU_TYPE_E2S: \
name = "E2S"; \
break; \
case CPU_TYPE_ES2_DSP: \
name = "E2C+DSP"; \
break; \
case CPU_TYPE_ES2_RU: \
name = "E1C"; \
break; \
case CPU_TYPE_E8C: \
name = "E8C"; \
break; \
case CPU_TYPE_E1CP: \
name = "E1C+"; \
break; \
case CPU_TYPE_E8C2: \
name = "E8C2"; \
break; \
case CPU_TYPE_E12C: \
name = "E12C"; \
break; \
case CPU_TYPE_E16C: \
name = "E16C"; \
break; \
case CPU_TYPE_E2C3: \
name = "E2C3"; \
break; \
case CPU_TYPE_SIMUL: \
name = "SIMUL"; \
break; \
default: \
name = "unknown"; \
} \
\
name; \
})
/*
* The mother board types names
*/
#define GET_MB_TYPE_NAME(type) \
({ \
char *name; \
\
switch (type) { \
case MB_TYPE_ES2_MB3S1_C: \
name = "MB3S1/C"; \
break; \
case MB_TYPE_ES2_MBCUB_C: \
case MB_TYPE_ES2_PLATO1: \
name = "MBKUB/C"; \
break; \
case MB_TYPE_ES2_MB3S_C_K: \
name = "MB3S/C-K"; \
break; \
case MB_TYPE_ES2_NT: \
name = "NT-ELBRUS-S"; \
break; \
case MB_TYPE_ES2_CUB_COM: \
name = "CUB-COM"; \
break; \
case MB_TYPE_ES2_RTC_FM33256: \
name = "MONOCUB+FM33256"; \
break; \
case MB_TYPE_ES2_RTC_CY14B101P: \
name = "MONOCUB"; \
break; \
case MB_TYPE_ES2_RTC_CY14B101P_MULTICLOCK: \
name = "MP1C1/V"; \
break; \
case MB_TYPE_ES2_EL2S4: \
name = "EL2S4"; \
break; \
case MB_TYPE_ES2_MGA3D: \
name = "MGA3D"; \
break; \
case MB_TYPE_ES2_BC_M4211: \
name = "BC-M4211"; \
break; \
case MB_TYPE_E1CP_PMC: \
name = "E1C+ PMC"; \
break; \
case MB_TYPE_E1CP_IOHUB2_RAZBRAKOVSCHIK: \
name = "IOHUB2 razbrakovschik"; \
break; \
case MB_TYPE_MBE1C_PC: \
name = "MBE1C-PC"; \
break; \
case MB_TYPE_ES4_MBE2S_PC: \
name = "MBE2S-PC"; \
break; \
case MB_TYPE_ES4_PC401: \
name = "PC-401"; \
break; \
case MB_TYPE_E8C: \
name = "E8C"; \
break; \
default: \
name = "unknown"; \
} \
\
name; \
})
#define GET_MB_USED_IN(type) \
({ \
char *name; \
\
switch (type) { \
case MB_TYPE_ES2_PLATO1: \
name = "Plato with softreset error"; \
break; \
case MB_TYPE_ES2_MBCUB_C: \
name = "APM VK-2, APM VK-120, BV632, BV631"; \
break; \
case MB_TYPE_ES2_MB3S1_C: \
name = "ELBRUS-3C-CVS, ELBRUS-3C"; \
break; \
case MB_TYPE_ES2_RTC_FM33256: \
name = "MONOCUB+FM33256"; \
break; \
case MB_TYPE_ES2_RTC_CY14B101P: \
name = "MONOCUB-M, MONOCUB-PC"; \
break; \
default: \
name = NULL; \
} \
\
name; \
})
#endif /* HW_E2K_BOOTINFO */

229
include/hw/e2k/e2k.h Normal file
View File

@ -0,0 +1,229 @@
/*
* Copyright (c) 2021 Denis Drakhnya
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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/>.
*/
#ifndef HW_E2K_H
#define HW_E2K_H
#include "qemu-common.h"
#include "hw/boards.h"
#include "qom/object.h"
#include "hw/e2k/ioapic.h"
#include "hw/e2k/bootinfo.h"
#include "hw/e2k/memmap.h"
#include "hw/pci-host/iohub.h"
/*
* Read/Write RT_PCIIOj Regs
*/
typedef unsigned int e2k_rt_pciio_t; /* Read/write pointer (32 bits) */
typedef struct e2k_rt_pciio_fields {
e2k_rt_pciio_t unused1 : 12; /* [11:0] */
e2k_rt_pciio_t bgn : 4; /* [15:12] */
e2k_rt_pciio_t unused2 : 12; /* [27:16] */
e2k_rt_pciio_t end : 4; /* [31:28] */
} e2k_rt_pciio_fields_t;
typedef union e2k_rt_pciio_struct { /* Structure of lower word */
e2k_rt_pciio_fields_t fields; /* as fields */
e2k_rt_pciio_t word; /* as entire register */
} e2k_rt_pciio_struct_t;
#define E2K_SIC_ALIGN_RT_PCIIO 12 /* 4 Kb */
#define E2K_SIC_SIZE_RT_PCIIO (1 << E2K_SIC_ALIGN_RT_PCIIO)
#define E2K_RT_PCIIO_bgn fields.bgn
#define E2K_RT_PCIIO_end fields.end
#define E2K_RT_PCIIO_reg word
/*
* Read/Write RT_PCIMj Regs
*/
typedef unsigned int e2k_rt_pcim_t; /* Read/write pointer (32 bits) */
typedef struct e2k_rt_pcim_fields {
e2k_rt_pcim_t unused1 : 11; /* [10:0] */
e2k_rt_pcim_t bgn : 5; /* [15:11] */
e2k_rt_pcim_t unused2 : 11; /* [26:16] */
e2k_rt_pcim_t end : 5; /* [31:27] */
} e2k_rt_pcim_fields_t;
typedef union e2k_rt_pcim_struct { /* Structure of lower word */
e2k_rt_pcim_fields_t fields; /* as fields */
e2k_rt_pcim_t word; /* as entire register */
} e2k_rt_pcim_struct_t;
#define E2K_SIC_ALIGN_RT_PCIM 27 /* 128 Mb */
#define E2K_SIC_SIZE_RT_PCIM (1 << E2K_SIC_ALIGN_RT_PCIM)
#define E2K_RT_PCIM_bgn fields.bgn
#define E2K_RT_PCIM_end fields.end
#define E2K_RT_PCIM_reg word
/*
* Read/Write RT_PCIMPj Regs
*/
typedef unsigned int e2k_rt_pcimp_t; /* Read/write pointer (32 bits) */
typedef struct e2k_rt_pcimp_struct {
e2k_rt_pcimp_t addr; /* [PA_MSB: 0] */
} e2k_rt_pcimp_struct_t;
#define E2K_SIC_ALIGN_RT_PCIMP 27 /* 128 Mb */
#define E2K_SIC_SIZE_RT_PCIMP (1 << E2K_SIC_ALIGN_RT_PCIMP)
#define E2K_RT_PCIMP_bgn addr
#define E2K_RT_PCIMP_end addr
#define E2K_RT_PCIMP_reg addr
/*
* Read/Write RT_PCICFGB Reg
*/
typedef unsigned int e2k_rt_pcicfgb_t; /* Read/write pointer (32 bits) */
typedef struct e2k_rt_pcicfgb_fields {
e2k_rt_pcicfgb_t unused1 : 3; /* [2:0] */
e2k_rt_pcicfgb_t bgn : 18; /* [20:3] */
e2k_rt_pcicfgb_t unused2 : 11; /* [31:21] */
} e2k_rt_pcicfgb_fields_t;
typedef union e2k_rt_pcicfgb_struct { /* Structure of lower word */
e2k_rt_pcicfgb_fields_t fields; /* as fields */
e2k_rt_pcicfgb_t word; /* as entire register */
} e2k_rt_pcicfgb_struct_t;
#define E2K_SIC_ALIGN_RT_PCICFGB 28 /* 256 Mb */
#define E2K_SIC_SIZE_RT_PCICFGB (1 << E2K_SIC_ALIGN_RT_PCICFGB)
#define E2K_RT_PCICFGB_bgn fields.bgn
#define E2K_RT_PCICFGB_reg word
#define RT_PCICFGB_NODE_BITS 2 /* 4 nodes */
#define RT_PCICFGB_IOLINK_BITS 0 /* 0 IO links per node */
/*
* Read/Write RT_MLOj Regs
*/
typedef unsigned int e2k_rt_mlo_t; /* Read/write pointer (32 bits) */
typedef struct e2k_rt_mlo_fields {
e2k_rt_mlo_t unused1 : 11; /* [10:0] */
e2k_rt_mlo_t bgn : 5; /* [15:11] */
e2k_rt_mlo_t unused2 : 11; /* [26:16] */
e2k_rt_mlo_t end : 5; /* [31:27] */
} e2k_rt_mlo_fields_t;
typedef union e2k_rt_mlo_struct { /* Structure of lower word */
e2k_rt_mlo_fields_t fields; /* as fields */
e2k_rt_mlo_t word; /* as entire register */
} e2k_rt_mlo_struct_t;
#define E2K_SIC_ALIGN_RT_MLO 27 /* 128 Mb */
#define E2K_SIC_SIZE_RT_MLO (1 << E2K_SIC_ALIGN_RT_MLO)
#define E2K_RT_MLO_bgn fields.bgn
#define E2K_RT_MLO_end fields.end
#define E2K_RT_MLO_reg word
/*
* Read/Write RT_MHIj Regs
*/
typedef unsigned int e2k_rt_mhi_t; /* Read/write pointer (32 bits) */
typedef struct e2k_rt_mhi_fields {
e2k_rt_mhi_t bgn : 16; /* [15: 0] */
e2k_rt_mhi_t end : 16; /* [31:16] */
} e2k_rt_mhi_fields_t;
typedef union e2k_rt_mhi_struct { /* Structure of lower word */
e2k_rt_mhi_fields_t fields; /* as fields */
e2k_rt_mhi_t word; /* as entire register */
} e2k_rt_mhi_struct_t;
#define E2K_SIC_ALIGN_RT_MHI 32 /* 4 Gb */
#define E2K_SIC_SIZE_RT_MHI (1UL << E2K_SIC_ALIGN_RT_MHI)
#define E2K_RT_MHI_bgn fields.bgn
#define E2K_RT_MHI_end fields.end
#define E2K_RT_MHI_reg word
typedef struct SICState {
uint32_t rt_lcfg0;
uint32_t rt_lcfg1;
uint32_t rt_lcfg2;
uint32_t rt_lcfg3;
e2k_rt_mhi_struct_t rt_mhi0;
e2k_rt_mhi_struct_t rt_mhi1;
e2k_rt_mhi_struct_t rt_mhi2;
e2k_rt_mhi_struct_t rt_mhi3;
e2k_rt_mlo_struct_t rt_mlo0;
e2k_rt_mlo_struct_t rt_mlo1;
e2k_rt_mlo_struct_t rt_mlo2;
e2k_rt_mlo_struct_t rt_mlo3;
e2k_rt_pcim_struct_t rt_pcim0;
e2k_rt_pcim_struct_t rt_pcim1;
e2k_rt_pcim_struct_t rt_pcim2;
e2k_rt_pcim_struct_t rt_pcim3;
e2k_rt_pciio_struct_t rt_pciio0;
e2k_rt_pciio_struct_t rt_pciio1;
e2k_rt_pciio_struct_t rt_pciio2;
e2k_rt_pciio_struct_t rt_pciio3;
e2k_rt_pcimp_struct_t rt_pcimp_b0;
e2k_rt_pcimp_struct_t rt_pcimp_b1;
e2k_rt_pcimp_struct_t rt_pcimp_b2;
e2k_rt_pcimp_struct_t rt_pcimp_b3;
e2k_rt_pcimp_struct_t rt_pcimp_e0;
e2k_rt_pcimp_struct_t rt_pcimp_e1;
e2k_rt_pcimp_struct_t rt_pcimp_e2;
e2k_rt_pcimp_struct_t rt_pcimp_e3;
e2k_rt_pcicfgb_struct_t rt_pcicfgb;
uint64_t rt_msi;
uint32_t iommu_ctrl;
uint64_t iommu_ptbar;
uint64_t iommu_dtbar;
uint64_t iommu_err;
uint64_t iommu_err_info;
uint32_t prepic_ctrl2;
uint32_t prepic_err_stat;
uint32_t prepic_err_int;
uint32_t prepic_linp0;
uint32_t prepic_linp1;
uint32_t prepic_linp2;
uint32_t prepic_linp3;
uint32_t prepic_linp4;
uint32_t prepic_linp5;
} SICState;
typedef struct GSIState {
qemu_irq ioapic_irq[IOAPIC_NUM_PINS];
} GSIState;
struct E2KMachineState {
/*< private >*/
MachineClass parent;
/*< public >*/
qemu_irq *pic;
GSIState *gsi_state;
AddressSpace *ioapic_as;
PCIBus *bus;
PCIIOHUBState *iohub;
MemoryRegion sicregion;
struct SICState sicregs;
ram_addr_t above_4g_mem_size;
ram_addr_t below_4g_mem_size;
bootblock_struct_t *bootblock;
};
#define TYPE_E2K_MACHINE MACHINE_TYPE_NAME("e2k")
OBJECT_DECLARE_SIMPLE_TYPE(E2KMachineState, E2K_MACHINE)
void sic_init(E2KMachineState *ms);
int pci_e2k_map_irq(PCIDevice *pci_dev, int irq_num);
#endif /* HW_E2K_H */

33
include/hw/e2k/ioapic.h Normal file
View File

@ -0,0 +1,33 @@
/*
* ioapic.c IOAPIC emulation logic
*
* Copyright (c) 2011 Jan Kiszka, Siemens AG
*
* 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/>.
*/
#ifndef HW_IOAPIC_H
#define HW_IOAPIC_H
#define IOAPIC_NUM_PINS 24
#define IO_APIC_DEFAULT_ADDRESS 0xfec00000
#define IO_APIC_SECONDARY_ADDRESS (IO_APIC_DEFAULT_ADDRESS + 0x10000)
#define IO_APIC_SECONDARY_IRQBASE 24 /* primary 0 -> 23, secondary 24 -> 47 */
#define TYPE_KVM_IOAPIC "kvm-ioapic"
#define TYPE_IOAPIC "ioapic"
void ioapic_eoi_broadcast(int vector);
#endif /* HW_IOAPIC_H */

48
include/hw/e2k/memmap.h Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2021 Alibek Omarov
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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/>.
*/
#ifndef HW_E2K_MEMMAP_H
#define HW_E2K_MEMMAP_H
/* Memory map */
/* may be overriden by VGAMEM, these bytes will be lost */
#define E2K_MLO_BASE 0x0
#define E2K_MLO_SIZE 0x080000000 /* 2 GiB */
#define E2K_PCIMEM_BASE 0x080000000
#define E2K_PCIMEM_SIZE 0x07ec00000 /* 2028 MiB */
/* there goes APIC/EPIC, compatible with x86 */
#define E2K_BIOS_AREA_BASE 0x100000000
#define E2K_BIOS_AREA_SIZE 0x001000000 /* 16 MiB */
#define E2K_IO_AREA_BASE 0x101000000
#define E2K_IO_AREA_SIZE 0x000010000 /* 64 KiB */
#define E2K_SICREGS_BASE 0x110000000
#define E2K_SICREGS_SIZE 0x000100000 /* 1 MiB */
#define E2K_PCICFG_BASE 0x200000000 /* set by SIC_rt_pcicfgb but we hardcode it */
#define E2K_PCICFG_SIZE 0x010000000 /* 256 MiB */
#define E2K_PCIMEMP_BASE 0x210000000 /* Prefetchable MEM */
#define E2K_PCIMEMP_SIZE 0x1f0000000 /* 7936 MiB */
#define E2K_HIMEM_BASE 0x400000000 /* and to the end of address space... */
#endif /* HW_E2K_MEMMAP_H */

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2021 Alibek Omarov
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#ifndef HW_PCI_IOHUB_H
#define HW_PCI_IOHUB_H
#include "hw/pci/pci_bus.h"
#include "qom/object.h"
#define TYPE_IOHUB_PCI_HOST_BRIDGE "iohub-pcihost"
#define TYPE_IOHUB_PCI_BRIDGE "iohub-pcibridge"
#define TYPE_IOHUB_PCI_DEVICE "iohub"
OBJECT_DECLARE_SIMPLE_TYPE(PCIIOHUBState, IOHUB_PCI_DEVICE)
struct PCIIOHUBState {
/*< private >*/
PCIDevice parent_obj;
/*< public >*/
MemoryRegion *system_memory;
MemoryRegion *pci_address_space;
qemu_irq *pic;
};
PCIBus *iohub_init(const char *host_type, const char *pci_type,
PCIIOHUBState **piohub_state,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
qemu_irq *pic);
PCIBus *find_iohub(void);
#endif

View File

@ -23,6 +23,7 @@ enum {
QEMU_ARCH_RISCV = (1 << 19),
QEMU_ARCH_RX = (1 << 20),
QEMU_ARCH_AVR = (1 << 21),
QEMU_ARCH_E2K = (1 << 22),
QEMU_ARCH_NONE = (1 << 31),
};

View File

@ -276,7 +276,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

189
linux-user/e2k/cpu_loop.c Normal file
View File

@ -0,0 +1,189 @@
/*
* 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"
#include "target_elf.h"
static void gen_signal(CPUE2KState *env, int signo, int code, abi_ulong addr)
{
target_siginfo_t info = {
.si_signo = signo,
.si_code = code,
._sifields._sigfault._addr = addr,
// TODO: ._sifields._sigfault._trapno = trapnr
};
queue_signal(env, signo, QEMU_SI_FAULT, &info);
}
static void stack_expand(CPUE2KState *env, E2KPsp *s)
{
abi_ulong new_size, new_size_tag;
abi_long new_base, new_base_tag = 0;
new_size = s->size * 2;
new_size_tag = new_size / 8;
new_base = target_mremap(s->base, s->size, new_size, MREMAP_MAYMOVE, 0);
if (s->base_tag) {
new_base_tag = target_mremap(s->base_tag, s->size / 8, new_size_tag,
MREMAP_MAYMOVE, 0);
}
if (new_base == -1 || new_base_tag == -1) {
gen_signal(env, TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->ip);
return;
}
s->base = new_base;
s->base_tag = new_base_tag;
s->size = new_size;
}
void cpu_loop(CPUE2KState *env)
{
CPUState *cs = env_cpu(env);
int trapnr;
while (1) {
cpu_exec_start(cs);
trapnr = cpu_exec(cs);
cpu_exec_end(cs);
process_queued_cpu_work(cs);
switch (trapnr) {
case EXCP_SYSCALL: {
abi_ullong args[E2K_SYSCALL_MAX_ARGS] = { 0 };
int i, psize = MIN(E2K_SYSCALL_MAX_ARGS, env->wd.size);
abi_ulong ret;
// TODO: check what happens if env->wd.size is zero
for (i = 0; i < psize; i++) {
args[i] = env->regs[i].lo;
}
ret = do_syscall(env, args[0], args[1], args[2], args[3],
args[4], args[5], args[6], args[7], args[8]);
if (ret == -TARGET_ERESTARTSYS) {
/* do not set sysret address and syscall will be restarted */
} else if (ret != -TARGET_QEMU_ESIGRETURN && env->wd.psize > 0) {
memset(env->tags, E2K_TAG_NON_NUMBER64,
psize * sizeof(env->tags[0]));
env->regs[0].lo = ret;
env->tags[0] = E2K_TAG_NUMBER64;
env->ip = E2K_SYSRET_ADDR;
}
break;
}
case EXCP_ILLEGAL_OPCODE:
case EXCP_PRIV_ACTION:
gen_signal(env, TARGET_SIGILL, TARGET_ILL_ILLOPC, env->ip);
break;
case EXCP_ILLEGAL_OPERAND:
gen_signal(env, TARGET_SIGILL, TARGET_ILL_ILLOPN, env->ip);
break;
case EXCP_CHAIN_STACK_BOUNDS:
stack_expand(env, &env->pcsp);
break;
case EXCP_PROC_STACK_BOUNDS:
stack_expand(env, &env->psp);
break;
case EXCP_WINDOW_BOUNDS:
case EXCP_ARRAY_BOUNDS:
case EXCP_DATA_PAGE:
gen_signal(env, TARGET_SIGSEGV, TARGET_SEGV_MAPERR, env->ip);
break;
case EXCP_DIV:
gen_signal(env, TARGET_SIGFPE, 0, env->ip);
break;
/* QEMU common interrupts */
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
case EXCP_DEBUG:
gen_signal(env, TARGET_SIGTRAP, TARGET_TRAP_BRKPT, 0);
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)
{
CPUState *cpu = env_cpu(env);
TaskState *ts = cpu->opaque;
struct image_info *info = ts->info;
uint32_t eflags = info->elf_flags;
env->psr = PSR_NMIE | PSR_SGE | PSR_IE;
env->upsr = UPSR_NMIE | UPSR_IE | UPSR_FE;
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;
env->elf_flags = info->elf_flags;
// TODO: set a chain info to return to kernel
if (eflags & E2K_ELF_PM) {
fprintf(stderr, "Protected mode is unsupported\n");
exit(EXIT_FAILURE);
}
if (eflags & E2K_ELF_X86APP) {
fprintf(stderr, "x86 recompiler is unsupported\n");
exit(EXIT_FAILURE);
}
}
const char *cpu_get_model(uint32_t eflags)
{
const char *name = "any";
uint32_t machine = E2K_ELF_MACH(eflags);
/* TODO: can't check for EM_E2K_OLD flags because e_machine isn't saved anywhere... */
switch(machine) {
case E2K_MACH_EV2: name = "e2c+"; break;
case E2K_MACH_EV3: name = "e2s"; break;
case E2K_MACH_1CPLUS:
case E2K_MACH_8C:
case E2K_MACH_EV4: name = "e8c"; break;
case E2K_MACH_EV5: name = "e8c2"; break;
case E2K_MACH_EV6: name = "e16c"; break;
}
return name;
}

361
linux-user/e2k/signal.c Normal file
View File

@ -0,0 +1,361 @@
/*
* Emulation of Linux signals
*
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2020 Alibek Omarov
* Copyright (c) 2021 Denis Drakhnya
*
* 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"
#include "target/e2k/helper-tcg.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_ullong cr0_lo;
abi_ullong cr0_hi;
abi_ullong cr1_lo;
abi_ullong cr1_hi;
abi_ullong sbr; /* 21 Stack base register: top of */
/* local data (user) stack */
abi_ullong usd_lo; /* 22 Local data (user) stack */
abi_ullong usd_hi; /* 23 descriptor: base & size */
abi_ullong psp_lo; /* 24 Procedure stack pointer: */
abi_ullong psp_hi; /* 25 base & index & size */
abi_ullong pcsp_lo; /* 26 Procedure chain stack */
abi_ullong pcsp_hi; /* 27 pointer: base & index & size */
/* additional part (for binary compiler) */
abi_ullong rpr_hi;
abi_ullong rpr_lo;
abi_ullong nr_TIRs;
abi_ullong tir_lo[TIR_NUM];
abi_ullong tir_hi[TIR_NUM];
abi_ullong trap_cell_addr[MAX_TC_SIZE];
abi_ullong trap_cell_val[MAX_TC_SIZE];
uint8_t trap_cell_tag[MAX_TC_SIZE];
abi_ullong trap_cell_info[MAX_TC_SIZE];
abi_ullong dam[DAM_ENTRIES_NUM];
abi_ullong sbbp[SBBP_ENTRIES_NUM];
abi_ullong mlt[MLT_NUM];
abi_ullong upsr;
};
/*
* This structure is used for compatibility
* All new fields must be added in this structure
*/
struct target_extra_ucontext {
abi_int sizeof_extra_uc; /* size of used fields(in bytes) */
abi_int curr_cnt; /* current index into trap_celler */
abi_int tc_count; /* trap_celler records count */
/*
* For getcontext()
*/
abi_int fpcr;
abi_int fpsr;
abi_int pfpfr;
abi_ullong ctpr1;
abi_ullong ctpr2;
abi_ullong ctpr3;
abi_int sc_need_rstrt;
};
struct target_ucontext {
abi_ulong uc_flags;
struct target_ucontext *uc_link;
target_stack_t uc_stack;
struct target_sigcontext uc_mcontext;
union {
target_sigset_t uc_sigmask; /* mask last for extensibility */
abi_ullong pad[16];
};
struct target_extra_ucontext uc_extra; /* for compatibility */
};
struct target_sigframe {
target_siginfo_t info;
union {
struct target_ucontext uc;
// TODO: ucontext_prot
};
/* FIXME: move this data to TaskState? */
E2KAauState aau;
uint64_t lsr;
uint64_t lsr_lcnt;
uint32_t ilcr;
uint64_t ilcr_lcnt;
// FIXME: according to ABI only 16-31 must be saved
E2KReg gregs[16];
uint8_t gtags[16];
};
#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
static abi_long setup_sigcontext(CPUE2KState *env,
struct target_sigcontext *sc, struct target_extra_ucontext *extra)
{
E2KCrs crs;
int i, ret;
// TODO: save binary compiler state (uspr, rpr, MLT)
__put_user(env->upsr, &sc->upsr);
ret = e2k_copy_from_user_crs(&crs, env->pcsp.base + env->pcsp.index);
if (ret) {
return ret;
}
__put_user(crs.cr0_lo, &sc->cr0_lo);
__put_user(crs.cr0_hi, &sc->cr0_hi);
__put_user(crs.cr1.lo, &sc->cr1_lo);
__put_user(crs.cr1.hi, &sc->cr1_hi);
__put_user(env->sbr, &sc->sbr);
__put_user(env->usd.lo, &sc->usd_lo);
__put_user(env->usd.hi, &sc->usd_hi);
__put_user(env->psp.lo, &sc->psp_lo);
__put_user(env->psp.hi, &sc->psp_hi);
__put_user(env->pcsp.lo, &sc->pcsp_lo);
__put_user(env->pcsp.hi, &sc->pcsp_hi);
// TODO: save trap state
__put_user(0, &sc->nr_TIRs);
__put_user(0, &sc->tir_lo[0]);
__put_user(0, &sc->tir_hi[0]);
__put_user(-1, &extra->curr_cnt);
__put_user(0, &extra->tc_count);
__put_user(sizeof(struct target_extra_ucontext) - sizeof(abi_int),
&extra->sizeof_extra_uc);
__put_user(env->fpcr.raw, &extra->fpcr);
__put_user(env->fpsr.raw, &extra->fpsr);
__put_user(env->pfpfr.raw, &extra->pfpfr);
__put_user(env->ctprs[0].raw, &extra->ctpr1);
__put_user(env->ctprs[1].raw, &extra->ctpr2);
__put_user(env->ctprs[2].raw, &extra->ctpr3);
for (i = 0; i < DAM_ENTRIES_NUM; i++) {
__put_user(env->dam[i].raw, &sc->dam[i]);
}
return 0;
}
static abi_long setup_ucontext(struct target_ucontext *uc, CPUE2KState *env)
{
__put_user(0, &uc->uc_flags);
__put_user(0, &uc->uc_link);
target_save_altstack(&uc->uc_stack, env);
return setup_sigcontext(env, &uc->uc_mcontext, &uc->uc_extra);
}
static abi_ulong get_sigframe(struct target_sigaction *ka, CPUE2KState *env,
size_t frame_size)
{
abi_ulong sp;
sp = target_sigsp(get_sp_from_cpustate(env), ka);
sp = (sp - frame_size) & ~15;
return sp;
}
static void target_setup_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info, target_sigset_t *set, CPUE2KState *env)
{
abi_ulong frame_addr;
struct target_sigframe *frame;
if (env->is_bp) {
/* numas13 FIXME: I am not sure that it is a good solution but
* the way we handle breakpoints requires these steps.
* Maybe we need to create more fake kernel frames for breakpoints? */
e2k_proc_return(env, true);
}
/* save current frame */
e2k_proc_call(env, env->wd.size, env->ip, false);
frame_addr = get_sigframe(ka, env, sizeof(*frame));
trace_user_setup_rt_frame(env, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
force_sigsegv(sig);
}
if (setup_ucontext(&frame->uc, env)) {
goto fail;
}
copy_to_user(frame_addr + offsetof(struct target_sigframe, uc.uc_sigmask),
set, sizeof(*set));
copy_to_user(frame_addr + offsetof(struct target_sigframe, aau),
&env->aau, sizeof(env->aau));
__put_user(env_lsr_get(env), &frame->lsr);
__put_user(env->lsr_lcnt, &frame->lsr_lcnt);
__put_user(env->ilcr, &frame->ilcr);
__put_user(env->ilcr_lcnt, &frame->ilcr_lcnt);
copy_to_user(frame_addr + offsetof(struct target_sigframe, gregs),
&env->regs[E2K_NR_COUNT + 16], 16 * sizeof(E2KReg));
copy_to_user(frame_addr + offsetof(struct target_sigframe, gtags),
&env->tags[E2K_NR_COUNT + 16], 16);
if (ka->sa_flags & TARGET_SA_RESTORER) {
// TODO: sa_restorer?
qemu_log_mask(LOG_UNIMP, "target_setup_frame sa_restorer +\n");
} else {
// TODO: ignore?
}
/* fake kernel frame */
env->wd.size = 0;
env->wd.psize = 0;
env->usd.size = env->sbr - frame_addr;
env->usd.base = frame_addr;
e2k_proc_call(env, 0, E2K_SIGRET_ADDR, false);
env->ip = ka->_sa_handler;
env->regs[0].lo = sig;
env->tags[0] = E2K_TAG_NUMBER64;
env->wd.size = 8;
if (info && (ka->sa_flags & TARGET_SA_SIGINFO)) {
tswap_siginfo(&frame->info, info);
env->regs[1].lo = frame_addr + offsetof(struct target_sigframe, info);
env->tags[1] = E2K_TAG_NUMBER64;
env->regs[2].lo = frame_addr + offsetof(struct target_sigframe, uc);
env->tags[2] = E2K_TAG_NUMBER64;
}
unlock_user_struct(frame, frame_addr, 1);
return;
fail:
unlock_user_struct(frame, frame_addr, 1);
force_sigsegv(sig);
}
static abi_long target_restore_sigframe(CPUE2KState *env,
struct target_sigframe *frame)
{
target_ulong crs_addr = env->pcsp.base + env->pcsp.index;
E2KCrs crs, *p;
if (!lock_user_struct(VERIFY_WRITE, p, crs_addr, 0)) {
return -TARGET_EFAULT;
}
__get_user(crs.cr0_hi, &frame->uc.uc_mcontext.cr0_hi);
__put_user(crs.cr0_hi, &p->cr0_hi);
unlock_user_struct(p, crs_addr, 1);
__get_user(env->ctprs[0].raw, &frame->uc.uc_extra.ctpr1);
__get_user(env->ctprs[1].raw, &frame->uc.uc_extra.ctpr2);
__get_user(env->ctprs[2].raw, &frame->uc.uc_extra.ctpr3);
return 0;
}
void setup_frame(int sig, struct target_sigaction *ka,
target_sigset_t *set, CPUE2KState *env)
{
target_setup_frame(sig, ka, 0, set, env);
}
void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info, target_sigset_t *set, CPUE2KState *env)
{
target_setup_frame(sig, ka, info, set, env);
}
long do_sigreturn(CPUE2KState *env)
{
return do_rt_sigreturn(env);
}
long do_rt_sigreturn(CPUE2KState *env)
{
abi_ulong frame_addr;
struct target_sigframe *frame;
sigset_t set;
/* restore fake kernel frame */
e2k_proc_return(env, false);
frame_addr = env->usd.base;
trace_user_do_rt_sigreturn(env, frame_addr);
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
goto badframe;
}
target_to_host_sigset(&set, &frame->uc.uc_sigmask);
set_sigmask(&set);
if (target_restore_sigframe(env, frame)) {
goto badframe;
}
copy_from_user(&env->aau, frame_addr
+ offsetof(struct target_sigframe, aau), sizeof(env->aau));
__get_user(env->lsr, &frame->lsr);
__get_user(env->lsr_lcnt, &frame->lsr_lcnt);
__get_user(env->ilcr, &frame->ilcr);
__get_user(env->ilcr_lcnt, &frame->ilcr_lcnt);
copy_from_user(&env->regs[E2K_NR_COUNT + 16], frame_addr
+ offsetof(struct target_sigframe, gregs), 16 * sizeof(E2KReg));
copy_from_user(&env->tags[E2K_NR_COUNT + 16], frame_addr
+ offsetof(struct target_sigframe, gtags), 16);
if (do_sigaltstack(frame_addr +
offsetof(struct target_sigframe, uc.uc_stack),
0, env) == -EFAULT)
{
goto badframe;
}
/* restore user */
e2k_proc_return(env, false);
unlock_user_struct(frame, frame_addr, 0);
return -TARGET_QEMU_ESIGRETURN;
badframe:
unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
return -TARGET_QEMU_ESIGRETURN;
}
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;
}

View File

@ -0,0 +1 @@
#include "../generic/sockbits.h"

457
linux-user/e2k/syscall_nr.h Normal file
View File

@ -0,0 +1,457 @@
/*
* 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_pread64 180
#define TARGET_NR_pwrite64 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_renameat2 384
#define TARGET_NR_getrandom 385
#define TARGET_NR_memfd_create 386
#define TARGET_NR_bpf 387
#define TARGET_NR_execveat 388
#define TARGET_NR_userfaultfd 389
#define TARGET_NR_membarrier 390
#define TARGET_NR_mlock2 391
#define TARGET_NR_seccomp 392
#define TARGET_NR_shutdown 393
#define TARGET_NR_copy_file_range 394
#define TARGET_NR_preadv2 395
#define TARGET_NR_pwritev2 396
#define TARGET_NR_pkey_mprotect 397
#define TARGET_NR_pkey_alloc 398
#define TARGET_NR_pkey_free 399
#define TARGET_NR_name_to_handle_at 400
#define TARGET_NR_open_by_handle_at 401
#define TARGET_NR_statx 402
/* added for compatibility with x86_64 */
#define TARGET_NR_socket 403
#define TARGET_NR_connect 404
#define TARGET_NR_accept 405
#define TARGET_NR_sendto 406
#define TARGET_NR_recvfrom 407
#define TARGET_NR_sendmsg 408
#define TARGET_NR_recvmsg 409
#define TARGET_NR_bind 410
#define TARGET_NR_listen 411
#define TARGET_NR_getsockname 412
#define TARGET_NR_getpeername 413
#define TARGET_NR_socketpair 414
#define TARGET_NR_setsockopt 415
#define TARGET_NR_getsockopt 416
/* free (unused) entries - reserve 417 - 418 */
/* TODO: #define TARGET_NR_arch_prctl 419 */
/* added for combability of protected system calls v1-v5 & v6 */
#define TARGET_NR_newuselib 420
#define TARGET_NR_rt_sigaction_ex 421
/* protected Mode specific memory allocation syscall number */
#define TARGET_NR_get_mem 422
#define TARGET_NR_free_mem 423
/* protected mode specific clean memory from old invalid descriptors */
#define TARGET_NR_clean_descriptors 424
/* protected mode specific unloading module from memory */
#define TARGET_NR_unuselib 425
#define TARGET_NR_clone3 426
#define TARGET_NR_fsopen 427
#define TARGET_NR_fsconfig 428
#define TARGET_NR_fsmount 429
#define TARGET_NR_fspick 430
#define TARGET_syscalls 431
#endif /* E2K_SYSCALL_NR_H */

View File

@ -0,0 +1,87 @@
#ifndef E2K_TARGET_CPU_H
#define E2K_TARGET_CPU_H
#include "qemu/log.h"
abi_long e2k_copy_from_user_crs(E2KCrs *crs, abi_ulong target_crs_addr);
abi_long e2k_copy_to_user_crs(abi_ulong target_crs_addr, E2KCrs *crs);
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 = env->sbr = newsp & ~0xf;
env->usd.read = 1;
env->usd.write = 1;
}
if (flags & CLONE_VM) {
E2KPsp pcs = { 0 };
E2KPsp ps = { 0 };
E2KCrs crs = { 0 };
uint64_t *ps_old, *ps_new;
size_t frame_size;
target_ulong pcsp = env->pcsp.base + env->pcsp.index;
target_ulong ps_base = env->psp.base + env->psp.index;
int i;
e2k_psp_new(&pcs, E2K_DEFAULT_PCS_SIZE, false);
e2k_psp_new(&ps, E2K_DEFAULT_PS_SIZE, true);
// TODO: size checks and a way to report errors
// TODO: set a chain info to return to kernel
pcs.index += sizeof(E2KCrs);
if (e2k_copy_from_user_crs(&crs, pcsp)
|| e2k_copy_to_user_crs(pcs.base + pcs.index, &crs))
{
qemu_log("qemu-e2k internal error: failed to copy parent frame\n");
env->ip = 0;
return;
}
frame_size = crs.cr1.wbs * (crs.cr1.wfx || E2K_FORCE_FX ? 32 : 16);
ps_base -= frame_size;
ps.index += frame_size;
ps_old = lock_user(VERIFY_READ, ps_base, frame_size, 1);
ps_new = lock_user(VERIFY_WRITE, ps.base, frame_size, 0);
for (i = 0; i < frame_size / 8; i++) {
uint64_t tmp;
__get_user(tmp, &ps_old[i]);
__put_user(tmp, &ps_new[i]);
}
unlock_user_struct(ps_new, ps.base, 1);
unlock_user_struct(ps_old, ps_base, 0);
env->ip = E2K_SYSRET_ADDR;
env->pcsp = pcs;
env->psp = ps;
env->regs[0].lo = 0;
env->tags[0] = 0;
}
}
static inline void cpu_clone_regs_parent(CPUE2KState *env, unsigned flags)
{
}
static inline void cpu_set_tls(CPUE2KState *env, target_ulong newtls)
{
env->regs[E2K_TLS_REG].lo = newtls;
}
static inline target_ulong cpu_get_tls(CPUE2KState *env)
{
return env->regs[E2K_TLS_REG].lo;
}
static inline abi_ulong get_sp_from_cpustate(CPUE2KState *env)
{
return env->usd.base;
}
#endif /* E2K_TARGET_CPU_H */

View File

@ -0,0 +1,27 @@
#ifndef E2K_TARGET_ELF_H
#define E2K_TARGET_ELF_H
#define E2K_ELF_IPD_MASK ((1U << 1)|(1U << 0))
#define E2K_ELF_X86APP (1U << 2)
#define E2K_ELF_4MB_PAGES (1U << 3)
#define E2K_ELF_INCOMPAT (1U << 4)
#define E2K_ELF_PM (1U << 5)
#define E2K_ELF_OLD_MACH(x) (((x) >> 28) & 7)
#define E2K_ELF_MACH(x) (((x) >> 24) & 255)
#define E2K_MACH_BASE 0
#define E2K_MACH_EV1 1
#define E2K_MACH_EV2 2
#define E2K_MACH_EV3 3
#define E2K_MACH_EV4 4
#define E2K_MACH_EV5 5
#define E2K_MACH_EV6 6
/* elbrus-v4 based processors */
#define E2K_MACH_8C 19
#define E2K_MACH_1CPLUS 20
const char *cpu_get_model(uint32_t eflags);
#endif /* E2K_TARGET_ELF_H */

View File

@ -0,0 +1,7 @@
#ifndef E2K_TARGET_ERRNO_DEFS_H
#define E2K_TARGET_ERRNO_DEFS_H
/* Target uses generic errno */
#include "../generic/target_errno_defs.h"
#endif

View File

@ -0,0 +1,4 @@
#ifndef E2K_TARGET_FCNTL_H
#define E2K_TARGET_FCNTL_H
#include "../generic/fcntl.h"
#endif

View File

@ -0,0 +1,26 @@
#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
#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 */

View File

@ -0,0 +1,41 @@
#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;
};
struct target_jmp_info {
abi_ullong sigmask;
abi_ullong cr0hi;
abi_ullong cr1lo;
abi_ullong pcsplo;
abi_ullong pcsphi;
abi_uint pcshtp;
abi_uint br;
abi_ullong usdlo;
abi_ullong wd;
abi_ullong reserv1;
};
#endif

View File

@ -0,0 +1,90 @@
#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 */
#define E2K_DEFAULT_PCS_SIZE (TARGET_PAGE_SIZE)
#define E2K_DEFAULT_PS_SIZE (TARGET_PAGE_SIZE * 4)
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
E2KPsp pcsp;
E2KPsp 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];
};
// FIXME: Is it right place for these constants?
#if TARGET_LONG_BITS == 64
#define TARGET_PAGE_OFFSET 0x0000d00000000000UL
#define TARGET_TASK_SIZE TARGET_PAGE_OFFSET
#else
#define TARGET_TASK_SIZE 0xe0000000UL
#endif
/* modes for sys_access_hw_stacks */
enum {
READ_CHAIN_STACK,
READ_PROCEDURE_STACK,
WRITE_PROCEDURE_STACK,
GET_CHAIN_STACK_OFFSET,
GET_CHAIN_STACK_SIZE,
GET_PROCEDURE_STACK_SIZE,
READ_CHAIN_STACK_EX,
READ_PROCEDURE_STACK_EX,
WRITE_PROCEDURE_STACK_EX,
WRITE_CHAIN_STACK_EX,
};
#endif /* E2K_TARGET_SYSCALL_H */

View File

@ -0,0 +1,6 @@
#ifndef _E2K_TERMBITS_H_
#define _E2K_TERMBITS_H_
#include "../generic/termbits.h"
#endif /* _E2K_TERMBITS_H_ */

View File

@ -1556,6 +1556,73 @@ static inline void init_thread(struct target_pt_regs *regs,
#endif /* TARGET_HEXAGON */
#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 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;
}
void e2k_psp_new(E2KPsp *psp, unsigned int size, bool tags)
{
psp->is_readable = true;
psp->is_writable = true;
psp->index = 0;
psp->size = size;
psp->base = e2k_mmap(size);
psp->base_tag = tags ? e2k_mmap(size / 8) : 0;
}
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;
e2k_psp_new(&regs->pcsp, E2K_DEFAULT_PCS_SIZE, false);
e2k_psp_new(&regs->psp, E2K_DEFAULT_PS_SIZE, true);
}
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

View File

@ -1411,6 +1411,22 @@ UNUSED static struct enums itimer_types[] = {
ENUM_END,
};
#ifdef TARGET_E2K
UNUSED static struct enums access_hw_stacks_reqs[] = {
ENUM_GENERIC(READ_CHAIN_STACK),
ENUM_GENERIC(READ_PROCEDURE_STACK),
ENUM_GENERIC(WRITE_PROCEDURE_STACK),
ENUM_GENERIC(GET_CHAIN_STACK_OFFSET),
ENUM_GENERIC(GET_CHAIN_STACK_SIZE),
ENUM_GENERIC(GET_PROCEDURE_STACK_SIZE),
ENUM_GENERIC(READ_CHAIN_STACK_EX),
ENUM_GENERIC(READ_PROCEDURE_STACK_EX),
ENUM_GENERIC(WRITE_PROCEDURE_STACK_EX),
ENUM_GENERIC(WRITE_CHAIN_STACK_EX),
ENUM_END,
};
#endif
/*
* print_xxx utility functions. These are used to print syscall
* parameters in certain format. All of these have parameter
@ -3758,6 +3774,22 @@ print_ioctl(void *cpu_env, const struct syscallname *name,
}
#endif
#ifdef TARGET_NR_access_hw_stacks
static void
print_access_hw_stacks(void *cpu_env, const struct syscallname *name,
abi_long arg0, abi_long arg1, abi_long arg2,
abi_long arg3, abi_long arg4, abi_long arg5)
{
print_syscall_prologue(name);
print_enums(access_hw_stacks_reqs, arg0, 0);
print_pointer(arg1, 0);
print_pointer(arg2, 0);
print_raw_param("%d", arg3, 0);
print_pointer(arg4, 1);
print_syscall_epilogue(name);
}
#endif
/*
* An array of all of the syscalls we know about
*/

View File

@ -126,6 +126,19 @@
#ifdef TARGET_NR_dup3
{ TARGET_NR_dup3, "dup3" , "%s(%d,%d,%d)", NULL, NULL },
#endif
#ifdef TARGET_NR_e2k_longjmp2
{ TARGET_NR_e2k_longjmp2, "e2k_longjmp2", "%s(%p, %d)", NULL, NULL },
#endif
#ifdef TARGET_NR_access_hw_stacks
{ TARGET_NR_access_hw_stacks, "access_hw_stacks", NULL,
print_access_hw_stacks, NULL },
#endif
#ifdef TARGET_NR_set_backtrace
{ TARGET_NR_set_backtrace, "set_backtrace", "%s(%p,%lu,%lu,%lu)", NULL, NULL },
#endif
#ifdef TARGET_NR_get_backtrace
{ TARGET_NR_get_backtrace, "get_backtrace", "%s(%p,%lu,%lu,%lu)", NULL, NULL },
#endif
#ifdef TARGET_NR_epoll_create
{ TARGET_NR_epoll_create, "epoll_create", "%s(%d)", NULL, NULL },
#endif

View File

@ -6749,6 +6749,526 @@ static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
return 0;
}
#ifdef TARGET_E2K
static inline abi_long copy_from_user_jmp_info(struct target_jmp_info *ji,
abi_ulong target_jmp_info_addr)
{
struct target_jmp_info *target_ji;
if (!lock_user_struct(VERIFY_READ, target_ji, target_jmp_info_addr, 1)) {
return -TARGET_EFAULT;
}
__get_user(ji->sigmask, &target_ji->sigmask);
__get_user(ji->cr0hi, &target_ji->cr0hi);
__get_user(ji->cr1lo, &target_ji->cr1lo);
__get_user(ji->pcsplo, &target_ji->pcsplo);
__get_user(ji->pcsphi, &target_ji->pcsphi);
__get_user(ji->pcshtp, &target_ji->pcshtp);
__get_user(ji->br, &target_ji->br);
__get_user(ji->usdlo, &target_ji->usdlo);
__get_user(ji->wd, &target_ji->wd);
__get_user(ji->reserv1, &target_ji->reserv1);
unlock_user_struct(target_ji, target_jmp_info_addr, 0);
if (ji->cr0hi > TARGET_TASK_SIZE) {
return -TARGET_EFAULT;
}
return 0;
}
abi_long e2k_copy_from_user_crs(E2KCrs *crs, abi_ulong target_crs_addr)
{
E2KCrs *target_crs;
if (!lock_user_struct(VERIFY_READ, target_crs, target_crs_addr, 1)) {
return -TARGET_EFAULT;
}
__get_user(crs->cr0_lo, &target_crs->cr0_lo);
__get_user(crs->cr0_hi, &target_crs->cr0_hi);
__get_user(crs->cr1.lo, &target_crs->cr1.lo);
__get_user(crs->cr1.hi, &target_crs->cr1.hi);
unlock_user_struct(target_crs, target_crs_addr, 0);
return 0;
}
abi_long e2k_copy_to_user_crs(abi_ulong target_crs_addr, E2KCrs *crs)
{
E2KCrs *target_crs;
if (!lock_user_struct(VERIFY_WRITE, target_crs, target_crs_addr, 0)) {
return -TARGET_EFAULT;
}
__put_user(crs->cr0_lo, &target_crs->cr0_lo);
__put_user(crs->cr0_hi, &target_crs->cr0_hi);
__put_user(crs->cr1.lo, &target_crs->cr1.lo);
__put_user(crs->cr1.hi, &target_crs->cr1.hi);
unlock_user_struct(target_crs, target_crs_addr, 1);
return 0;
}
static abi_long do_e2k_longjmp2(CPUE2KState *env, struct target_jmp_info *jmp_info)
{
E2KPsp jmp_pcsp;
E2KCrs crs;
int level; /* how many CRs need to restore */
int ps_index = env->psp.index;
int psize = env->wd.psize;
int ret, i;
target_ulong pcsp = env->pcsp.base + env->pcsp.index;
jmp_pcsp.lo = jmp_info->pcsplo;
jmp_pcsp.hi = jmp_info->pcsphi;
level = (env->pcsp.index - jmp_pcsp.index) / CRS_SIZE;
for (i = 0; i < level; i++) {
ret = e2k_copy_from_user_crs(&crs, pcsp);
if (ret) {
return ret;
}
psize = crs.cr1.wpsz * 2;
ps_index -= crs.cr1.wbs * E2K_REG_LEN *
(crs.cr1.wfx || E2K_FORCE_FX ? 4 : 2);
pcsp -= CRS_SIZE;
}
ret = e2k_copy_from_user_crs(&crs, pcsp);
if (ret) {
return ret;
}
crs.cr0_hi = jmp_info->cr0hi;
crs.cr1.lo = jmp_info->cr1lo;
crs.cr1.br = jmp_info->br;
crs.cr1.ussz = (env->sbr - extract64(jmp_info->usdlo, 0, 48)) >> 4;
ret = e2k_copy_to_user_crs(pcsp, &crs);
if (ret) {
return ret;
}
env->pcsp.index = pcsp - env->pcsp.base;
env->psp.index = ps_index;
env->wd.psize = psize;
return 0;
}
static abi_long copy_current_chain_stack(abi_ulong dst, abi_ulong src,
abi_ulong size)
{
E2KCrs *from, *to;
abi_long ret = 0;
int i;
if (!QEMU_IS_ALIGNED(src, sizeof(*from)) ||
!QEMU_IS_ALIGNED(size, sizeof(*from)))
{
return -TARGET_EINVAL;
}
from = lock_user(VERIFY_READ, src, size, 1);
to = lock_user(VERIFY_WRITE, dst, size, 0);
if (!to || !from) {
ret = -TARGET_EFAULT;
goto exit;
}
for (i = 0; i < size; i += sizeof(E2KCrs), to++, from++) {
E2KCrs crs = *from;
target_ulong ip;
memset(to, 0, sizeof(*to));
to->cr0_lo = from->cr0_lo;
ip = crs.cr0_hi & ~7;
if (ip < TARGET_TASK_SIZE) {
to->cr0_hi = ip;
to->cr1.ussz = from->cr1.ussz;
}
// FIXME: check what exactly needs to be copied
to->cr1 = from->cr1;
}
exit:
unlock_user(from, src, size);
unlock_user(to, dst, size);
return ret;
}
static abi_long copy_procedure_stack(CPUE2KState *env, abi_ulong dst,
abi_ulong dst_tag, abi_ulong src, abi_ulong size)
{
abi_ullong *from, *to;
uint8_t *to_tag = NULL;
abi_long ret = 0;
from = lock_user(VERIFY_READ, src, size, 1);
to = lock_user(VERIFY_WRITE, dst, size, 0);
if (!to || !from) {
ret = -TARGET_EFAULT;
goto exit;
}
if (dst_tag) {
to_tag = lock_user(VERIFY_WRITE, dst_tag, size / 8, 0);
if (!to_tag) {
ret = -TARGET_EFAULT;
goto exit;
}
// TODO: what to do with tags?
memset(to_tag, 0, size / 8);
}
/* v5+ has different stack layout and we need to shuffle registers
* for backward compatibility. */
if (env->version >= 5) {
int i, j;
bool to_ps = dst >= env->psp.base
&& dst < (env->psp.base + env->psp.size);
i = ((to_ps ? dst : src) - env->psp.base) / sizeof(abi_ullong);
if (to_ps) {
for (j = 0; j < size / sizeof(abi_ullong); j++, i++) {
to[j + ((i & 3) == 1 ? 1 : ((i & 3) == 2 ? -1 : 0))] = from[j];
}
} else {
for (j = 0; j < size / sizeof(abi_ullong); j++, i++) {
to[j] = from[j + ((i & 3) == 1 ? 1 : ((i & 3) == 2 ? -1 : 0))];
}
}
} else {
memcpy(to, from, size);
}
exit:
unlock_user(from, src, size);
unlock_user(to_tag, dst_tag, size / 8);
unlock_user(to, dst, size);
return ret;
}
static abi_long do_e2k_access_hw_stacks(CPUState *cpu, abi_ulong arg2,
abi_ulong arg3, abi_ulong arg4, abi_ulong arg5, abi_ulong arg6)
{
E2KCPU *e2k_cpu = E2K_CPU(cpu);
CPUE2KState *env = &e2k_cpu->env;
abi_ulong mode = arg2;
abi_ulong frame_addr = arg3; // __user (abi_ullong *)
abi_ulong buf_addr = arg4; // __user (char *)
abi_ulong buf_size = arg5;
abi_ulong size_addr = arg6; // __user (void *)
int ret = 0;
switch (mode) {
case GET_PROCEDURE_STACK_SIZE:
ret = put_user(env->psp.index, size_addr, target_ulong);
break;
case GET_CHAIN_STACK_SIZE:
ret = put_user(env->pcsp.index + sizeof(E2KCrs), size_addr, target_ulong);
break;
case GET_CHAIN_STACK_OFFSET:
{
abi_ullong frame, pcs_top;
ret = get_user(frame, frame_addr, abi_ullong);
if (ret) {
return ret;
}
pcs_top = env->pcsp.base + env->pcsp.size;
if (env->pcsp.base > frame || pcs_top <= frame) {
return -TARGET_ESRCH;
}
ret = put_user(frame - env->pcsp.base, size_addr, target_ulong);
break;
}
case READ_CHAIN_STACK:
{
abi_ullong frame, pcs_used_top;
abi_ulong used_size;
ret = get_user(frame, frame_addr, abi_ullong);
if (ret) {
return ret;
}
pcs_used_top = env->pcsp.base + env->pcsp.index;
if (frame < env->pcsp.base || frame > pcs_used_top) {
return -TARGET_EINVAL;
}
used_size = frame - env->pcsp.base;
if (size_addr) {
ret = put_user(used_size, size_addr, target_ulong);
if (ret) {
return ret;
}
}
if (used_size > buf_size) {
return -TARGET_ENOMEM;
}
ret = copy_current_chain_stack(buf_addr, env->pcsp.base,
used_size);
break;
}
case READ_CHAIN_STACK_EX:
case WRITE_CHAIN_STACK_EX:
{
abi_ullong frame;
abi_ulong dst, src;
ret = get_user(frame, frame_addr, abi_ullong);
if (ret) {
return ret;
}
if ((env->pcsp.index + sizeof(E2KCrs)) < (frame + buf_size)) {
return -TARGET_EFAULT;
}
if (mode == READ_CHAIN_STACK_EX) {
dst = buf_addr;
src = env->pcsp.base + frame;
} else {
dst = env->pcsp.base + frame;
src = buf_addr;
}
ret = copy_current_chain_stack(dst, src, buf_size);
break;
}
case READ_PROCEDURE_STACK:
case WRITE_PROCEDURE_STACK:
{
abi_ullong offset, ps_used_top;
abi_ulong used_size, dst, dst_tag, src;
ret = get_user(offset, frame_addr, abi_ullong);
if (ret) {
return ret;
}
ps_used_top = env->psp.base + env->psp.index;
if (offset < env->psp.base || offset > ps_used_top) {
return -TARGET_EINVAL;
}
used_size = offset - env->psp.base;
if (size_addr) {
ret = put_user(used_size, size_addr, target_ulong);
if (ret) {
return ret;
}
}
if (used_size > buf_size) {
return -TARGET_ENOMEM;
}
if (mode == READ_PROCEDURE_STACK) {
dst = buf_addr;
dst_tag = 0;
src = env->psp.base;
} else {
dst = env->psp.base;
dst_tag = env->psp.base_tag;
src = buf_addr;
}
ret = copy_procedure_stack(env, dst, dst_tag, src, used_size);
break;
}
case READ_PROCEDURE_STACK_EX:
case WRITE_PROCEDURE_STACK_EX:
{
abi_ullong offset;
abi_ulong dst, dst_tag, src;
ret = get_user(offset, frame_addr, abi_ullong);
if (ret) {
return ret;
}
if (env->psp.index < (offset + buf_size)) {
return -TARGET_EFAULT;
}
if (mode == READ_PROCEDURE_STACK_EX) {
dst = buf_addr;
dst_tag = 0;
src = env->psp.base + offset;
} else {
dst = env->psp.base + offset;
dst_tag = env->psp.base_tag + offset / 8;
src = buf_addr;
}
ret = copy_procedure_stack(env, dst, dst_tag, src, buf_size);
break;
}
default:
return -TARGET_ENOSYS;
}
return ret;
}
static bool is_privileged_return(target_ulong ip)
{
return ip == E2K_SYSRET_BACKTRACE_ADDR;
}
static abi_long do_e2k_set_backtrace(CPUState *cpu, abi_ulong buf_addr,
abi_ulong count, abi_ulong skip, abi_ulong flags)
{
E2KCPU *e2k_cpu = E2K_CPU(cpu);
CPUE2KState *env = &e2k_cpu->env;
E2KCrs *pcs_base, *frame;
target_ulong *buf;
abi_long ret = 0;
int nr_written = 0;
uint64_t cr0_hi;
E2KCr1 cr1;
if (flags) {
return -TARGET_EINVAL;
}
buf = lock_user(VERIFY_READ, buf_addr, count * sizeof(*buf), 1);
pcs_base = lock_user(VERIFY_WRITE, env->pcsp.base, env->pcsp.index, 1);
if (!buf || !pcs_base) {
ret = -TARGET_EFAULT;
goto exit;
}
frame = pcs_base + env->pcsp.index / sizeof(*frame);
while (nr_written < count) {
target_ulong prev_ip, ip;
frame -= 1;
if (frame < pcs_base) {
/* Not an error: we will just return the size */
break;
}
__get_user(ip, buf);
__get_user(cr0_hi, &frame->cr0_hi);
__get_user(cr1.lo, &frame->cr1.lo);
if (ip == -1) {
ip = E2K_SYSRET_BACKTRACE_ADDR;
}
prev_ip = cr0_hi & ~7;
/* skip fake kernel frames */
if (prev_ip >= TARGET_TASK_SIZE) {
continue;
}
/* Skip the requested number of frames */
if (skip) {
--skip;
continue;
}
if (!is_privileged_return(ip) && !access_ok(cpu, VERIFY_READ, ip, 8)) {
ret = -TARGET_EFAULT;
break;
}
/* Forbid changing of special return value into normal
* one - to avoid cases when user changes to special and
* back to normal function to avoid security checks. */
if (is_privileged_return(prev_ip) && !is_privileged_return(ip)) {
ret = -TARGET_EPERM;
break;
}
// TODO: ip/prev_ip page flags checks
cr0_hi = ip & ~7;
__put_user(cr0_hi, &frame->cr0_hi);
if (is_privileged_return(ip)) {
cr1.pm = 1;
cr1.ic = 0;
__put_user(cr1.lo, &frame->cr1.lo);
}
buf += 1;
nr_written += 1;
}
if (nr_written) {
ret = nr_written;
}
exit:
unlock_user(pcs_base, env->pcsp.base, env->pcsp.index);
unlock_user(buf, buf_addr, count * sizeof(buf));
return ret;
}
static abi_long do_e2k_get_backtrace(CPUState *cpu, abi_ulong buf_addr,
abi_ulong count, abi_ulong skip, abi_ulong flags)
{
E2KCPU *e2k_cpu = E2K_CPU(cpu);
CPUE2KState *env = &e2k_cpu->env;
E2KCrs *pcs_base, *frame;
target_ulong *buf;
abi_long ret = 0;
int nr_read = 0;
uint64_t cr0_hi;
if (flags) {
return -TARGET_EINVAL;
}
buf = lock_user(VERIFY_WRITE, buf_addr, count * sizeof(*buf), 0);
pcs_base = lock_user(VERIFY_READ, env->pcsp.base, env->pcsp.index, 1);
if (!buf || !pcs_base) {
ret = -TARGET_EFAULT;
goto exit;
}
frame = pcs_base + env->pcsp.index / sizeof(*frame);
while (nr_read < count) {
target_ulong ip;
frame -= 1;
if (frame < pcs_base) {
/* Not an error: we will just return the size */
break;
}
__get_user(cr0_hi, &frame->cr0_hi);
ip = cr0_hi & ~7;
/* skip fake kernel frames */
if (!is_privileged_return(ip) && ip >= TARGET_TASK_SIZE) {
continue;
}
/* Skip the requested number of frames */
if (skip) {
--skip;
continue;
}
if (!is_privileged_return(ip) && !access_ok(cpu, VERIFY_READ, ip, 8)) {
ret = -TARGET_EFAULT;
break;
}
/* Special case of "just return" function */
if (is_privileged_return(ip)) {
ip = -1;
}
__put_user(ip, buf);
buf += 1;
nr_read += 1;
}
if (nr_read) {
ret = nr_read;
}
exit:
unlock_user(pcs_base, env->pcsp.base, env->pcsp.index);
unlock_user(buf, buf_addr, count * sizeof(buf));
return ret;
}
#endif /* end of TARGET_E2K */
static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
{
struct flock64 fl64;
@ -11839,6 +12359,35 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
#endif
return ret;
#endif
#ifdef TARGET_NR_e2k_longjmp2
case TARGET_NR_e2k_longjmp2:
{
E2KCPU *e2k_cpu = E2K_CPU(cpu);
CPUE2KState *env = &e2k_cpu->env;
struct target_jmp_info ji;
ret = copy_from_user_jmp_info(&ji, arg1);
if (ret) {
break;
}
ret = do_e2k_longjmp2(env, &ji);
if (ret) {
break;
}
return arg2;
}
#endif
#ifdef TARGET_NR_access_hw_stacks
case TARGET_NR_access_hw_stacks:
return do_e2k_access_hw_stacks(cpu, arg1, arg2, arg3, arg4, arg5);
#endif
#ifdef TARGET_NR_set_backtrace
case TARGET_NR_set_backtrace:
return do_e2k_set_backtrace(cpu, arg1, arg2, arg3, arg4);
#endif
#ifdef TARGET_NR_get_backtrace
case TARGET_NR_get_backtrace:
return do_e2k_get_backtrace(cpu, arg1, arg2, arg3, arg4);
#endif
#ifdef CONFIG_ATTR
#ifdef TARGET_NR_setxattr
case TARGET_NR_listxattr:

View File

@ -74,7 +74,7 @@
|| defined(TARGET_M68K) || defined(TARGET_CRIS) \
|| defined(TARGET_S390X) || defined(TARGET_OPENRISC) \
|| defined(TARGET_NIOS2) || defined(TARGET_RISCV) \
|| defined(TARGET_XTENSA)
|| defined(TARGET_XTENSA) || defined(TARGET_E2K)
#define TARGET_IOC_SIZEBITS 14
#define TARGET_IOC_DIRBITS 2
@ -1372,6 +1372,25 @@ struct target_winsize {
#define TARGET_MAP_NONBLOCK 0x20000 /* do not block on IO */
#define TARGET_MAP_STACK 0x40000
#define TARGET_MAP_HUGETLB 0x80000 /* create a huge page mapping */
#elif defined(TARGET_E2K)
#define TARGET_MAP_ANONYMOUS 0x000010 /* don't use a file */
#define TARGET_MAP_FIXED 0x000100 /* Interpret addr exactly */
#define TARGET_MAP_DENYWRITE 0x000800 /* ETXTBSY */
#define TARGET_MAP_GROWSDOWN 0x001000 /* stack-like segment */
#define TARGET_MAP_GROWSUP 0x002000 /* register stack-like segment */
#define TARGET_MAP_EXECUTABLE 0x004000 /* mark it as an executable */
#define TARGET_MAP_LOCKED 0x008000 /* pages are locked */
#define TARGET_MAP_NORESERVE 0x010000 /* don't check for reservations */
#define TARGET_MAP_POPULATE 0x020000 /* populate (prefault) pagetables */
#define TARGET_MAP_NONBLOCK 0x040000 /* do not block on IO */
#define TARGET_MAP_FIRST32 0x080000 /* in protected mode map in */
/* first 2 ** 32 area */
#define TARGET_MAP_WRITECOMBINED 0x100000 /* Write combine */
#define TARGET_MAP_HUGETLB 0x200000 /* create a huge page mapping */
#define TARGET_MAP_FIXED_NOREPLACE 0x400000 /* MAP_FIXED which doesn't unmap */
/* underlying mapping */
#define TARGET_MAP_STACK TARGET_MAP_GROWSDOWN
#else
#define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */
#define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */
@ -1597,6 +1616,57 @@ struct target_stat64 {
unsigned int __unused2;
};
#elif defined(TARGET_E2K)
#define TARGET_STAT_HAVE_NSEC
struct target_stat {
abi_uint st_dev;
abi_ulong st_ino;
abi_uint st_mode;
abi_uint st_nlink;
abi_uint st_uid;
abi_uint st_gid;
abi_uint st_rdev;
abi_long st_size;
abi_long st_blksize;
abi_long st_blocks;
abi_long target_st_atime;
abi_ulong target_st_atime_nsec;
abi_long target_st_mtime;
abi_ulong target_st_mtime_nsec;
abi_long target_st_ctime;
abi_ulong target_st_ctime_nsec;
};
#define TARGET_HAS_STRUCT_STAT64
struct target_stat64 {
abi_ullong st_dev;
abi_ullong st_ino;
abi_uint st_mode;
abi_uint st_nlink;
abi_uint st_uid;
abi_uint st_gid;
abi_ullong st_rdev;
abi_ullong st_size;
abi_uint st_blksize;
abi_uint __unused1;
abi_ullong st_blocks;
#if 0
abi_int target_st_atime;
abi_uint target_st_atime_nsec;
abi_int target_st_mtime;
abi_uint target_st_mtime_nsec;
abi_int target_st_ctime;
abi_uint target_st_ctime_nsec;
#else
abi_long target_st_atime;
abi_ulong target_st_atime_nsec;
abi_long target_st_mtime;
abi_ulong target_st_mtime_nsec;
abi_long target_st_ctime;
abi_ulong target_st_ctime_nsec;
#endif
};
#elif defined(TARGET_PPC)
#define TARGET_STAT_HAVE_NSEC
@ -2388,6 +2458,36 @@ struct target_statfs64 {
int32_t f_flags;
int32_t f_spare[4];
};
#elif defined(TARGET_E2K)
struct target_statfs {
abi_long f_type;
abi_long f_bsize;
abi_ulong f_blocks;
abi_ulong f_bfree;
abi_ulong f_bavail;
abi_ulong f_files;
abi_ulong f_ffree;
target_fsid_t f_fsid;
abi_long f_namelen;
abi_long f_frsize;
abi_long f_flags;
abi_long f_spare[4];
};
struct target_statfs64 {
abi_long f_type;
abi_long f_bsize;
abi_ullong f_blocks;
abi_ullong f_bfree;
abi_ullong f_bavail;
abi_ullong f_files;
abi_ullong f_ffree;
target_fsid_t f_fsid;
abi_long f_namelen;
abi_long f_frsize;
abi_long f_flags;
abi_long f_spare[4];
};
#else
struct target_statfs {
uint32_t f_type;

View File

@ -1483,6 +1483,7 @@ disassemblers = {
'avr' : ['CONFIG_AVR_DIS'],
'cris' : ['CONFIG_CRIS_DIS'],
'hexagon' : ['CONFIG_HEXAGON_DIS'],
'e2k' : ['CONFIG_E2K_DIS'],
'hppa' : ['CONFIG_HPPA_DIS'],
'i386' : ['CONFIG_I386_DIS'],
'x86_64' : ['CONFIG_I386_DIS'],
@ -2111,6 +2112,7 @@ if have_system
'hw/char',
'hw/display',
'hw/dma',
'hw/e2k',
'hw/hppa',
'hw/hyperv',
'hw/i2c',
@ -2160,6 +2162,7 @@ if have_system or have_user
'accel/tcg',
'hw/core',
'target/arm',
'target/e2k',
'target/hppa',
'target/i386',
'target/i386/kvm',

View File

@ -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 hexagon"
microblaze microblazeel or1k x86_64 hexagon e2k e2k_old e2k32 e2k32_old"
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'
@ -140,6 +140,22 @@ hexagon_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x
hexagon_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
hexagon_family=hexagon
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
e2k_old_magic='\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x31\x00'
e2k_old_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
e2k_old_family=e2k
e2k32_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xaf\x00'
e2k32_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
e2k32_family=e2k
e2k32_old_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x31\x00'
e2k32_old_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
e2k32_old_family=e2k
qemu_get_family() {
cpu=${HOST_ARCH:-$(uname -m)}
case "$cpu" in
@ -316,10 +332,12 @@ qemu_set_binfmts() {
continue
fi
qemu="$QEMU_PATH/qemu-$cpu"
if [ "$cpu" = "i486" ] ; then
qemu="$QEMU_PATH/qemu-i386"
fi
case "$cpu" in
"i486" ) qemu="$QEMU_PATH/qemu-i386";;
"e2k_old" ) qemu="$QEMU_PATH/qemu-e2k";;
"e2k32_old" ) qemu="$QEMU_PATH/qemu-e2k32";;
* ) qemu="$QEMU_PATH/qemu-$cpu";;
esac
qemu="$qemu$QEMU_SUFFIX"
if [ "$host_family" != "$family" ] ; then

View File

@ -84,6 +84,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;

View File

@ -2,6 +2,7 @@ source alpha/Kconfig
source arm/Kconfig
source avr/Kconfig
source cris/Kconfig
source e2k/Kconfig
source hppa/Kconfig
source i386/Kconfig
source m68k/Kconfig

6
target/e2k/Kconfig Normal file
View File

@ -0,0 +1,6 @@
config E2K
bool
config E2K32
bool
select E2K

1830
target/e2k/alops.inc Normal file

File diff suppressed because it is too large Load Diff

182
target/e2k/cpu-dump.c Normal file
View File

@ -0,0 +1,182 @@
/*
* e2k CPU dump to file
*
* Copyright (c) 2021 Denis Drakhnya
*
* 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 "cpu.h"
#include "helper-tcg.h"
#include "qemu/qemu-print.h"
static inline const char *indent(int width, int max_width)
{
static const char s[] = " ";
assert(width < sizeof(s) && max_width < sizeof(s));
return s + sizeof(s) - 1 - max_width + width;
}
static void dump_psp(FILE *f, int flags, const char *name, E2KPsp *psp,
bool newline)
{
qemu_fprintf(f, "%s %016" PRIx64 " base %016" PRIx64 " index %08" PRIx32
" size %08" PRIx32 " %c%c itag=%x%s",
name,
(uint64_t) psp->base + psp->index,
(uint64_t) psp->base,
(uint32_t) psp->index,
(uint32_t) psp->size,
psp->is_readable ? 'R' : ' ',
psp->is_writable ? 'W' : ' ',
(int) psp->itag,
newline ? "\n" : "");
}
static void dump_rwap(FILE *f, int flags, const char *name, E2KRwap *rwap,
bool newline)
{
qemu_fprintf(f, "%s %016" PRIx64 " base %016" PRIx64 " curptr %08" PRIx32
" size %08" PRIx32 " %c%c%c%s",
name,
(uint64_t) rwap->base + rwap->curptr,
(uint64_t) rwap->base,
(uint32_t) rwap->curptr,
(uint32_t) rwap->size,
rwap->protected ? 'P' : ' ',
rwap->read ? 'R' : ' ',
rwap->write ? 'W' : ' ',
newline ? "\n" : "");
}
static void dump_lsr(CPUE2KState *env, FILE *f, int flags)
{
qemu_fprintf(f,
" lcnt %016" PRIx64 " pcnt=%02x ecnt=%02x vlc=%d ldmc=%d ldovl=%02x\n"
"ilcnt %016" PRIx64 " ipcnt=%02x iecnt=%02x over=%d semc=%d strmd=%02x\n",
env->lsr_lcnt,
(int) env->lsr_pcnt,
(int) env->lsr_ecnt,
(int) env->lsr_vlc,
(int) extract32(env->lsr, LSR_LDMC_OFF - 32, 1),
(int) extract32(env->lsr, LSR_LDOVL_OFF - 32, LSR_LDOVL_LEN),
env->ilcr_lcnt,
(int) extract32(env->ilcr, LSR_PCNT_OFF - 32, LSR_PCNT_LEN),
(int) extract32(env->ilcr, LSR_ECNT_OFF - 32, LSR_ECNT_LEN),
(int) env->lsr_over,
(int) extract32(env->lsr, LSR_SEMC_OFF - 32, 1),
(int) env->lsr_strmd
);
}
static void dump_predicate_regs(CPUE2KState *env, FILE *f, int flags)
{
int i;
qemu_fprintf(f, "pred");
for (i = 0; i < 32; i++) {
qemu_fprintf(f, "%s%d", indent(i > 9, 2), i);
}
qemu_fprintf(f, "\n ");
for (i = 0; i < 32; i++) {
int index = i < env->bp.size ? (i + env->bp.cur) % env->bp.size : i;
int preg = (env->pregs >> (index * 2)) & 3;
qemu_fprintf(f, " %c%d", preg >> 1 ? '*' : ' ', preg & 1);
}
qemu_fprintf(f, "\n");
}
static inline void dump_reg(FILE *f, char mnemonic, int index,
uint8_t tag, E2KReg reg)
{
int width = (index > 9) + (index > 99);
const char *prefix = indent(width, 3 - ((index & 3) == 0));
uint8_t tag_lo = tag & 3;
uint8_t tag_hi = (tag >> 2) & 3;
qemu_fprintf(f, "%s%c%d <%d%d>%016" PRIx64, prefix, mnemonic, index,
tag_hi, tag_lo, reg.lo);
if ((index & 3) == 3) {
qemu_fprintf(f, "\n");
}
}
static void dump_regs(CPUE2KState *env, FILE *f, int flags)
{
int i;
for (i = 0; i < env->wd.size; i++) {
dump_reg(f, 'r', i, env->tags[i], env->regs[i]);
}
if (env->wd.size & 3) {
qemu_fprintf(f, "\n");
}
if ((env->wd.size - env->bn.base) >= env->bn.size) {
for (i = 0; i < env->bn.size; i++) {
int index = env->bn.base + (i + env->bn.cur) % env->bn.size;
dump_reg(f, 'b', i, env->tags[index], env->regs[index]);
}
if (env->bn.size & 3) {
qemu_fprintf(f, "\n");
}
}
for (i = 0; i < 32; i++) {
int index = E2K_NR_COUNT + i;
dump_reg(f, 'g', i, env->tags[index], env->regs[index]);
}
}
void e2k_cpu_dump_state(CPUState *cs, FILE *f, int flags)
{
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
qemu_fprintf(f,
" ip %016" PRIx64 " ctpr1 %016" PRIx64 " ctpr2 %016" PRIx64 " ctpr3 %016" PRIx64 "\n"
" sbr %016" PRIx64 " osr0 %016" PRIx64 " psr=%02x upsr=%04x\n",
(uint64_t) env->ip,
env->ctprs[0].raw,
env->ctprs[1].raw,
env->ctprs[2].raw,
env->sbr,
env->osr0,
(int) env->psr,
(int) env->upsr
);
dump_rwap(f, flags, " usd", &env->usd, true);
dump_psp(f, flags, " pcsp", &env->pcsp, true);
dump_psp(f, flags, " psp", &env->psp, true);
dump_rwap(f, flags, "oscud", &env->oscud, true);
dump_rwap(f, flags, " osgd", &env->osgd, true);
dump_rwap(f, flags, " cud", &env->cud, true);
dump_rwap(f, flags, " gd", &env->gd, true);
dump_lsr(env, f, flags);
qemu_fprintf(f, " wsz=%d wbdl=%d rbs=%d rsz=%d rcur=%d psz=%d pcur=%d\n",
(int) env->wd.size,
(int) env->wdbl,
(int) env->bn.base,
(int) env->bn.size,
(int) env->bn.cur,
(int) env->bp.size,
(int) env->bp.cur
);
dump_predicate_regs(env, f, flags);
dump_regs(env, f, flags);
}

20
target/e2k/cpu-param.h Normal file
View File

@ -0,0 +1,20 @@
/*
* E2K cpu parameters for qemu.
*
* SPDX-License-Identifier: LGPL-2.0+
*/
#ifndef E2K_CPU_PARAM_H
#define E2K_CPU_PARAM_H 1
#ifdef TARGET_E2K32
# define TARGET_LONG_BITS 32
#else
# define TARGET_LONG_BITS 64
#endif
#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
View 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

462
target/e2k/cpu.c Normal file
View File

@ -0,0 +1,462 @@
/*
* 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 "qemu/module.h"
#include "qemu/qemu-print.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "cpu.h"
#include "helper-tcg.h"
#include "exec/exec-all.h"
#include "hw/qdev-properties.h"
#include "hw/core/tcg-cpu-ops.h"
#include "sysemu/sysemu.h"
#include "sysemu/tcg.h"
#include "sysemu/reset.h"
#ifndef CONFIG_USER_ONLY
#include "exec/address-spaces.h"
#include "hw/e2k/apic_internal.h"
#include "hw/boards.h"
#endif
//#define DEBUG_FEATURES
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));
/* must be set by set_pc */
/* env->ip = 0x10000; */
env->psr = PSR_PM;
env->upsr = UPSR_NMIE | UPSR_FE;
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;
env->fpcr.pc = FPCR_PC_XP;
env->fpcr.em = FP_EM;
env->pfpfr.em = FP_EM;
e2k_update_fp_status(env);
e2k_update_fx_status(env);
// FIXME: testing
env->idr = 0x3a207; /* mimic 8c */
// FIXME: correct values
env->psp.base = 0x810000;
env->psp.size = 0x100000;
env->pcsp.base = 0x910000;
env->pcsp.size = 0xa10000;
#if !defined(CONFIG_USER_ONLY)
/* FIXME: default values calculated from E2K E1CP firmware */
env->sbr = 0xb000;
env->usd.hi = 0x400000000000;
env->usd.lo = env->sbr + 0x1800000000000000;
/* We hard-wire the BSP to the first CPU. */
apic_designate_bsp(cpu->apic_state, cs->cpu_index == 0);
cs->halted = !cpu_is_bsp(cpu);
#endif
}
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)
{
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
qemu_log_mask(LOG_UNIMP, "e2k_cpu_do_interrupt: not implemented %d at " TARGET_FMT_lx "\n",
cs->exception_index, env->ip);
exit(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;
}
/* https://www.altlinux.org/Модели_процессоров_Эльбрус */
#define DEFAULT_CPU_MODEL "e8c"
static const struct e2k_def_t e2k_defs[] = {
{
.name = "e2c+", /* however it may work better */
.canonical_name = "MCST Elbrus 2C+ (Monocube)",
.gdb_arch = "elbrus-v2",
.isa_version = 2,
},
{
.name = "e2s",
.canonical_name = "MCST Elbrus 4C",
.gdb_arch = "elbrus-v3",
.isa_version = 3,
},
{
.name = "e8c", /* default choice for system */
.canonical_name = "MCST Elbrus 8C",
.gdb_arch = "elbrus-8c",
.isa_version = 4,
},
{
.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,
},
};
static bool e2k_get_paging_enabled(const CPUState *cs)
{
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
return env->mmu.cr & MMU_CR_TLB_EN;
}
static void e2k_cpu_set_pc(CPUState *cs, vaddr value)
{
E2KCPU *cpu = E2K_CPU(cs);
cpu->env.ip = value;
}
static void e2k_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb)
{
E2KCPU *cpu = E2K_CPU(cs);
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
typename = e2k_cpu_type_name(cpu_model);
oc = object_class_by_name(typename);
g_free(typename);
return oc;
}
#ifndef CONFIG_USER_ONLY
bool cpu_is_bsp(E2KCPU *cpu)
{
return cpu_get_apic_base(cpu->apic_state) & MSR_IA32_APICBASE_BSP;
}
/* TODO: remove me, when reset over QOM tree is implemented */
static void e2k_cpu_machine_reset_cb(void *opaque)
{
E2KCPU *cpu = opaque;
cpu_reset(CPU(cpu));
}
void cpu_clear_apic_feature(CPUE2KState *env)
{
}
APICCommonClass *apic_get_class(void)
{
const char *apic_type = "apic";
/* TODO: kvm */
return APIC_COMMON_CLASS(object_class_by_name(apic_type));
}
static void e2k_cpu_apic_create(E2KCPU *cpu, Error **errp)
{
APICCommonState *apic;
ObjectClass *apic_class = OBJECT_CLASS(apic_get_class());
cpu->apic_state = DEVICE(object_new_with_class(apic_class));
object_property_add_child(OBJECT(cpu), "lapic",
OBJECT(cpu->apic_state));
object_unref(OBJECT(cpu->apic_state));
qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id);
/* TODO: convert to link<> */
apic = APIC_COMMON(cpu->apic_state);
apic->cpu = cpu;
apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE;
}
static void e2k_cpu_apic_realize(E2KCPU *cpu, Error **errp)
{
APICCommonState *apic;
static bool apic_mmio_map_once;
if (cpu->apic_state == NULL) {
return;
}
qdev_realize(DEVICE(cpu->apic_state), NULL, errp);
/* Map APIC MMIO area */
apic = APIC_COMMON(cpu->apic_state);
if (!apic_mmio_map_once) {
memory_region_add_subregion_overlap(get_system_memory(),
apic->apicbase &
MSR_IA32_APICBASE_BASE,
&apic->io_memory,
0x1000);
apic_mmio_map_once = true;
}
}
#endif /* !CONFIG_USER_ONLY */
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) {
goto out;
}
e2k_cpu_register_gdb_regs_for_features(cs);
#ifndef CONFIG_USER_ONLY
qemu_register_reset(e2k_cpu_machine_reset_cb, cpu);
// if (ms->smp.cpus > 1) {
e2k_cpu_apic_create(cpu, &local_err);
if (local_err != NULL) {
goto out;
}
// }
#endif
qemu_init_vcpu(cs);
e2k_cpu_apic_realize(cpu, &local_err);
if (local_err != NULL) {
goto out;
}
cpu_reset(cs);
ecc->parent_realize(dev, errp);
out:
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
}
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 struct TCGCPUOps e2k_tcg_ops = {
.initialize = e2k_tcg_initialize,
.synchronize_from_tb = e2k_cpu_synchronize_from_tb,
.cpu_exec_interrupt = e2k_cpu_exec_interrupt,
.do_interrupt = e2k_cpu_do_interrupt,
.tlb_fill = e2k_cpu_tlb_fill,
};
static Property e2k_cpu_properties[] = {
DEFINE_PROP_BOOL("force_save_alc_dst", E2KCPU, env.force_save_alc_dst, false),
DEFINE_PROP_BOOL("tags", E2KCPU, env.enable_tags, false),
DEFINE_PROP_END_OF_LIST()
};
#ifndef CONFIG_USER_ONLY
#include "hw/core/sysemu-cpu-ops.h"
static const struct SysemuCPUOps e2k_sysemu_ops = {
.get_paging_enabled = e2k_get_paging_enabled,
.get_phys_page_attrs_debug = e2k_get_phys_page_attrs_debug,
};
#endif
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_props(dc, e2k_cpu_properties);
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->class_by_name = e2k_cpu_class_by_name;
cc->disas_set_info = cpu_e2k_disas_set_info;
#ifndef CONFIG_USER_ONLY
cc->sysemu_ops = &e2k_sysemu_ops;
#endif /* !CONFIG_USER_ONLY */
cc->gdb_core_xml_file = "e2k-v1.xml";
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;
cc->tcg_ops = &e2k_tcg_ops;
}
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;
size_t len = 0;
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
);
}
qemu_printf("\nFeatures:\n");
for (i = 0; i < ARRAY_SIZE(e2k_cpu_properties); i++) {
const char *name = e2k_cpu_properties[i].name;
size_t l = strlen(name) + 1;
if (len + l >= 75) {
qemu_printf("\n");
len = 0;
}
qemu_printf("%s%s", len ? " " : " ", name);
len += l;
}
qemu_printf("\n");
}

1057
target/e2k/cpu.h Normal file

File diff suppressed because it is too large Load Diff

379
target/e2k/gdbstub.c Normal file
View File

@ -0,0 +1,379 @@
/*
* 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 "helper-tcg.h"
#include "exec/gdbstub.h"
/* TODO: reverse engineer e2k-linux-gdb register ids */
static uint64_t cr_read(CPUState *cs, CPUE2KState *env, size_t offset)
{
target_ulong addr = env->pcsp.base + env->pcsp.index + offset;
uint64_t r;
cpu_memory_rw_debug(cs, addr, &r, sizeof(r), false);
return r;
}
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].lo);
}
switch (n) {
case 35: return gdb_get_reg64(mem_buf, env->psr); // psr
case 36: return gdb_get_reg64(mem_buf, env->upsr); // upsr
case 37: return gdb_get_reg64(mem_buf, env->oscud.lo); // oscud_lo
case 38: return gdb_get_reg64(mem_buf, env->oscud.hi); // oscud_hi
case 39: return gdb_get_reg64(mem_buf, env->osgd.lo); // osgd_lo
case 40: return gdb_get_reg64(mem_buf, env->osgd.hi); // osgd_hi
case 41: return gdb_get_reg64(mem_buf, 0); // osem
case 42: return gdb_get_reg64(mem_buf, env->osr0); // osr0
case 43: return gdb_get_reg64(mem_buf, env->pfpfr.raw); // pfpfr
case 44: return gdb_get_reg64(mem_buf, env->fpcr.raw); // fpcr
case 45: return gdb_get_reg64(mem_buf, env->fpsr.raw); // 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, env->psp.lo); // psp_lo
case 50: return gdb_get_reg64(mem_buf, env->psp.hi); // psp_hi
case 51: return gdb_get_reg64(mem_buf, 0); // 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: { // cr1_lo
uint64_t cr1_lo = cr_read(cs, env, offsetof(E2KCrs, cr1.lo));
return gdb_get_reg64(mem_buf, cr1_lo);
}
case 55: { // cr1_hi
uint64_t cr1_hi = cr_read(cs, env, offsetof(E2KCrs, cr1.hi));
return gdb_get_reg64(mem_buf, cr1_hi);
}
case 56: return gdb_get_reg64(mem_buf, 0); // cwd
case 57: return gdb_get_reg64(mem_buf, env->pcsp.lo); // pcsp_lo
case 58: return gdb_get_reg64(mem_buf, env->pcsp.hi); // pcsp_hi
case 59: return gdb_get_reg64(mem_buf, 0); // pcshtp
case 60: return gdb_get_reg64(mem_buf, env->cud.lo); // cud_lo
case 61: return gdb_get_reg64(mem_buf, env->cud.hi); // cud_hi
case 62: return gdb_get_reg64(mem_buf, env->gd.lo); // gd_lo
case 63: return gdb_get_reg64(mem_buf, env->gd.hi); // gd_hi
case 64: return gdb_get_reg64(mem_buf, env->cs.lo); // cs_lo
case 65: return gdb_get_reg64(mem_buf, env->cs.hi); // cs_hi
case 66: return gdb_get_reg64(mem_buf, env->ds.lo); // ds_lo
case 67: return gdb_get_reg64(mem_buf, env->ds.hi); // ds_hi
case 68: return gdb_get_reg64(mem_buf, env->es.lo); // es_lo
case 69: return gdb_get_reg64(mem_buf, env->es.hi); // es_hi
case 70: return gdb_get_reg64(mem_buf, env->fs.lo); // fs_lo
case 71: return gdb_get_reg64(mem_buf, env->fs.hi); // fs_hi
case 72: return gdb_get_reg64(mem_buf, env->gs.lo); // gs_lo
case 73: return gdb_get_reg64(mem_buf, env->gs.hi); // gs_hi
case 74: return gdb_get_reg64(mem_buf, env->ss.lo); // ss_lo
case 75: return gdb_get_reg64(mem_buf, env->ss.hi); // 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, env_wd_get(env)); // wd
case 335: return gdb_get_reg64(mem_buf, 0); // unk
case 336: return gdb_get_reg64(mem_buf, env->bgr); // bgr
case 337: return gdb_get_reg64(mem_buf, 0); // unk
case 338: return gdb_get_reg64(mem_buf, env->nip); // 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_get(env)); /* lsr */
case 348: return gdb_get_reg64(mem_buf, env_ilcr_get(env)); /* ilcr */
default:
break;
}
if (349 <= n && n < 356) {
return gdb_get_reg64(mem_buf, 0); // unk
}
if (356 <= n && n < 360) {
uint64_t tags = 0;
int i, offset = E2K_NR_COUNT + (n - 356) * 8;
for (i = 0; i < 8; i++) {
tags |= (uint64_t) env->tags[offset + i] << (i * 8);
}
return gdb_get_reg64(mem_buf, tags); // gN tags (tag len is 1 byte)
}
if (360 <= n && n < 368) {
uint64_t ext = 0;
int i, offset = E2K_NR_COUNT + (n - 360) * 4;
for (i = 0; i < 4; i++) {
ext |= ((uint64_t) env->regs[offset + i].hi & 0xffff) << (i * 16);
}
return gdb_get_reg64(mem_buf, ext); // 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;
}
static int gdb_get_v2(CPUE2KState *env, GByteArray *buf, int n)
{
if (n == 0) {
/* idr */
return gdb_get_reg64(buf, env->idr);
}
return 0;
}
static int gdb_set_v2(CPUE2KState *env, uint8_t *mem_buf, int n)
{
fprintf(stderr, "%s: unknown register %d\n", __FUNCTION__, n);
return 0;
}
static int gdb_get_v3(CPUE2KState *env, GByteArray *buf, int n)
{
if (n == 0) {
/* core_mode */
return gdb_get_reg64(buf, env->core_mode);
}
return 0;
}
static int gdb_set_v3(CPUE2KState *env, uint8_t *mem_buf, int n)
{
fprintf(stderr, "%s: unknown register %d\n", __FUNCTION__, n);
return 0;
}
static int gdb_get_v5(CPUE2KState *env, GByteArray *buf, int n)
{
if (n == 0) {
/* lsr1 */
return gdb_get_reg64(buf, env->lsr_lcnt);
} else if (n == 1) {
/* ilcr1 */
return gdb_get_reg64(buf, env->ilcr_lcnt);
} else if (n >= 2 && n < 34) {
/* xgN (upper 64-bit) */
return gdb_get_reg64(buf, env->regs[E2K_NR_COUNT + n - 2].hi);
} else if (n >= 34 && n < 66) {
/* qpgN tags */
return gdb_get_reg8(buf, env->tags[E2K_NR_COUNT + n - 34]);
}
return 0;
}
static int gdb_set_v5(CPUE2KState *env, uint8_t *mem_buf, int n)
{
fprintf(stderr, "%s: unknown register %d\n", __FUNCTION__, n);
return 0;
}
void e2k_cpu_register_gdb_regs_for_features(CPUState *cs)
{
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
if (env->version >= 2) {
gdb_register_coprocessor(cs, gdb_get_v2, gdb_set_v2,
1, "e2k-v2.xml", 574);
}
if (env->version >= 3) {
gdb_register_coprocessor(cs, gdb_get_v3, gdb_set_v3,
1, "e2k-v3.xml", 575);
}
if (env->version >= 5) {
gdb_register_coprocessor(cs, gdb_get_v5, gdb_set_v5,
66, "e2k-v5.xml", 576);
}
}

144
target/e2k/helper-tcg.h Normal file
View File

@ -0,0 +1,144 @@
/*
* e2k TCG specific prototypes for helpers
*
* Copyright (c) 2020-2021 Denis Drakhnya, Alibek Omarov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef E2K_HELPER_TCG_H
#define E2K_HELPER_TCG_H
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/exec-all.h"
#define glue3(x, y, z) glue(glue(x, y), z)
#define glue4(x, y, z, w) glue(glue3(x, y, z), w)
#define deref(x) *(x)
#define ident(x) (x)
/* helper.c */
void QEMU_NORETURN raise_exception(CPUE2KState *desc, int exception_index);
void QEMU_NORETURN raise_exception_ra(CPUE2KState *desc, int exception_index,
uintptr_t retaddr);
static inline uint64_t env_wd_get(CPUE2KState *env)
{
E2KWdState *wd = &env->wd;
uint64_t ret = 0;
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 void env_wd_set(CPUE2KState *env, uint64_t raw)
{
env->wd.size = extract64(raw, WD_SIZE_OFF, WD_SIZE_LEN) / 8;
env->wd.psize = extract64(raw, WD_PSIZE_OFF, WD_PSIZE_LEN) / 8;
env->wd.fx = extract64(raw, WD_FX_OFF, 1);
}
static inline uint32_t env_br_get(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 - 1);
ret = deposit32(ret, BR_PCUR_OFF, BR_PCUR_LEN, bp->cur);
return ret;
}
static inline void env_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) + 1;
bp->cur = extract32(br, BR_PCUR_OFF, BR_PCUR_LEN);
}
static inline uint64_t env_lsr_get(CPUE2KState *env)
{
uint64_t lsr = env->lsr;
lsr = deposit64(lsr, LSR_LCNT_OFF, LSR_LCNT_LEN, env->lsr_lcnt);
lsr = deposit64(lsr, LSR_ECNT_OFF, LSR_ECNT_LEN, env->lsr_ecnt);
lsr = deposit64(lsr, LSR_VLC_OFF, 1, env->lsr_vlc);
lsr = deposit64(lsr, LSR_OVER_OFF, 1, env->lsr_over);
lsr = deposit64(lsr, LSR_PCNT_OFF, LSR_PCNT_LEN, env->lsr_pcnt);
lsr = deposit64(lsr, LSR_STRMD_OFF, LSR_STRMD_LEN, env->lsr_strmd);
return lsr;
}
static inline void env_lsr_set(CPUE2KState *env, uint64_t val)
{
env->lsr = val;
env->lsr_lcnt = extract64(val, LSR_LCNT_OFF, LSR_LCNT_LEN);
env->lsr_ecnt = extract64(val, LSR_ECNT_OFF, LSR_ECNT_LEN);
env->lsr_vlc = extract64(val, LSR_VLC_OFF, 1);
env->lsr_over = extract64(val, LSR_OVER_OFF, 1);
env->lsr_pcnt = extract64(val, LSR_PCNT_OFF, LSR_PCNT_LEN);
env->lsr_strmd = extract64(val, LSR_STRMD_OFF, LSR_STRMD_LEN);
}
static inline uint64_t env_ilcr_get(CPUE2KState *env)
{
return ((uint64_t) env->ilcr << LSR_ECNT_OFF)
| (env->ilcr_lcnt & GEN_MASK(0, LSR_LCNT_LEN));
}
static inline void env_ilcr_set(CPUE2KState *env, uint64_t value)
{
env->ilcr = (value >> LSR_ECNT_OFF) & ILCR_MASK;
env->ilcr_lcnt = value & GEN_MASK(0, LSR_LCNT_LEN);
}
static inline uint64_t env_usd_lo_get(CPUE2KState *env)
{
uint64_t r = 0;
r = deposit64(r, USD_LO_BASE_OFF, USD_LO_BASE_LEN, env->usd.base);
r |= env->usd.protected ? USD_LO_PROTECTED_BIT : 0;
r |= env->usd.read ? USD_LO_READ_BIT : 0;
r |= env->usd.write ? USD_LO_WRITE_BIT : 0;
return r;
}
static inline void env_usd_lo_set(CPUE2KState *env, uint64_t value)
{
env->usd.base = extract64(value, USD_LO_BASE_OFF, USD_LO_BASE_LEN);
env->usd.protected = (value & USD_LO_PROTECTED_BIT) != 0;
env->usd.read = (value & USD_LO_READ_BIT) != 0;
env->usd.write = (value & USD_LO_WRITE_BIT) != 0;
}
#endif /* E2K_HELPER_TCG_H */

488
target/e2k/helper.c Normal file
View File

@ -0,0 +1,488 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "qemu/log.h"
#include "sysemu/runstate.h"
#include "exec/helper-proto.h"
#include "exec/address-spaces.h"
#include "helper-tcg.h"
#include "trace.h"
#include "hw/e2k/memmap.h"
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 ps_push(CPUE2KState *env, uint64_t value, uint8_t tag)
{
#ifndef CONFIG_USER_ONLY
if ((env->psp.index + 8) > env->psp.size) {
raise_exception(env, EXCP_PROC_STACK_BOUNDS);
}
#endif
cpu_stq_le_data(env, env->psp.base + env->psp.index, value);
if (env->enable_tags) {
cpu_stb_data(env, env->psp.base_tag + env->psp.index / 8, tag);
}
env->psp.index += 8;
}
static inline uint64_t ps_pop(CPUE2KState *env, uint8_t *ret_tag)
{
if (env->psp.index < 8) {
raise_exception(env, EXCP_PROC_STACK_BOUNDS);
}
env->psp.index -= 8;
if (ret_tag != NULL) {
if (env->enable_tags) {
abi_ptr ptr = env->psp.base_tag + env->psp.index / 8;
*ret_tag = cpu_ldub_data(env, ptr);
} else {
*ret_tag = 0;
}
}
return cpu_ldq_le_data(env, env->psp.base + env->psp.index);
}
static void ps_spill(CPUE2KState *env, int n, bool fx)
{
int i;
if (env->version >= 5) {
for (i = 0; i < n; i++) {
ps_push(env, env->regs[i].lo, env->tags[i]);
if (fx || E2K_FORCE_FX) {
ps_push(env, env->regs[i].hi, 0);
}
}
} else{
for (i = 0; i < n; i += 2) {
E2KReg r0 = env->regs[i + 0];
E2KReg r1 = env->regs[i + 1];
ps_push(env, r0.lo, env->tags[i]);
ps_push(env, r1.lo, env->tags[i + 1]);
if (fx || E2K_FORCE_FX) {
ps_push(env, r0.hi, 0);
ps_push(env, r1.hi, 0);
}
}
}
}
static void ps_fill(CPUE2KState *env, int n, bool fx)
{
int i;
if (env->version >= 5) {
for (i = n; i-- > 0;) {
if (fx || E2K_FORCE_FX) {
env->regs[i].hi = ps_pop(env, NULL);
}
env->regs[i].lo = ps_pop(env, &env->tags[i]);
}
} else {
for (i = n; i > 0; i -= 2) {
E2KReg *r0 = &env->regs[i - 1];
E2KReg *r1 = &env->regs[i - 2];
if (fx || E2K_FORCE_FX) {
r0->hi = ps_pop(env, NULL);
r1->hi = ps_pop(env, NULL);
}
r0->lo = ps_pop(env, &env->tags[i - 1]);
r1->lo = ps_pop(env, &env->tags[i - 2]);
}
}
}
static void move_regs(CPUE2KState *env, int dst, int src, int n)
{
memmove(&env->regs[dst], &env->regs[src], n * sizeof(env->regs[0]));
if (env->enable_tags) {
memmove(&env->tags[dst], &env->tags[src], n * sizeof(env->tags[0]));
}
}
static void callee_window(CPUE2KState *env, int base, int size, bool fx)
{
ps_spill(env, base, fx);
move_regs(env, 0, base, size - base);
}
static void caller_window(CPUE2KState *env, int base, int params, bool fx)
{
move_regs(env, base, 0, params);
ps_fill(env, base, fx);
}
static void crs_write(CPUE2KState *env, target_ulong addr, E2KCrs *crs)
{
cpu_stq_le_data(env, addr + offsetof(E2KCrs, cr0_lo), crs->cr0_lo);
cpu_stq_le_data(env, addr + offsetof(E2KCrs, cr0_hi), crs->cr0_hi);
cpu_stq_le_data(env, addr + offsetof(E2KCrs, cr1.lo), crs->cr1.lo);
cpu_stq_le_data(env, addr + offsetof(E2KCrs, cr1.hi), crs->cr1.hi);
}
static void crs_read(CPUE2KState *env, target_ulong addr, E2KCrs *crs)
{
crs->cr0_lo = cpu_ldq_le_data(env, addr + offsetof(E2KCrs, cr0_lo));
crs->cr0_hi = cpu_ldq_le_data(env, addr + offsetof(E2KCrs, cr0_hi));
crs->cr1.lo = cpu_ldq_le_data(env, addr + offsetof(E2KCrs, cr1.lo));
crs->cr1.hi = cpu_ldq_le_data(env, addr + offsetof(E2KCrs, cr1.hi));
}
static void pcs_push(CPUE2KState *env, E2KCrs *crs)
{
#ifndef CONFIG_USER_ONLY
if ((env->pcsp.index + sizeof(E2KCrs) * 2) > env->pcsp.size) {
raise_exception(env, EXCP_CHAIN_STACK_BOUNDS);
}
#endif
env->pcsp.index += sizeof(E2KCrs);
crs_write(env, env->pcsp.base + env->pcsp.index, crs);
}
static void pcs_pop(CPUE2KState *env, E2KCrs *crs)
{
crs_read(env, env->pcsp.base + env->pcsp.index, crs);
if (env->pcsp.index < sizeof(E2KCrs)) {
raise_exception(env, EXCP_CHAIN_STACK_BOUNDS);
} else {
env->pcsp.index -= sizeof(E2KCrs);
}
}
void e2k_proc_call(CPUE2KState *env, int base, target_ulong ret_ip,
bool force_fx)
{
E2KCrs crs;
crs.cr0_lo = env->pregs;
crs.cr0_hi = ret_ip & ~7;
crs.cr1.wbs = base / 2;
crs.cr1.wpsz = env->wd.psize / 2;
crs.cr1.wfx = env->wd.fx;
crs.cr1.wdbl = env->wdbl;
crs.cr1.psr = env->psr;
crs.cr1.cuir = env->cuir;
crs.cr1.br = env_br_get(env);
crs.cr1.ussz = env->usd.size >> 4;
pcs_push(env, &crs);
callee_window(env, base, env->wd.size, env->wd.fx || force_fx);
env->wd.fx = true;
env->wd.size -= base;
env->wd.psize = env->wd.size;
}
void e2k_proc_return(CPUE2KState *env, bool force_fx)
{
E2KCrs crs;
int base;
pcs_pop(env, &crs);
base = crs.cr1.wbs * 2;
caller_window(env, base, env->wd.psize, crs.cr1.wfx || force_fx);
env->pregs = crs.cr0_lo;
env->ip = crs.cr0_hi & ~7;
env_br_set(env, crs.cr1.br);
env->cuir = crs.cr1.cuir;
env->psr = crs.cr1.psr;
env->wd.size = env->wd.psize + base;
env->wd.psize = crs.cr1.wpsz * 2;
env->wd.fx = crs.cr1.wfx;
env->wdbl = crs.cr1.wdbl;
env->usd.size = crs.cr1.ussz << 4;
env->usd.base = env->sbr - env->usd.size;
}
static inline void do_call(CPUE2KState *env, int wbs, target_ulong ret_ip)
{
e2k_proc_call(env, wbs * 2, ret_ip, false);
reset_ctprs(env);
}
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:
case CTPR_TAG_SDISP:
do_call(env, call_wbs, pc_next);
env->ip = ctpr.base;
break;
default:
raise_exception(env, EXCP_ILLEGAL_OPCODE);
break;
}
}
#ifdef CONFIG_USER_ONLY
void HELPER(expand_stacks)(CPUE2KState *env)
{
if ((env->psp.size - env->psp.index) <= (E2K_REG_LEN * E2K_NR_COUNT * 4)) {
raise_exception_ra(env, EXCP_PROC_STACK_BOUNDS, GETPC());
}
if ((env->pcsp.size - env->pcsp.index) <= (sizeof(E2KCrs) * 2)) {
raise_exception_ra(env, EXCP_CHAIN_STACK_BOUNDS, GETPC());
}
}
#endif /* CONFIG_USER_ONLY */
uint64_t HELPER(prep_return)(CPUE2KState *env, int ipd)
{
E2KCtpr ret = { 0 };
target_ulong addr = env->pcsp.base + env->pcsp.index + offsetof(E2KCrs, cr0_hi);
uint64_t cr0_hi = cpu_ldq_le_data(env, addr) & ~7;
ret.ipd = ipd;
ret.base = cr0_hi;
ret.tag = CTPR_TAG_RETURN;
#ifdef CONFIG_USER_ONLY
ret.opc = cr0_hi == E2K_SIGRET_ADDR ? CTPR_OPC_SIGRET : 0;
#else
// TODO: set ctpr.opc
ret.opc = 0;
#endif
return ret.raw;
}
void HELPER(return)(CPUE2KState *env)
{
CtprOpc opc = env->ctprs[2].opc;
#ifdef CONFIG_USER_ONLY
if (opc == CTPR_OPC_SIGRET) {
CPUState *cs = env_cpu(env);
env->wd.psize = 2;
env->regs[0].lo = 119; /* TARGET_NR_sigreturn */
env->tags[0] = E2K_TAG_NUMBER64;
cs->exception_index = EXCP_SYSCALL;
cpu_loop_exit(cs);
}
#endif
if (opc != 0) {
qemu_log(TARGET_FMT_lx ": unknown return ctpr opc %d\n", env->ip, opc);
}
e2k_proc_return(env, false);
reset_ctprs(env);
}
void QEMU_NORETURN raise_exception(CPUE2KState *env, int exception_index)
{
raise_exception_ra(env, exception_index, 0);
}
void QEMU_NORETURN raise_exception_ra(CPUE2KState *env, int exception_index,
uintptr_t retaddr)
{
CPUState *cs = env_cpu(env);
switch (exception_index) {
#ifdef CONFIG_USER_ONLY
case EXCP_SYSCALL:
#endif
case EXCP_PROC_STACK_BOUNDS:
case EXCP_CHAIN_STACK_BOUNDS:
/* ignore */
break;
default:
e2k_proc_call(env, env->wd.size, env->ip, true);
break;
}
cs->exception_index = exception_index;
cpu_loop_exit_restore(cs, retaddr);
}
void HELPER(raise_exception)(CPUE2KState *env, int exception_index)
{
raise_exception(env, exception_index);
}
void HELPER(setwd)(CPUE2KState *env, int wsz, int nfx, int dbl)
{
int size, diff;
size = wsz * 2;
diff = size - env->wd.size;
if (size < env->wd.psize) {
raise_exception(env, EXCP_ILLEGAL_OPCODE);
}
if (diff > 0) {
// FIXME: zeroing registers is not needed, but useful for debugging
#if 0
memset(&env->regs[env->wd.size], 0, diff * sizeof(env->regs[0]));
#endif
if (env->enable_tags) {
memset(&env->tags[env->wd.size], E2K_TAG_NON_NUMBER128, diff);
}
}
env->wd.size = size;
env->wd.fx = nfx == 0;
env->wdbl = dbl;
}
#ifndef CONFIG_USER_ONLY
hwaddr e2k_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, MemTxAttrs *attrs)
{
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
uint64_t pte;
uint32_t page_offset;
int page_size;
if (!(env->mmu.cr & MMU_CR_TLB_EN)) {
pte = addr & PTE_MASK;
page_size = PTE_SIZE;
} else {
// TODO: page table walk
abort();
}
pte &= ((1ULL << (env->version >= 6 ? 48 : 40)) - 1) & ~(page_size - 1);
page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
return pte | page_offset;
}
static int handle_mmu_fault(CPUState *cs, vaddr addr, int size,
MMUAccessType access_type, int mmu_idx)
{
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
if (!(env->mmu.cr & MMU_CR_TLB_EN)) {
int prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
tlb_set_page(cs, addr, addr, prot, mmu_idx, PTE_SIZE);
} else {
// TODO: page table walk
abort();
}
return 0;
}
#endif
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;
#ifdef CONFIG_USER_ONLY
raise_exception_ra(env, EXCP_DATA_PAGE, retaddr);
#else
env->retaddr = retaddr;
if (handle_mmu_fault(cs, address, size, access_type, mmu_idx)) {
raise_exception_ra(env, EXCP_DATA_PAGE, retaddr);
}
return true;
#endif
}
void HELPER(break_restore_state)(CPUE2KState *env)
{
e2k_proc_return(env, true);
env->is_bp = false;
}
void HELPER(debug)(CPUE2KState *env)
{
CPUState *cs = env_cpu(env);
env->is_bp = true;
e2k_proc_call(env, env->wd.size, env->ip, true);
cs->exception_index = EXCP_DEBUG;
cpu_loop_exit(cs);
}
#ifndef CONFIG_USER_ONLY
static AddressSpace *get_addressspace_by_addr(target_ulong *addr, CPUState *env, MemTxAttrs attrs)
{
if (*addr >= E2K_IO_AREA_BASE && *addr < E2K_IO_AREA_BASE + E2K_IO_AREA_SIZE)
{
*addr -= E2K_IO_AREA_BASE;
return &address_space_io;
}
return cpu_addressspace(env, attrs);
}
#define GEN_IO_LD_IMPL(T, f, op) \
T HELPER(f)(CPUE2KState *env, target_ulong port) \
{ \
MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; \
AddressSpace *as = get_addressspace_by_addr(&port, env_cpu(env), attrs); \
T ret = address_space_ ## op (as, port, attrs, NULL); \
trace_ioaddr_in(#f, port, ret); \
return ret; \
}
#define GET_IO_ST_IMPL(T, f, op) \
void HELPER(f)(CPUE2KState *env, target_ulong port, T val) \
{ \
MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; \
AddressSpace *as = get_addressspace_by_addr(&port, env_cpu(env), attrs); \
address_space_ ## op (as, port, val, attrs, NULL); \
trace_ioaddr_out(#f, port, val); \
}
GEN_IO_LD_IMPL(uint64_t, inb, ldub)
GEN_IO_LD_IMPL(uint64_t, inh, lduw)
GEN_IO_LD_IMPL(uint64_t, inw, ldl)
GEN_IO_LD_IMPL(uint64_t, ind, ldq)
GET_IO_ST_IMPL(uint32_t, outb, stb)
GET_IO_ST_IMPL(uint32_t, outh, stw)
GET_IO_ST_IMPL(uint32_t, outw, stl)
GET_IO_ST_IMPL(uint64_t, outd, stq)
uint64_t HELPER(mmu_ind)(CPUE2KState *env, target_ulong reg)
{
trace_mmu_ind(reg, 0);
return 0;
}
void HELPER(mmu_outd)(CPUE2KState *env, target_ulong reg, uint64_t val)
{
trace_mmu_outd(reg, val);
}
void cpu_report_tpr_access(CPUE2KState *env, TPRAccess access)
{
#if 0
E2KCPU *cpu = env_archcpu(env);
CPUState *cs = env_cpu(env);
if (kvm_enabled() || whpx_enabled()) {
env->tpr_access_type = access;
cpu_interrupt(cs, CPU_INTERRUPT_TPR);
} else if (tcg_enabled()) {
cpu_restore_state(cs, cs->mem_io_pc, false);
apic_handle_tpr_access_report(cpu->apic_state, env->eip, access);
}
#else
abort();
#endif
}
#endif

355
target/e2k/helper.h Normal file
View File

@ -0,0 +1,355 @@
#define dh_alias_vec ptr
#define dh_alias_f80 ptr
#define dh_ctype_vec E2KReg *
#define dh_ctype_f80 floatx80 *
#define dh_is_signed_vec dh_is_signed_ptr
#define dh_is_signed_f80 dh_is_signed_ptr
DEF_HELPER_2(raise_exception, noreturn, env, int)
DEF_HELPER_1(debug, noreturn, env)
DEF_HELPER_1(break_restore_state, void, env)
#ifdef CONFIG_USER_ONLY
DEF_HELPER_1(expand_stacks, void, env)
#else
DEF_HELPER_2(inb, i64, env, tl)
DEF_HELPER_2(inh, i64, env, tl)
DEF_HELPER_2(inw, i64, env, tl)
DEF_HELPER_2(ind, i64, env, tl)
DEF_HELPER_3(outb, void, env, tl, i32)
DEF_HELPER_3(outh, void, env, tl, i32)
DEF_HELPER_3(outw, void, env, tl, i32)
DEF_HELPER_3(outd, void, env, tl, i64)
DEF_HELPER_2(mmu_ind, i64, env, tl)
DEF_HELPER_3(mmu_outd, void, env, tl, i64)
#endif
DEF_HELPER_4(call, void, env, i64, int, tl)
DEF_HELPER_2(prep_return, i64, env, int)
DEF_HELPER_1(return, void, env)
DEF_HELPER_4(setwd, void, env, int, int, int)
DEF_HELPER_FLAGS_4(probe_read_access, TCG_CALL_NO_RWG, int, env, tl, int, int)
DEF_HELPER_FLAGS_4(probe_write_access, TCG_CALL_NO_RWG, int, env, tl, int, int)
DEF_HELPER_1(aau_load_program, void, env)
DEF_HELPER_6(mova_ptr, tl, env, int, int, int, 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)
DEF_HELPER_2(getsp, i64, env, i32)
DEF_HELPER_FLAGS_2(state_reg_get, TCG_CALL_NO_WG_SE, i64, env, int)
DEF_HELPER_3(state_reg_set, void, env, i64, int)
DEF_HELPER_FLAGS_2(sxt, TCG_CALL_NO_RWG_SE, i64, i32, i32)
DEF_HELPER_FLAGS_2(clmull, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(clmulh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
/* Packed Min/Max */
DEF_HELPER_FLAGS_2(pminub, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pminsb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pminuh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pminsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pminuw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pminsw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmaxub, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmaxsb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmaxuh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmaxsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmaxuw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmaxsw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
/* Packed Cmp */
DEF_HELPER_FLAGS_2(pcmpeqb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pcmpeqh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pcmpeqw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pcmpeqd, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pcmpgtb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pcmpgth, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pcmpgtw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pcmpgtd, TCG_CALL_NO_RWG_SE, i64, i64, i64)
/* Pached Horizontal Add */
DEF_HELPER_FLAGS_2(phaddh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(phaddw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(phaddsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_3(qphaddh, TCG_CALL_NO_RWG, void, vec, vec, vec)
DEF_HELPER_FLAGS_3(qphaddw, TCG_CALL_NO_RWG, void, vec, vec, vec)
DEF_HELPER_FLAGS_3(qphaddsh, TCG_CALL_NO_RWG, void, vec, vec, vec)
/* Packed Horizontal Sub */
DEF_HELPER_FLAGS_2(phsubh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(phsubw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(phsubsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_3(qphsubh, TCG_CALL_NO_RWG, void, vec, vec, vec)
DEF_HELPER_FLAGS_3(qphsubw, TCG_CALL_NO_RWG, void, vec, vec, vec)
DEF_HELPER_FLAGS_3(qphsubsh, TCG_CALL_NO_RWG, void, vec, vec, vec)
/* Packed Add using saturation */
DEF_HELPER_FLAGS_2(paddsb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(paddsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(paddusb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(paddush, TCG_CALL_NO_RWG_SE, i64, i64, i64)
/* Packed Sub using saturation */
DEF_HELPER_FLAGS_2(psubsb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psubsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psubusb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psubush, TCG_CALL_NO_RWG_SE, i64, i64, i64)
/* Packed shifts */
DEF_HELPER_FLAGS_2(psllh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psllw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pslld, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psrlh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psrlw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psrld, TCG_CALL_NO_RWG_SE, i64, i64, i64)
/* Packed shifts with sign */
DEF_HELPER_FLAGS_2(psrah, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psraw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
/* Packed Mul */
DEF_HELPER_FLAGS_2(pmaddh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmaddubsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmulhh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmullh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmulhuh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmulubhh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmulhrsh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
/* Packed Sign Mul */
DEF_HELPER_FLAGS_2(psignb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psignh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(psignw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
/* Packed Move Mask */
DEF_HELPER_FLAGS_2(pmovmskb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmovmskps, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pmovmskpd, TCG_CALL_NO_RWG_SE, i64, i64, i64)
/* Packed packs */
DEF_HELPER_FLAGS_2(packsshb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(packushb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(packsswh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(packuswh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
/* Packed unpacks */
DEF_HELPER_FLAGS_2(punpcklbh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(punpcklhw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(punpcklwd, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(punpckhbh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(punpckhhw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(punpckhwd, TCG_CALL_NO_RWG_SE, i64, i64, i64)
/* Packed shuffle */
DEF_HELPER_FLAGS_3(pshufb, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64)
DEF_HELPER_FLAGS_3(pmerge, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64)
DEF_HELPER_FLAGS_2(pshufh, TCG_CALL_NO_RWG_SE, i64, i64, i32)
DEF_HELPER_FLAGS_3(pshufw, TCG_CALL_NO_RWG_SE, i64, i64, i64, i32)
/* Packed uncategorized */
DEF_HELPER_FLAGS_2(psadbw, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pavgusb, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(pavgush, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(phminposuh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(mpsadbh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_4(plog, TCG_CALL_NO_RWG_SE, i64, i32, i64, i64, i64)
DEF_HELPER_FLAGS_3(qpmpsadbh, TCG_CALL_NO_RWG, void, vec, vec, i32)
DEF_HELPER_FLAGS_3(qpmulubhh, TCG_CALL_NO_RWG, void, vec, i64, vec)
DEF_HELPER_FLAGS_2(qphminposuh, TCG_CALL_NO_RWG_SE, i64, vec, vec)
DEF_HELPER_FLAGS_1(qpsgn2mskb, TCG_CALL_NO_RWG_SE, i32, vec)
DEF_HELPER_FLAGS_3(qpmsk2sgnb, TCG_CALL_NO_RWG, void, vec, vec, i32)
DEF_HELPER_FLAGS_4(qppermb, TCG_CALL_NO_RWG, void, vec, vec, vec, vec)
DEF_HELPER_FLAGS_4(qpshufb, TCG_CALL_NO_RWG, void, vec, vec, vec, vec)
/* Float 32/64 Ops */
DEF_HELPER_FLAGS_3(fadds, TCG_CALL_NO_RWG, i32, env, i32, i32)
DEF_HELPER_FLAGS_3(fsubs, TCG_CALL_NO_RWG, i32, env, i32, i32)
DEF_HELPER_FLAGS_3(fmuls, TCG_CALL_NO_RWG, i32, env, i32, i32)
DEF_HELPER_FLAGS_3(fdivs, TCG_CALL_NO_RWG, i32, env, i32, i32)
DEF_HELPER_FLAGS_3(fmins, TCG_CALL_NO_RWG, i32, env, i32, i32)
DEF_HELPER_FLAGS_3(fmaxs, TCG_CALL_NO_RWG, i32, env, i32, i32)
DEF_HELPER_FLAGS_3(fscales, TCG_CALL_NO_RWG, i32, env, i32, i32)
DEF_HELPER_FLAGS_3(faddd, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(fsubd, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(fmuld, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(fdivd, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(fmind, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(fmaxd, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(fscaled, TCG_CALL_NO_RWG, i64, env, i64, i32)
DEF_HELPER_FLAGS_2(frcps, TCG_CALL_NO_RWG, i32, env, i32)
DEF_HELPER_FLAGS_2(fsqrts, TCG_CALL_NO_RWG, i32, env, i32)
DEF_HELPER_FLAGS_2(frsqrts, TCG_CALL_NO_RWG, i32, env, i32)
DEF_HELPER_FLAGS_3(fsqrttd, TCG_CALL_NO_RWG, i64, env, i64, i64)
/* Packed Float ops */
DEF_HELPER_FLAGS_3(pfadds, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(pfsubs, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(pfmuls, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(pfmaxs, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(pfmins, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(pfhadds, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(pfhsubs, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(pfaddsubs, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_4(qpfhadds, TCG_CALL_NO_RWG, void, vec, env, vec, vec)
DEF_HELPER_FLAGS_4(qpfhsubs, TCG_CALL_NO_RWG, void, vec, env, vec, vec)
DEF_HELPER_FLAGS_3(pfstoifs, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_2(pistofs, TCG_CALL_NO_RWG, i64, env, i64)
DEF_HELPER_FLAGS_2(pfstois, TCG_CALL_NO_RWG, i64, env, i64)
DEF_HELPER_FLAGS_2(pfstoistr, TCG_CALL_NO_RWG, i64, env, i64)
DEF_HELPER_FLAGS_3(qpfstoid, TCG_CALL_NO_RWG, void, vec, env, i64)
DEF_HELPER_FLAGS_3(qpfstoidtr, TCG_CALL_NO_RWG, void, vec, env, i64)
DEF_HELPER_FLAGS_3(qpistofd, TCG_CALL_NO_RWG, void, vec, env, i64)
DEF_HELPER_FLAGS_3(qpfstofd, TCG_CALL_NO_RWG, void, vec, env, i64)
DEF_HELPER_FLAGS_2(qpfdtois, TCG_CALL_NO_RWG, i64, env, vec)
DEF_HELPER_FLAGS_2(qpfdtoistr, TCG_CALL_NO_RWG, i64, env, vec)
DEF_HELPER_FLAGS_2(qpidtofs, TCG_CALL_NO_RWG, i64, env, vec)
DEF_HELPER_FLAGS_2(qpfdtofs, TCG_CALL_NO_RWG, i64, env, vec)
DEF_HELPER_FLAGS_3(pfcmpeqs, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(pfcmplts, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(pfcmples, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(pfcmpuods, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(pfcmpneqs, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(pfcmpnlts, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(pfcmpnles, TCG_CALL_NO_RWG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(pfcmpods, TCG_CALL_NO_RWG, i64, env, i64, i64)
/* FMA */
DEF_HELPER_FLAGS_4(fmas, TCG_CALL_NO_RWG, i32, env, i32, i32, i32)
DEF_HELPER_FLAGS_4(fmss, TCG_CALL_NO_RWG, i32, env, i32, i32, i32)
DEF_HELPER_FLAGS_4(fnmas, TCG_CALL_NO_RWG, i32, env, i32, i32, i32)
DEF_HELPER_FLAGS_4(fnmss, TCG_CALL_NO_RWG, i32, env, i32, i32, i32)
DEF_HELPER_FLAGS_4(fmad, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(fmsd, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(fnmad, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(fnmsd, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_5(qpfmas, TCG_CALL_NO_RWG, void, vec, env, vec, vec, vec)
DEF_HELPER_FLAGS_5(qpfmss, TCG_CALL_NO_RWG, void, vec, env, vec, vec, vec)
DEF_HELPER_FLAGS_5(qpfnmas, TCG_CALL_NO_RWG, void, vec, env, vec, vec, vec)
DEF_HELPER_FLAGS_5(qpfnmss, TCG_CALL_NO_RWG, void, vec, env, vec, vec, vec)
DEF_HELPER_FLAGS_5(qpfmass, TCG_CALL_NO_RWG, void, vec, env, vec, vec, vec)
DEF_HELPER_FLAGS_5(qpfmsas, TCG_CALL_NO_RWG, void, vec, env, vec, vec, vec)
DEF_HELPER_FLAGS_5(qpfmad, TCG_CALL_NO_RWG, void, vec, env, vec, vec, vec)
DEF_HELPER_FLAGS_5(qpfmsd, TCG_CALL_NO_RWG, void, vec, env, vec, vec, vec)
DEF_HELPER_FLAGS_5(qpfnmad, TCG_CALL_NO_RWG, void, vec, env, vec, vec, vec)
DEF_HELPER_FLAGS_5(qpfnmsd, TCG_CALL_NO_RWG, void, vec, env, vec, vec, vec)
DEF_HELPER_FLAGS_5(qpfmasd, TCG_CALL_NO_RWG, void, vec, env, vec, vec, vec)
DEF_HELPER_FLAGS_5(qpfmsad, TCG_CALL_NO_RWG, void, vec, env, vec, vec, vec)
/* Float x80 ops */
#define DEF_FX_OP2(op) \
DEF_HELPER_FLAGS_3(glue(op, ss), TCG_CALL_NO_RWG, i32, env, f80, i32) \
DEF_HELPER_FLAGS_3(glue(op, dd), TCG_CALL_NO_RWG, i64, env, f80, i64) \
DEF_HELPER_FLAGS_4(glue(op, sx), TCG_CALL_NO_RWG, void, f80, env, f80, i32) \
DEF_HELPER_FLAGS_4(glue(op, dx), TCG_CALL_NO_RWG, void, f80, env, f80, i64) \
DEF_HELPER_FLAGS_4(glue(op, xx), TCG_CALL_NO_RWG, void, f80, env, f80, f80) \
DEF_HELPER_FLAGS_3(glue(op, xd), TCG_CALL_NO_RWG, i64, env, f80, f80) \
DEF_HELPER_FLAGS_3(glue(op, xs), TCG_CALL_NO_RWG, i32, env, f80, f80)
DEF_FX_OP2(fxadd)
DEF_FX_OP2(fxsub)
DEF_FX_OP2(fxmul)
DEF_FX_OP2(fxdiv)
#undef DEF_FX_OP2
DEF_HELPER_FLAGS_3(fxdivtss, TCG_CALL_NO_RWG, f32, env, f32, f80)
DEF_HELPER_FLAGS_3(fxdivtdd, TCG_CALL_NO_RWG, f64, env, f64, f80)
DEF_HELPER_FLAGS_4(fxdivtsx, TCG_CALL_NO_RWG, void, f80, env, f32, f80)
DEF_HELPER_FLAGS_4(fxdivtdx, TCG_CALL_NO_RWG, void, f80, env, f64, f80)
DEF_HELPER_FLAGS_3(fxrsubss, TCG_CALL_NO_RWG, i32, env, f80, i32)
DEF_HELPER_FLAGS_3(fxrsubdd, TCG_CALL_NO_RWG, i64, env, f80, i64)
DEF_HELPER_FLAGS_4(fxrsubsx, TCG_CALL_NO_RWG, void, f80, env, f80, i32)
DEF_HELPER_FLAGS_4(fxrsubdx, TCG_CALL_NO_RWG, void, f80, env, f80, i64)
DEF_HELPER_FLAGS_4(fxsqrttsx, TCG_CALL_NO_RWG, void, f80, env, i32, f80)
DEF_HELPER_FLAGS_4(fxsqrttdx, TCG_CALL_NO_RWG, void, f80, env, i64, f80)
DEF_HELPER_FLAGS_4(fxsqrttxx, TCG_CALL_NO_RWG, void, f80, env, f80, f80)
DEF_HELPER_FLAGS_4(fxscalesx, TCG_CALL_NO_RWG, void, f80, env, f80, i32)
DEF_HELPER_FLAGS_3(fxcmpodsf, TCG_CALL_NO_RWG, i32, env, f80, f32)
DEF_HELPER_FLAGS_3(fxcmpudsf, TCG_CALL_NO_RWG, i32, env, f80, f32)
DEF_HELPER_FLAGS_3(fxcmpoddf, TCG_CALL_NO_RWG, i32, env, f80, f64)
DEF_HELPER_FLAGS_3(fxcmpuddf, TCG_CALL_NO_RWG, i32, env, f80, f64)
DEF_HELPER_FLAGS_3(fxcmpodxf, TCG_CALL_NO_RWG, i32, env, f80, f80)
DEF_HELPER_FLAGS_3(fxcmpudxf, TCG_CALL_NO_RWG, i32, env, f80, f80)
/* Float Comparisons */
#define DEF_HELPER_FP_CMP(P, S, R, A, B) \
DEF_HELPER_FLAGS_3(glue(glue(P, cmpeq), S), TCG_CALL_NO_RWG, R, env, A, B) \
DEF_HELPER_FLAGS_3(glue(glue(P, cmpneq), S), TCG_CALL_NO_RWG, R, env, A, B) \
DEF_HELPER_FLAGS_3(glue(glue(P, cmple), S), TCG_CALL_NO_RWG, R, env, A, B) \
DEF_HELPER_FLAGS_3(glue(glue(P, cmpnle), S), TCG_CALL_NO_RWG, R, env, A, B) \
DEF_HELPER_FLAGS_3(glue(glue(P, cmplt), S), TCG_CALL_NO_RWG, R, env, A, B) \
DEF_HELPER_FLAGS_3(glue(glue(P, cmpnlt), S), TCG_CALL_NO_RWG, R, env, A, B) \
DEF_HELPER_FLAGS_3(glue(glue(P, cmpuod), S), TCG_CALL_NO_RWG, R, env, A, B) \
DEF_HELPER_FLAGS_3(glue(glue(P, cmpod), S), TCG_CALL_NO_RWG, R, env, A, B)
DEF_HELPER_FP_CMP(f, s, i32, i32, i32)
DEF_HELPER_FP_CMP(f, d, i64, i64, i64)
DEF_HELPER_FP_CMP(fx, s, i64, f80, i32)
DEF_HELPER_FP_CMP(fx, d, i64, f80, i64)
DEF_HELPER_FP_CMP(fx, x, i64, f80, f80)
#undef DEF_HELPER_FP_CMP
/* Float Flag Comparisons */
DEF_HELPER_FLAGS_3(fcmpodsf, TCG_CALL_NO_RWG, i32, env, i32, i32)
DEF_HELPER_FLAGS_3(fcmpudsf, TCG_CALL_NO_RWG, i32, env, i32, i32)
DEF_HELPER_FLAGS_3(fcmpoddf, TCG_CALL_NO_RWG, i32, env, i64, i64)
DEF_HELPER_FLAGS_3(fcmpuddf, TCG_CALL_NO_RWG, i32, env, i64, i64)
/* Float Conversions */
DEF_HELPER_FLAGS_2(fstofd, TCG_CALL_NO_RWG, i64, env, i32)
DEF_HELPER_FLAGS_3(fstofx, TCG_CALL_NO_RWG, void, f80, env, i32)
DEF_HELPER_FLAGS_2(fdtofs, TCG_CALL_NO_RWG, i32, env, i64)
DEF_HELPER_FLAGS_3(fdtofx, TCG_CALL_NO_RWG, void, f80, env, i64)
DEF_HELPER_FLAGS_2(fxtofs, TCG_CALL_NO_RWG, i32, env, f80)
DEF_HELPER_FLAGS_2(fxtofd, TCG_CALL_NO_RWG, i64, env, f80)
DEF_HELPER_FLAGS_2(istofs, TCG_CALL_NO_RWG, i32, env, i32)
DEF_HELPER_FLAGS_2(istofd, TCG_CALL_NO_RWG, i64, env, i32)
DEF_HELPER_FLAGS_3(istofx, TCG_CALL_NO_RWG, void, f80, env, i32)
DEF_HELPER_FLAGS_2(idtofs, TCG_CALL_NO_RWG, i32, env, i64)
DEF_HELPER_FLAGS_2(idtofd, TCG_CALL_NO_RWG, i64, env, i64)
DEF_HELPER_FLAGS_3(idtofx, TCG_CALL_NO_RWG, void, f80, env, i64)
DEF_HELPER_FLAGS_2(fstois, TCG_CALL_NO_RWG, i32, env, i32)
DEF_HELPER_FLAGS_2(fstoid, TCG_CALL_NO_RWG, i64, env, i32)
DEF_HELPER_FLAGS_2(fstoistr, TCG_CALL_NO_RWG, i32, env, i32)
DEF_HELPER_FLAGS_2(fstoidtr, TCG_CALL_NO_RWG, i64, env, i32)
DEF_HELPER_FLAGS_2(fdtois, TCG_CALL_NO_RWG, i32, env, i64)
DEF_HELPER_FLAGS_2(fdtoid, TCG_CALL_NO_RWG, i64, env, i64)
DEF_HELPER_FLAGS_2(fdtoistr, TCG_CALL_NO_RWG, i32, env, i64)
DEF_HELPER_FLAGS_2(fdtoidtr, TCG_CALL_NO_RWG, i64, env, i64)
DEF_HELPER_FLAGS_2(fxtois, TCG_CALL_NO_RWG, i32, env, f80)
DEF_HELPER_FLAGS_2(fxtoistr, TCG_CALL_NO_RWG, i32, env, f80)
DEF_HELPER_FLAGS_2(fxtoid, TCG_CALL_NO_RWG, i64, env, f80)
DEF_HELPER_FLAGS_2(fxtoidtr, TCG_CALL_NO_RWG, i64, env, f80)
/* Float Rounding */
DEF_HELPER_FLAGS_3(fstoifs, TCG_CALL_NO_RWG, i32, env, i32, i32)
DEF_HELPER_FLAGS_3(fdtoifd, TCG_CALL_NO_RWG, i64, env, i64, i64)

88
target/e2k/helper_aau.c Normal file
View File

@ -0,0 +1,88 @@
#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)
{
s->last_page = 0;
s->last_page_valid = false;
if (pi.fmt != 0) {
s->pi = pi;
s->ldi = 0;
s->cdi = inds[pi.ind];
} 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, EXCP_ILLEGAL_OPCODE);
}
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, int ind,
int size, int mmu_idx)
{
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];
target_ulong addr = aad.base + as->cdi + instr.disp + ind;
target_ulong page = addr & TARGET_PAGE_MASK;
if (addr & (size - 1)) {
return 0;
} else if (page != as->last_page) {
void *ignore;
int flags;
flags = probe_access_flags(env, page, MMU_DATA_LOAD, mmu_idx,
true, &ignore, 0);
as->last_page = page;
as->last_page_valid = !(flags & TLB_INVALID_MASK);
}
return as->last_page_valid ? addr : 0;
}
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;
}

608
target/e2k/helper_fpu.c Normal file
View File

@ -0,0 +1,608 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "cpu.h"
#include "helper-tcg.h"
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
static FloatRoundMode rm[] = {
float_round_nearest_even,
float_round_down,
float_round_up,
float_round_to_zero,
};
static inline int fpu_flags(int flags)
{
return (flags & float_flag_invalid ? FP_IE : 0) |
(flags & float_flag_divbyzero ? FP_ZE : 0) |
(flags & float_flag_overflow ? FP_OE : 0) |
(flags & float_flag_underflow ? FP_UE : 0) |
(flags & float_flag_inexact ? FP_PE : 0) |
(flags & float_flag_input_denormal ? FP_DE : 0);
}
static inline void fx_merge_exception_flags(CPUE2KState *env, int old_flags)
{
int new_flags = get_float_exception_flags(&env->fx_status);
float_raise(old_flags, &env->fx_status);
env->fpsr.ef |= fpu_flags(new_flags);
if (env->fpsr.ef & (~env->fpcr.em & FP_EM)) {
env->fpsr.es = 1;
env->fpsr.b = 1;
}
}
static inline void fp_merge_exception_flags(CPUE2KState *env, int old_flags)
{
int new_flags = get_float_exception_flags(&env->fp_status);
float_raise(old_flags, &env->fp_status);
env->pfpfr.ef |= fpu_flags(new_flags);
}
static inline int save_exception_flags(float_status *s)
{
int old_flags = get_float_exception_flags(s);
set_float_exception_flags(0, s);
return old_flags;
}
#define fx_save_exception_flags(e) save_exception_flags(&(e)->fx_status)
#define fp_save_exception_flags(e) save_exception_flags(&(e)->fp_status)
void e2k_update_fx_status(CPUE2KState *env)
{
int x;
set_float_rounding_mode(rm[env->fpcr.rc], &env->fx_status);
switch(env->fpcr.pc) {
case FPCR_PC_XP: x = floatx80_precision_x; break;
case FPCR_PC_DP: x = floatx80_precision_d; break;
case FPCR_PC_SP: x = floatx80_precision_s; break;
case FPCR_PC_RESERVED:
default:
qemu_log_mask(LOG_UNIMP, "unknown precision mode 0x%x\n", env->fpcr.pc);
abort();
}
set_floatx80_rounding_precision(x, &env->fx_status);
}
void e2k_update_fp_status(CPUE2KState *env)
{
set_float_rounding_mode(rm[env->pfpfr.rc], &env->fp_status);
}
#define TOIF_RC_CURRENT 0x4
#define TOIF_RC_IGNORE_INEXACT 0x8
static inline void toif_set_round_mode(uint32_t flags, float_status *s)
{
if ((flags & TOIF_RC_CURRENT) == 0) {
set_float_rounding_mode(rm[flags & FP_RC_CHOP], s);
}
}
static inline void toif_clear_inexact(uint32_t flags, float_status *s)
{
if(flags & TOIF_RC_IGNORE_INEXACT) {
int new_flags = get_float_exception_flags(s);
new_flags = new_flags & (~float_flag_inexact);
set_float_exception_flags(new_flags, s);
}
}
#ifdef TARGET_E2K_PRECISE_FSQRTID
uint64 HELPER(fsqrtid)(CPUE2KState *env, uint64_t x)
{
#error implement
return x;
}
#endif
#define IMPL_FSCALE(name, ty, exp_len, exp_off, mul, cvt) \
ty HELPER(name)(CPUE2KState *env, ty src1, uint32_t src2) \
{ \
int32_t p = (int32_t) src2; \
ty max = (1 << exp_len) - 1; \
int32_t bias = max >> 1; \
ty exp; \
ty m = 0; \
if (p <= -bias) { \
exp = 0; \
p += bias + exp_off - 1; \
if (p >= 0 && p < exp_off) { \
m = 1ULL << p; \
} else { \
m = p == -1; \
} \
} else if (p > bias) { \
exp = max; \
} else { \
exp = bias + p; \
} \
ty s2 = (exp << exp_off) | m; \
return mul(env, src1, s2); \
}
IMPL_FSCALE(fscaled, uint64_t, 11, 52, helper_fmuld, uint64_to_float64)
IMPL_FSCALE(fscales, uint32_t, 8, 23, helper_fmuls, uint32_to_float32)
void HELPER(fxscalesx)(floatx80 *r, CPUE2KState *env, floatx80 *a, uint32_t b)
{
floatx80 v;
int32_t p = (int32_t) b;
uint16_t max = (1 << 15) - 1;
int16_t bias = max >> 1;
if (p <= -bias) {
v.high = 0;
p += bias + 62;
if (p >= 0 && p < 63) {
v.low = 1ULL << p;
} else {
v.low = p == -1;
}
} else if (p > bias) {
v.low = 1UL << 63;
v.high = max;
} else {
v.low = 1UL << 63;
v.high = bias + p;
}
helper_fxmulxx(r, env, a, &v);
}
#define type_name_i32 int32
#define type_name_i64 int64
#define type_name_f32 float32
#define type_name_f64 float64
#define type_name_f80 floatx80
#define type_name(S) glue(type_name_, S)
#define arg_type_i32 uint32_t
#define arg_type_i64 uint64_t
#define arg_type_f32 uint32_t
#define arg_type_f64 uint64_t
#define arg_type_f80 floatx80 *
#define arg_type(S) glue(arg_type_, S)
#define ret_arg_i32
#define ret_arg_i64
#define ret_arg_f32
#define ret_arg_f64
#define ret_arg_f80 floatx80 *ret,
#define ret_arg(S) glue(ret_arg_, S)
#define ret_type_i32 uint32_t
#define ret_type_i64 uint64_t
#define ret_type_f32 uint32_t
#define ret_type_f64 uint64_t
#define ret_type_f80 void
#define ret_type(S) glue(ret_type_, S)
#define make_i32(v) (v)
#define make_i64(v) (v)
#define make_f32(v) make_float32(v)
#define make_f64(v) make_float64(v)
#define make_f80(v) (*(v))
#define make(S, v) glue(make_, S)(v)
#define float_val_f32(v) float32_val(v)
#define float_val_f64(v) float64_val(v)
#define float_val(S, v) glue(float_val_, S)(v)
#define type_i32 uint32_t
#define type_i64 uint64_t
#define type_f32 float32
#define type_f64 float64
#define type_f80 floatx80
#define type(S) glue(type_, S)
#define int32_to_int32(v, s) (v)
#define int64_to_int64(v, s) (v)
#define float32_to_float32(v, s) (v)
#define float64_to_float64(v, s) (v)
#define floatx80_to_floatx80(v, s) (v)
#define convert(F, T, v, s) glue3(type_name(F), _to_, type_name(T))(v, s)
#define ret_i32(v) return (v)
#define ret_i64(v) return (v)
#define ret_f32(v) return float32_val(v)
#define ret_f64(v) return float64_val(v)
#define ret_f80(v) *ret = v
#define ret(S, v) glue(ret_, S)(v)
#define fpu_mov(x, s) (x)
#define ident(x) (x)
#define not(x) (!(x))
#define IMPL_ALOPF2_FPU_BASIC(FPU, name, S2, R, T2, TR, op) \
ret_type(R) HELPER(name)(ret_arg(R) CPUE2KState *env, arg_type(S2) s2) \
{ \
int old_flags = glue(FPU, _save_exception_flags)(env); \
float_status *s = &env->glue(FPU, _status); \
type(T2) t2 = convert(S2, T2, make(S2, s2), s); \
type(TR) tr = op(t2, s); \
type(R) r = convert(TR, R, tr, s); \
glue(FPU, _merge_exception_flags)(env, old_flags); \
ret(R, r); \
}
#define IMPL_ALOPF2_FPU(FPU, name, S2, R, op) \
IMPL_ALOPF2_FPU_BASIC(FPU, name, S2, R, S2, R, op)
#define IMPL_ALOPF2_FP(name, S2, R, op) \
IMPL_ALOPF2_FPU_BASIC(fp, name, R, S2, R, S2, op)
#define IMPL_ALOPF2_FPU_CVT_OP(FPU, name, S2, R, op) \
ret_type(R) HELPER(name)(ret_arg(R) CPUE2KState *env, arg_type(S2) s2) \
{ \
int old_flags = glue(FPU, _save_exception_flags)(env); \
float_status *s = &env->glue(FPU, _status); \
type(R) r = op(make(S2, s2), s); \
glue(FPU, _merge_exception_flags)(env, old_flags); \
ret(R, r); \
}
#define IMPL_ALOPF2_FPU_CVT(FPU, name, S2, R) \
ret_type(R) HELPER(name)(ret_arg(R) CPUE2KState *env, arg_type(S2) s2) \
{ \
int old_flags = glue(FPU, _save_exception_flags)(env); \
float_status *s = &env->glue(FPU, _status); \
type(R) r = convert(S2, R, make(S2, s2), s); \
glue(FPU, _merge_exception_flags)(env, old_flags); \
ret(R, r); \
}
#define IMPL_ALOPF1_FPU(FPU, name, S1, S2, R, T1, T2, TR, op) \
ret_type(R) HELPER(name)(ret_arg(R) CPUE2KState *env, \
arg_type(S1) s1, arg_type(S2) s2) \
{ \
int old_flags = glue(FPU, _save_exception_flags)(env); \
float_status *s = &env->glue(FPU, _status); \
type(T1) t1 = convert(S1, T1, make(S1, s1), s); \
type(T2) t2 = convert(S2, T2, make(S2, s2), s); \
type(TR) tr = op(t1, t2, s); \
type(R) r = convert(TR, R, tr, s); \
glue(FPU, _merge_exception_flags)(env, old_flags); \
ret(R, r); \
}
#define IMPL_ALOPF1_FX(name, S1, S2, R, op) \
IMPL_ALOPF1_FPU(fx, name, S1, S2, R, f80, f80, f80, op)
#define IMPL_ALOPF1_FP(name, S1, S2, R, op) \
IMPL_ALOPF1_FPU(fp, name, S1, S2, R, S1, S2, R, op)
#define IMPL_ALOPF1_FPU_CMP_BASIC(FPU, name, S1, S2, R, T1, T2, TR, op1, op2) \
ret_type(R) HELPER(name)(ret_arg(R) CPUE2KState *env, \
arg_type(S1) s1, arg_type(S2) s2) \
{ \
int old_flags = glue(FPU, _save_exception_flags)(env); \
float_status *s = &env->glue(FPU, _status); \
type(T1) t1 = convert(S1, T1, make(S1, s1), s); \
type(T2) t2 = convert(S2, T2, make(S2, s2), s); \
type(TR) tr = op2(op1(t1, t2, s)) ? -1 : 0; \
type(R) r = convert(TR, R, tr, s); \
glue(FPU, _merge_exception_flags)(env, old_flags); \
ret(R, r); \
}
#define IMPL_ALOPF1_FPU_CMP(FPU, name, S1, S2, R, T, op1, op2) \
IMPL_ALOPF1_FPU_CMP_BASIC(FPU, name, S1, S2, R, T, T, R, op1, op2)
#define IMPL_ALOPF1_FP_S(name, S1, S2, R, op) \
ret_type(R) HELPER(name)(CPUE2KState *env, arg_type(S1) s1, \
arg_type(S2) s2) \
{ \
int old_flags = fp_save_exception_flags(env); \
type(R) r = op(R, make(S1, s1), make(S2, s2), &env->fp_status); \
fp_merge_exception_flags(env, old_flags); \
return float_val(R, r); \
}
#define IMPL_ALOPF21_FPU(FPU, name, S1, S2, S3, R, T1, T2, T3, TR, op) \
ret_type(R) HELPER(name)(ret_arg(R) CPUE2KState *env, \
arg_type(S1) s1, arg_type(S2) s2, arg_type(S3) s3) \
{ \
int old_flags = glue(FPU, _save_exception_flags)(env); \
float_status *s = &env->glue(FPU, _status); \
type(T1) t1 = convert(S1, T1, make(S1, s1), s); \
type(T2) t2 = convert(S2, T2, make(S2, s2), s); \
type(T3) t3 = convert(S3, T3, make(S3, s3), s); \
type(TR) tr = op(t1, t2, t3, s); \
type(R) r = convert(TR, R, tr, s); \
glue(FPU, _merge_exception_flags)(env, old_flags); \
ret(R, r); \
}
#define IMPL_ALOPF21_FP(name, T, op) \
IMPL_ALOPF21_FPU(fp, name, T, T, T, T, T, T, T, T, op)
#define IMPL_ALOPF1_FX_MANY(name, op) \
IMPL_ALOPF1_FX(glue3(fx, name, ss), f80, f32, f32, op) \
IMPL_ALOPF1_FX(glue3(fx, name, dd), f80, f64, f64, op) \
IMPL_ALOPF1_FX(glue3(fx, name, sx), f80, f32, f80, op) \
IMPL_ALOPF1_FX(glue3(fx, name, dx), f80, f64, f80, op) \
IMPL_ALOPF1_FX(glue3(fx, name, xx), f80, f80, f80, op) \
IMPL_ALOPF1_FX(glue3(fx, name, xd), f80, f80, f64, op) \
IMPL_ALOPF1_FX(glue3(fx, name, xs), f80, f80, f32, op)
IMPL_ALOPF1_FX_MANY(add, floatx80_add)
IMPL_ALOPF1_FX_MANY(sub, floatx80_sub)
IMPL_ALOPF1_FX_MANY(mul, floatx80_mul)
IMPL_ALOPF1_FX_MANY(div, floatx80_div)
#define floatx80_rsub(x, y, s) floatx80_sub(y, x, s)
IMPL_ALOPF1_FX(fxrsubss, f80, f32, f32, floatx80_rsub)
IMPL_ALOPF1_FX(fxrsubdd, f80, f64, f64, floatx80_rsub)
IMPL_ALOPF1_FX(fxrsubsx, f80, f32, f80, floatx80_rsub)
IMPL_ALOPF1_FX(fxrsubdx, f80, f64, f80, floatx80_rsub)
IMPL_ALOPF1_FX(fxdivtss, f32, f80, f32, floatx80_div)
IMPL_ALOPF1_FX(fxdivtdd, f64, f80, f64, floatx80_div)
IMPL_ALOPF1_FX(fxdivtsx, f32, f80, f80, floatx80_div)
IMPL_ALOPF1_FX(fxdivtdx, f64, f80, f80, floatx80_div)
static floatx80 fxsqrtt(floatx80 a, floatx80 b, float_status *s)
{
// TODO: fxsqrtt
return floatx80_sqrt(a, s);
}
IMPL_ALOPF1_FX(fxsqrttsx, f32, f80, f80, fxsqrtt)
IMPL_ALOPF1_FX(fxsqrttdx, f64, f80, f80, fxsqrtt)
IMPL_ALOPF1_FX(fxsqrttxx, f80, f80, f80, fxsqrtt)
#define CMPODF_BASIC(p, x, y, s) ({ \
uint32_t ret = 0x45; \
if (!glue(p, _is_any_nan)(x) && !glue(p, _is_any_nan)(y)) { \
FloatRelation relation = glue(p, _compare_quiet)(x, y, s); \
switch (relation) { \
case float_relation_greater: ret = 0x00; break; \
case float_relation_less: ret = 0x01; break; \
case float_relation_equal: ret = 0x40; break; \
case float_relation_unordered: ret = 0x45; break; \
} \
} \
ret;\
})
#define FXCMPODF(x, y, s) CMPODF_BASIC(floatx80, x, y, s)
#define FCMPODDF(x, y, s) CMPODF_BASIC(float64, x, y, s)
#define FCMPODSF(x, y, s) CMPODF_BASIC(float32, x, y, s)
// TODO: cmpudf
#define FXCMPUDF FXCMPODF
#define FCMPUDSF FCMPODSF
#define FCMPUDDF FCMPODDF
#define IMPL_CMPF_FX(name, S1, S2, op) \
IMPL_ALOPF1_FPU(fx, name, S1, S2, i32, f80, f80, i32, op)
IMPL_CMPF_FX(fxcmpodsf, f80, f32, FXCMPODF)
IMPL_CMPF_FX(fxcmpoddf, f80, f64, FXCMPODF)
IMPL_CMPF_FX(fxcmpodxf, f80, f80, FXCMPODF)
IMPL_CMPF_FX(fxcmpudsf, f80, f32, FXCMPUDF)
IMPL_CMPF_FX(fxcmpuddf, f80, f64, FXCMPUDF)
IMPL_CMPF_FX(fxcmpudxf, f80, f80, FXCMPUDF)
#define IMPL_CMPF_FP(name, T, R, op) \
IMPL_ALOPF1_FPU(fp, name, T, T, R, T, T, R, op)
IMPL_CMPF_FP(fcmpodsf, f32, i32, FCMPODSF)
IMPL_CMPF_FP(fcmpoddf, f64, i32, FCMPODDF)
IMPL_CMPF_FP(fcmpudsf, f32, i32, FCMPUDSF)
IMPL_CMPF_FP(fcmpuddf, f64, i32, FCMPUDDF)
#define cmp_op(T, op) glue3(type_name(T), _, op)
#define IMPL_ALOPF1_FPU_CMP_ALL(F, P, S, T, R, A, B) \
IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmpeq, S), A, B, R, T, cmp_op(T, eq), ident) \
IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmpneq, S), A, B, R, T, cmp_op(T, eq), not) \
IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmple, S), A, B, R, T, cmp_op(T, le), ident) \
IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmpnle, S), A, B, R, T, cmp_op(T, le), not) \
IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmplt, S), A, B, R, T, cmp_op(T, lt), ident) \
IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmpnlt, S), A, B, R, T, cmp_op(T, lt), not) \
IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmpuod, S), A, B, R, T, cmp_op(T, unordered), ident) \
IMPL_ALOPF1_FPU_CMP(F, glue3(P, cmpod, S), A, B, R, T, cmp_op(T, unordered), not)
IMPL_ALOPF1_FPU_CMP_ALL(fp, f, s, f32, i32, f32, f32)
IMPL_ALOPF1_FPU_CMP_ALL(fp, f, d, f64, i64, f64, f64)
IMPL_ALOPF1_FPU_CMP_ALL(fx, fx, s, f80, i64, f80, f32)
IMPL_ALOPF1_FPU_CMP_ALL(fx, fx, d, f80, i64, f80, f64)
IMPL_ALOPF1_FPU_CMP_ALL(fx, fx, x, f80, i64, f80, f80)
IMPL_ALOPF2_FPU_CVT(fp, fstofd, f32, f64)
IMPL_ALOPF2_FPU_CVT(fx, fstofx, f32, f80)
IMPL_ALOPF2_FPU_CVT(fp, fdtofs, f64, f32)
IMPL_ALOPF2_FPU_CVT(fx, fdtofx, f64, f80)
IMPL_ALOPF2_FPU_CVT(fx, fxtofs, f80, f32)
IMPL_ALOPF2_FPU_CVT(fx, fxtofd, f80, f64)
IMPL_ALOPF2_FPU_CVT(fp, istofs, i32, f32)
IMPL_ALOPF2_FPU_CVT(fp, istofd, i32, f64)
IMPL_ALOPF2_FPU_CVT(fx, istofx, i32, f80)
IMPL_ALOPF2_FPU_CVT(fp, idtofs, i64, f32)
IMPL_ALOPF2_FPU_CVT(fp, idtofd, i64, f64)
IMPL_ALOPF2_FPU_CVT(fx, idtofx, i64, f80)
/*
* I assume e2k behaves like x86.
*
* e2k/x86 mandates that we return the indefinite integer value for the result
* of any float-to-integer conversion that raises the 'invalid' exception.
* Wrap the softfloat functions to get this behaviour.
*/
#define WRAP_F2I(RET, func, T, defval) \
static RET glue(e2k_, func)(T x, float_status *s) \
{ \
int oldflags, newflags; \
RET r; \
\
oldflags = get_float_exception_flags(s); \
set_float_exception_flags(0, s); \
r = func(x, s); \
newflags = get_float_exception_flags(s); \
if (newflags & float_flag_invalid) { \
r = defval; \
} \
set_float_exception_flags(newflags | oldflags, s); \
return r; \
}
WRAP_F2I(int32_t, float32_to_int32, float32, INT32_MIN)
WRAP_F2I(int32_t, float32_to_int32_round_to_zero, float32, INT32_MIN)
WRAP_F2I(int64_t, float32_to_int64, float32, INT64_MIN)
WRAP_F2I(int64_t, float32_to_int64_round_to_zero, float32, INT64_MIN)
WRAP_F2I(int32_t, float64_to_int32, float64, INT32_MIN)
WRAP_F2I(int32_t, float64_to_int32_round_to_zero, float64, INT32_MIN)
WRAP_F2I(int64_t, float64_to_int64, float64, INT64_MIN)
WRAP_F2I(int64_t, float64_to_int64_round_to_zero, float64, INT64_MIN)
WRAP_F2I(int32_t, floatx80_to_int32, floatx80, INT32_MIN)
WRAP_F2I(int32_t, floatx80_to_int32_round_to_zero, floatx80, INT32_MIN)
WRAP_F2I(int64_t, floatx80_to_int64, floatx80, INT64_MIN)
WRAP_F2I(int64_t, floatx80_to_int64_round_to_zero, floatx80, INT64_MIN)
IMPL_ALOPF2_FPU_CVT_OP(fp, fstois, f32, i32, e2k_float32_to_int32)
IMPL_ALOPF2_FPU_CVT_OP(fp, fdtois, f64, i32, e2k_float64_to_int32)
IMPL_ALOPF2_FPU_CVT_OP(fx, fxtois, f80, i32, e2k_floatx80_to_int32)
IMPL_ALOPF2_FPU_CVT_OP(fp, fstoid, f32, i64, e2k_float32_to_int64)
IMPL_ALOPF2_FPU_CVT_OP(fp, fdtoid, f64, i64, e2k_float64_to_int64)
IMPL_ALOPF2_FPU_CVT_OP(fx, fxtoid, f80, i64, e2k_floatx80_to_int64)
IMPL_ALOPF2_FPU_CVT_OP(fp, fstoistr, f32, i32, e2k_float32_to_int32_round_to_zero)
IMPL_ALOPF2_FPU_CVT_OP(fp, fstoidtr, f32, i64, e2k_float32_to_int64_round_to_zero)
IMPL_ALOPF2_FPU_CVT_OP(fp, fdtoistr, f64, i32, e2k_float64_to_int32_round_to_zero)
IMPL_ALOPF2_FPU_CVT_OP(fp, fdtoidtr, f64, i64, e2k_float64_to_int64_round_to_zero)
IMPL_ALOPF2_FPU_CVT_OP(fx, fxtoistr, f80, i32, e2k_floatx80_to_int32_round_to_zero)
IMPL_ALOPF2_FPU_CVT_OP(fx, fxtoidtr, f80, i64, e2k_floatx80_to_int64_round_to_zero)
#define IMPL_FTOIF(name, A, B) \
static type(B) name(type(A) flags, type(B) f, float_status *s) \
{ \
FloatRoundMode oldrm = get_float_rounding_mode(s); \
type(B) ret; \
\
toif_set_round_mode(flags, s); \
ret = glue(type_name(B), _round_to_int)(f, s); \
set_float_rounding_mode(oldrm, s); \
toif_clear_inexact(flags, s); \
return ret; \
}
IMPL_FTOIF(fstoifs, i32, f32)
IMPL_FTOIF(fdtoifd, i64, f64)
IMPL_ALOPF1_FP(fstoifs, i32, f32, f32, fstoifs)
IMPL_ALOPF1_FP(fdtoifd, i64, f64, f64, fdtoifd)
/* TODO: frcps: test if valid, test exception flags */
#define frcps(a, s) float32_div(float32_one, a, s)
#define frsqrts(a, s) float32_div(float32_one, float32_sqrt(a, s), s)
static float64 fsqrttd(float64 a, float64 b, float_status *s)
{
// TODO: fxsqrtt
return float64_sqrt(a, s);
}
/*
* I assume e2k behaves like x86.
*
* Note that the choice of comparison op here is important to get the
* special cases right: for min and max Intel specifies that (-0,0),
* (NaN, anything) and (anything, NaN) return the second argument.
*/
#define FPU_MIN(T, a, b, s) \
(glue(type_name(T), _lt)(a, b, s) ? (a) : (b))
#define FPU_MAX(T, a, b, s) \
(glue(type_name(T), _lt)(b, a, s) ? (a) : (b))
#define IMPL_ALOPF1_FP_MANY(S, T) \
IMPL_ALOPF1_FP(glue(fadd, S), T, T, T, glue(type_name(T), _add)) \
IMPL_ALOPF1_FP(glue(fsub, S), T, T, T, glue(type_name(T), _sub)) \
IMPL_ALOPF1_FP(glue(fmul, S), T, T, T, glue(type_name(T), _mul)) \
IMPL_ALOPF1_FP(glue(fdiv, S), T, T, T, glue(type_name(T), _div)) \
IMPL_ALOPF1_FP_S(glue(fmin, S), T, T, T, FPU_MIN) \
IMPL_ALOPF1_FP_S(glue(fmax, S), T, T, T, FPU_MAX)
IMPL_ALOPF1_FP_MANY(s, f32)
IMPL_ALOPF1_FP_MANY(d, f64)
IMPL_ALOPF2_FP(fsqrts, f32, f32, float32_sqrt)
IMPL_ALOPF2_FP(frcps, f32, f32, frcps)
IMPL_ALOPF2_FP(frsqrts, f32, f32, frsqrts)
IMPL_ALOPF1_FP(fsqrttd, f64, f64, f64, fsqrttd)
#define FMA(T, x, y, z, f, s) \
glue(type_name(T), _muladd)(x, y, z, f, s)
#define FMAS(x, y, z, s) FMA(f32, x, y, z, 0, s)
#define FMAD(x, y, z, s) FMA(f64, x, y, z, 0, s)
#define FMSS(x, y, z, s) FMA(f32, x, y, z, float_muladd_negate_c, s)
#define FMSD(x, y, z, s) FMA(f64, x, y, z, float_muladd_negate_c, s)
#define FNMAS(x, y, z, s) FMA(f32, x, y, z, float_muladd_negate_product, s)
#define FNMAD(x, y, z, s) FMA(f64, x, y, z, float_muladd_negate_product, s)
#define FNMSS(x, y, z, s) FMA(f32, x, y, z, float_muladd_negate_product | float_muladd_negate_c, s)
#define FNMSD(x, y, z, s) FMA(f64, x, y, z, float_muladd_negate_product | float_muladd_negate_c, s)
IMPL_ALOPF21_FP(fmas, f32, FMAS)
IMPL_ALOPF21_FP(fmss, f32, FMSS)
IMPL_ALOPF21_FP(fnmas, f32, FNMAS)
IMPL_ALOPF21_FP(fnmss, f32, FNMSS)
IMPL_ALOPF21_FP(fmad, f64, FMAD)
IMPL_ALOPF21_FP(fmsd, f64, FMSD)
IMPL_ALOPF21_FP(fnmad, f64, FNMAD)
IMPL_ALOPF21_FP(fnmsd, f64, FNMSD)
#define qp_len_uw 4
#define qp_len_ud 2
#define qp_len(T) glue(qp_len_, T)
#define IMPL_OP3_QP_ENV(name, T, F, code) \
void HELPER(name)(E2KReg *r, CPUE2KState *env, E2KReg *s1, \
E2KReg *s2, E2KReg *s3) \
{ \
int old_flags = fp_save_exception_flags(env); \
int i; \
\
for (i = 0; i < qp_len(T); i++) { \
type(F) a = make(F, s1->T[i]); \
type(F) b = make(F, s2->T[i]); \
type(F) c = make(F, s3->T[i]); \
{ code; } \
} \
\
fp_merge_exception_flags(env, old_flags); \
}
#define IMPL_OP3_QP_ENV_OP(name, T, F, op) \
IMPL_OP3_QP_ENV(name, T, F, { \
r->T[i] = float_val(F, op(a, b, c, &env->fp_status)); \
})
IMPL_OP3_QP_ENV_OP(qpfmas, uw, f32, FMAS)
IMPL_OP3_QP_ENV_OP(qpfmss, uw, f32, FMSS)
IMPL_OP3_QP_ENV_OP(qpfnmas, uw, f32, FNMAS)
IMPL_OP3_QP_ENV_OP(qpfnmss, uw, f32, FNMSS)
IMPL_OP3_QP_ENV_OP(qpfmad, ud, f64, FMAD)
IMPL_OP3_QP_ENV_OP(qpfmsd, ud, f64, FMSD)
IMPL_OP3_QP_ENV_OP(qpfnmad, ud, f64, FNMAD)
IMPL_OP3_QP_ENV_OP(qpfnmsd, ud, f64, FNMSD)
#define IMPL_OP3_QP_ENV_OP_ALT(name, T, F, op1, op2) \
IMPL_OP3_QP_ENV(name, T, F, { \
r->T[i] = float_val(F, i & 1 ? op2(a, b, c, &env->fp_status) : \
op1(a, b, c, &env->fp_status)); \
})
IMPL_OP3_QP_ENV_OP_ALT(qpfmass, uw, f32, FMAS, FMSS)
IMPL_OP3_QP_ENV_OP_ALT(qpfmsas, uw, f32, FMSS, FMAS)
IMPL_OP3_QP_ENV_OP_ALT(qpfmasd, ud, f64, FMAD, FMSD)
IMPL_OP3_QP_ENV_OP_ALT(qpfmsad, ud, f64, FMSD, FMAD)

355
target/e2k/helper_int.c Normal file
View File

@ -0,0 +1,355 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "cpu.h"
#include "helper-tcg.h"
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
uint64_t HELPER(sxt)(uint32_t s1, uint32_t s2)
{
int size = MIN(32, 8 << (s1 & 3));
return s1 & 4 ? extract32(s2, 0, size) : sextract64(s2, 0, size);
}
static uint64_t cr_read(CPUE2KState *env, size_t offset)
{
target_ulong addr = env->pcsp.base + env->pcsp.index + offset;
return cpu_ldq_le_data(env, addr);
}
static void cr_write(CPUE2KState *env, size_t offset, uint64_t data)
{
target_ulong addr = env->pcsp.base + env->pcsp.index + offset;
cpu_stq_le_data(env, addr, data);
}
uint64_t HELPER(state_reg_get)(CPUE2KState *env, int index)
{
switch (index) {
case SR_PSR: return env->psr;
case SR_WD: return env_wd_get(env);
case SR_CORE_MODE: return env->core_mode;
case SR_CWD: return 0; /* ignore */
case SR_PSP_HI: return env->psp.hi;
case SR_PSP_LO: return env->psp.lo;
case SR_PSHTP: return 0; /* ignore */
case SR_PCSP_HI: return env->pcsp.hi;
case SR_PCSP_LO: return env->pcsp.lo;
case SR_PCSHTP: return 0; /* ignore */
case SR_CTPR1: return env->ctprs[0].raw;
case SR_CTPR2: return env->ctprs[1].raw;
case SR_CTPR3: return env->ctprs[2].raw;
case SR_SBR: return env->sbr;
case SR_CUTD:
case SR_EIR:
case SR_TSD: goto todo;
case SR_CUIR: return env->cuir;
case SR_OSCUD_HI: return env->oscud.hi;
case SR_OSCUD_LO: return env->oscud.lo;
case SR_OSGD_HI: return env->osgd.hi;
case SR_OSGD_LO: return env->osgd.lo;
case SR_OSEM: goto todo;
case SR_USD_HI: return env->usd.hi;
case SR_USD_LO: return env->usd.lo;
case SR_TR: goto todo;
case SR_OSR0: return env->osr0;
case SR_CUD_HI: return env->cud.hi;
case SR_CUD_LO: return env->cud.lo;
case SR_GD_HI: return env->gd.hi;
case SR_GD_LO: return env->gd.lo;
case SR_CS_HI: return env->cs.hi;
case SR_CS_LO: return env->cs.lo;
case SR_DS_HI: return env->ds.hi;
case SR_DS_LO: return env->ds.lo;
case SR_ES_HI: return env->es.hi;
case SR_ES_LO: return env->es.lo;
case SR_FS_HI: return env->fs.hi;
case SR_FS_LO: return env->fs.lo;
case SR_GS_HI: return env->gs.hi;
case SR_GS_LO: return env->gs.lo;
case SR_SS_HI: return env->ss.hi;
case SR_SS_LO: return env->ss.lo;
case SR_DIBCR:
case SR_DIMCR:
case SR_DIBSR:
case SR_DTCR:
case SR_DIBAR0:
case SR_DIBAR1:
case SR_DIBAR2:
case SR_DIBAR3:
case SR_DIMAR0:
case SR_DIMAR1:
case SR_DTRAF:
case SR_DTART: goto todo;
case SR_CR0_HI: return cr_read(env, offsetof(E2KCrs, cr0_hi));
case SR_CR0_LO: return cr_read(env, offsetof(E2KCrs, cr0_lo));
case SR_CR1_HI: return cr_read(env, offsetof(E2KCrs, cr1.hi));
case SR_CR1_LO: return cr_read(env, offsetof(E2KCrs, cr1.lo));
case SR_SCLKM1:
case SR_SCLKM2:
case SR_CU_HW0: goto todo;
case SR_UPSR: return env->upsr;
case SR_IP: return env->ip;
case SR_NIP: return env->nip;
case SR_LSR: return env_lsr_get(env);
case SR_PFPFR: return env->pfpfr.raw;
case SR_FPCR: return env->fpcr.raw;
case SR_FPSR: return env->fpsr.raw;
case SR_ILCR: return env_ilcr_get(env);
case SR_BR: return env_br_get(env);
case SR_BGR: return env->bgr;
case SR_IDR: return env->idr;
case SR_CLKR: return cpu_get_host_ticks(); // FIXME
case SR_RNDPR:
case SR_SCLKR:
case SR_TIR_HI:
case SR_TIR_LO:
case SR_RPR:
case SR_SBBP:
case SR_RPR_HI:
case SR_UPSRM: goto todo;
case SR_LSR1: return env->lsr_lcnt;
case SR_ILCR1: return env->ilcr_lcnt;
default:
/* The index is checked during translation. */
g_assert_not_reached();
break;
}
todo:
qemu_log("reading a state register %#x is not implemented\n", index);
return 0;
}
#define CASE_RWAP_SET(e, f) \
case glue(e, _HI): \
env->f.hi = value; \
break; \
case glue(e, _LO): \
env->f.lo = value & E2K_RWAP_LO_MASK; \
break;
void HELPER(state_reg_set)(CPUE2KState *env, uint64_t value, int index)
{
switch (index) {
case SR_UPSR:
case SR_LSR:
case SR_ILCR:
case SR_PFPFR:
case SR_FPCR:
case SR_FPSR:
case SR_SCLKR:
case SR_TIR_HI:
case SR_TIR_LO:
case SR_RPR:
case SR_SBBP:
case SR_RPR_HI:
case SR_UPSRM:
case SR_LSR1:
case SR_ILCR1:
break;
case SR_CUIR:
raise_exception(env, EXCP_ILLEGAL_OPCODE); /* FIXME */
break;
default:
if ((env->psr & PSR_PM) == 0) {
raise_exception(env, EXCP_PRIV_ACTION);
}
break;
}
switch (index) {
case SR_PSR:
env->psr = value & PSR_MASK;
break;
case SR_WD:
env_wd_set(env, value);
break;
case SR_CORE_MODE:
// FIXME: core_mode
qemu_log("FIXME: core_mode is set to %#lx\n", value);
env->core_mode = value;
break;
case SR_CWD:
/* ignore */
break;
case SR_PSP_HI:
env->psp.hi = value;
break;
case SR_PSP_LO:
env->psp.lo = value & E2K_PSP_LO_MASK;
break;
case SR_PSHTP:
/* ignore */
break;
case SR_PCSP_HI:
env->pcsp.hi = value;
break;
case SR_PCSP_LO:
env->pcsp.lo = value & E2K_PSP_LO_MASK;
break;
case SR_PCSHTP:
/* ignore */
break;
case SR_CTPR1:
env->ctprs[0].raw = value;
break;
case SR_CTPR2:
env->ctprs[1].raw = value;
break;
case SR_CTPR3:
env->ctprs[2].raw = value;
break;
case SR_SBR:
env->sbr = value;
break;
case SR_CUTD:
case SR_EIR:
case SR_TSD:
goto todo;
case SR_CUIR:
env->cuir = value & CUIR_MASK;
break;
case SR_OSEM:
case SR_TR:
goto todo;
case SR_OSR0:
env->osr0 = value;
break;
CASE_RWAP_SET(SR_OSCUD, oscud)
CASE_RWAP_SET(SR_OSGD, osgd)
CASE_RWAP_SET(SR_USD, usd)
CASE_RWAP_SET(SR_CUD, cud)
CASE_RWAP_SET(SR_GD, gd)
CASE_RWAP_SET(SR_CS, cs)
CASE_RWAP_SET(SR_DS, ds)
CASE_RWAP_SET(SR_ES, es)
CASE_RWAP_SET(SR_FS, fs)
CASE_RWAP_SET(SR_GS, gs)
CASE_RWAP_SET(SR_SS, ss)
case SR_DIBCR:
case SR_DIMCR:
case SR_DIBSR:
case SR_DTCR:
case SR_DIBAR0:
case SR_DIBAR1:
case SR_DIBAR2:
case SR_DIBAR3:
case SR_DIMAR0:
case SR_DIMAR1:
case SR_DTRAF:
case SR_DTART:
case SR_CR0_HI:
cr_write(env, offsetof(E2KCrs, cr0_hi), value);
break;
case SR_CR0_LO:
cr_write(env, offsetof(E2KCrs, cr0_lo), value);
break;
case SR_CR1_HI:
cr_write(env, offsetof(E2KCrs, cr1.hi), value);
break;
case SR_CR1_LO:
cr_write(env, offsetof(E2KCrs, cr1.lo), value);
break;
case SR_SCLKM1:
case SR_SCLKM2:
case SR_CU_HW0:
goto todo;
case SR_UPSR:
env->upsr = value & UPSR_MASK;
break;
case SR_LSR:
env_lsr_set(env, value);
env_ilcr_set(env, value);
break;
case SR_PFPFR:
env->pfpfr.raw = value;
e2k_update_fp_status(env);
break;
case SR_FPCR:
env->fpcr.raw = value;
e2k_update_fx_status(env);
break;
case SR_FPSR:
env->fpsr.raw = value;
break;
case SR_ILCR:
env->ilcr = (value >> LSR_ECNT_OFF) & ILCR_MASK;
env->ilcr_lcnt = value & GEN_MASK(0, LSR_LCNT_LEN);
break;
case SR_BR:
env_br_set(env, value);
break;
case SR_BGR:
env->bgr = value & BGR_MASK;
break;
case SR_RNDPR:
case SR_SCLKR:
case SR_TIR_HI:
case SR_TIR_LO:
case SR_RPR:
case SR_SBBP:
case SR_RPR_HI:
case SR_UPSRM:
goto todo;
case SR_LSR1:
env->lsr_lcnt = value;
env->ilcr_lcnt = value;
break;
case SR_ILCR1:
env->ilcr_lcnt = value;
break;
default:
/* The index is checked during translation. */
g_assert_not_reached();
break;
}
return;
todo:
qemu_log("write to state register %#x is not implemented\n", index);
}
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;
}
uint64_t HELPER(clmull)(uint64_t s1, uint64_t s2)
{
uint64_t r = 0;
for (; s1; s1 >>= 1, s2 <<= 1) {
r ^= s1 & 1 ? s2 : 0;
}
return r;
}
uint64_t HELPER(clmulh)(uint64_t s1, uint64_t s2)
{
uint64_t r = 0;
for (s2 >>= 1; s1; s1 <<= 1, s2 >>= 1) {
r ^= s1 & (1ULL << 63) ? s2 : 0;
}
return r;
}

39
target/e2k/helper_sm.c Normal file
View File

@ -0,0 +1,39 @@
#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 int e2k_probe_access(CPUE2KState *env, target_ulong addr, int size,
MMUAccessType access_type, int mmu_idx)
{
target_ulong addr_end = addr + size - 1;
int flags;
void *ignore;
flags = probe_access_flags(env, addr, access_type, mmu_idx,
true, &ignore, 0);
if (flags & TLB_INVALID_MASK) {
return 0;
} else if ((addr & TARGET_PAGE_MASK) != (addr_end & TARGET_PAGE_MASK)) {
flags = probe_access_flags(env, addr_end, access_type, mmu_idx, true,
&ignore, 0);
return !(flags & TLB_INVALID_MASK);
}
return 1;
}
int HELPER(probe_read_access)(CPUE2KState *env, target_ulong addr,
int size, int mmu_idx)
{
return e2k_probe_access(env, addr, size, MMU_DATA_LOAD, mmu_idx);
}
int HELPER(probe_write_access)(CPUE2KState *env, target_ulong addr,
int size, int mmu_idx)
{
return e2k_probe_access(env, addr, size, MMU_DATA_STORE, mmu_idx);
}

604
target/e2k/helper_vec.c Normal file
View File

@ -0,0 +1,604 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "cpu.h"
#include "helper-tcg.h"
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.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;
}
#define vec64_ub 8
#define vec64_uh 4
#define vec64_uw 2
#define vec64_ud 1
#define vec64_sb vec64_ub
#define vec64_sh vec64_uh
#define vec64_sw vec64_uw
#define vec64_sd vec64_ud
#define vec64_len(type) glue(vec64_, type)
#define vec128_ub 16
#define vec128_uh 8
#define vec128_uw 4
#define vec128_ud 2
#define vec128_sb vec128_ub
#define vec128_sh vec128_uh
#define vec128_sw vec128_uw
#define vec128_sd vec128_ud
#define vec128_len(type) glue(vec128_, type)
typedef union {
uint8_t ub[vec64_ub];
uint16_t uh[vec64_uh];
uint32_t uw[vec64_uw];
uint64_t ud[vec64_ud];
int8_t sb[vec64_ub];
int16_t sh[vec64_uh];
int32_t sw[vec64_uw];
int64_t sd[vec64_ud];
} vec64;
#define shr16(x) ((x) >> 16)
#define shr14_add1_shr1(x) ((((x) >> 14) + 1) >> 1)
#define and16(x) ((x) & 0xffff)
#define satsb(x) MIN(MAX(x, -128), 127)
#define satsh(x) MIN(MAX(x, -32768), 32767)
#define satub(x) MIN(MAX(x, 0), 255)
#define satuh(x) MIN(MAX(x, 0), 65535)
#define add(a, b) ((a) + (b))
#define sub(a, b) ((a) - (b))
#define mul(a, b) ((a) * (b))
#define div(a, b) ((a) / (b))
#define GEN_HELPER_PACKED_N(name, n, code) \
uint64_t HELPER(name)(uint64_t src1, uint64_t src2) \
{ \
size_t i = 0; \
vec64 s1 = { .ud[0] = src1 }, s2 = { .ud[0] = src2 }; \
vec64 dst = { .ud[0] = 0 }; \
for (; i < n; i++) { \
code \
} \
return dst.ud[0]; \
}
#define GEN_HELPER_PACKED(name, type, code) \
GEN_HELPER_PACKED_N(name, vec64_len(type), code)
#define GEN_HELPER_PACKED_OP(name, type, op) \
GEN_HELPER_PACKED_N(name, vec64_len(type), { \
dst.type[i] = op(s1.type[i], s2.type[i]); \
})
#define GEN_HELPER_PACKED_SCALAR(name, type, code) \
uint64_t HELPER(name)(uint64_t src1, uint64_t s2) \
{ \
size_t i = 0; \
vec64 s1 = { .ud[0] = src1 }, dst = { .ud[0] = 0 }; \
for (; i < glue(vec64_, type); i++) { \
code \
} \
return dst.ud[0]; \
}
#define IMPL_QPACKED_N(name, n, code) \
void HELPER(name)(E2KReg *r, E2KReg *s1, E2KReg *s2) \
{ \
int i; \
\
for (i = 0; i < n; i++) { \
code \
} \
}
#define IMPL_QPACKED(name, type, code) \
IMPL_QPACKED_N(name, vec64_len(type), code)
#define IMPL_QPACKED_OP(name, type, op) \
IMPL_QPACKED_N(name, vec128_len(type), { \
r->type[i] = op(s1->type[i], s2->type[i]); \
})
#define GEN_HELPER_PACKED_MINMAX(name, type, op) \
GEN_HELPER_PACKED_OP(glue(name, type), type, op)
GEN_HELPER_PACKED_MINMAX(pmin, ub, MIN)
GEN_HELPER_PACKED_MINMAX(pmin, sb, MIN)
GEN_HELPER_PACKED_MINMAX(pmin, uh, MIN)
GEN_HELPER_PACKED_MINMAX(pmin, sh, MIN)
GEN_HELPER_PACKED_MINMAX(pmin, uw, MIN)
GEN_HELPER_PACKED_MINMAX(pmin, sw, MIN)
GEN_HELPER_PACKED_MINMAX(pmax, ub, MAX)
GEN_HELPER_PACKED_MINMAX(pmax, sb, MAX)
GEN_HELPER_PACKED_MINMAX(pmax, uh, MAX)
GEN_HELPER_PACKED_MINMAX(pmax, sh, MAX)
GEN_HELPER_PACKED_MINMAX(pmax, uw, MAX)
GEN_HELPER_PACKED_MINMAX(pmax, sw, MAX)
#define GEN_HELPER_PACKED_CMP(name, type, op) \
GEN_HELPER_PACKED(name, type, { \
dst.type[i] = s1.type[i] op s2.type[i] ? -1 : 0; \
})
GEN_HELPER_PACKED_CMP(pcmpeqb, ub, ==)
GEN_HELPER_PACKED_CMP(pcmpeqh, uh, ==)
GEN_HELPER_PACKED_CMP(pcmpeqw, uw, ==)
GEN_HELPER_PACKED_CMP(pcmpeqd, ud, ==)
GEN_HELPER_PACKED_CMP(pcmpgtb, sb, >)
GEN_HELPER_PACKED_CMP(pcmpgth, sh, >)
GEN_HELPER_PACKED_CMP(pcmpgtw, sw, >)
GEN_HELPER_PACKED_CMP(pcmpgtd, sd, >)
#define GEN_HELPER_PACKED_BINOP_MAP(name, type, op, cast, map) \
GEN_HELPER_PACKED(name, type, { \
dst.type[i] = map((cast) s1.type[i] op s2.type[i]); \
})
GEN_HELPER_PACKED_BINOP_MAP(paddsb, sb, +, int16_t, satsb)
GEN_HELPER_PACKED_BINOP_MAP(paddsh, sh, +, int32_t, satsh)
GEN_HELPER_PACKED_BINOP_MAP(paddusb, ub, +, int16_t, satub)
GEN_HELPER_PACKED_BINOP_MAP(paddush, uh, +, int32_t, satuh)
GEN_HELPER_PACKED_BINOP_MAP(psubsb, sb, -, int16_t, satsb)
GEN_HELPER_PACKED_BINOP_MAP(psubsh, sh, -, int32_t, satsh)
GEN_HELPER_PACKED_BINOP_MAP(psubusb, ub, -, int16_t, satub)
GEN_HELPER_PACKED_BINOP_MAP(psubush, uh, -, int32_t, satuh)
#define GEN_HELPER_PACKED_HORIZONTAL_OP(name, type, op, map) \
GEN_HELPER_PACKED_N(name, vec64_len(type) / 2, { \
int j = i * 2; \
dst.type[i ] = map(op(s1.type[j], s1.type[j + 1])); \
dst.type[i + vec64_len(type) / 2] = map(op(s2.type[j], s2.type[j + 1])); \
}) \
IMPL_QPACKED_N(glue(q, name), vec128_len(type) / 2, { \
int j = i * 2; \
r->type[i ] = map(op(s1->type[j], s1->type[j + 1])); \
r->type[i + vec128_len(type) / 2] = map(op(s2->type[j], s2->type[j + 1])); \
})
GEN_HELPER_PACKED_HORIZONTAL_OP(phaddh, sh, add, ident)
GEN_HELPER_PACKED_HORIZONTAL_OP(phaddw, sw, add, ident)
GEN_HELPER_PACKED_HORIZONTAL_OP(phaddsh, sh, add, satsh)
GEN_HELPER_PACKED_HORIZONTAL_OP(phsubh, sh, sub, ident)
GEN_HELPER_PACKED_HORIZONTAL_OP(phsubw, sw, sub, ident)
GEN_HELPER_PACKED_HORIZONTAL_OP(phsubsh, sh, sub, satsh)
#define GEN_HELPER_PACKED_SCALAR_BINOP(name, type, op) \
GEN_HELPER_PACKED_SCALAR(name, type, { \
dst.type[i] = s2 < sizeof(s1.type[0]) * 8 ? s1.type[i] op s2 : 0; \
})
GEN_HELPER_PACKED_SCALAR_BINOP(psllh, uh, <<)
GEN_HELPER_PACKED_SCALAR_BINOP(psllw, uw, <<)
GEN_HELPER_PACKED_SCALAR_BINOP(pslld, ud, <<)
GEN_HELPER_PACKED_SCALAR_BINOP(psrlh, uh, >>)
GEN_HELPER_PACKED_SCALAR_BINOP(psrlw, uw, >>)
GEN_HELPER_PACKED_SCALAR_BINOP(psrld, ud, >>)
#define GEN_HELPER_PACKED_SRA(name, type, t) \
GEN_HELPER_PACKED_SCALAR(name, type, { \
int max = sizeof(s1.type[0]) * 8 - 1; \
dst.type[i] = (t) s1.type[i] >> (s2 < max ? s2 : max); \
})
GEN_HELPER_PACKED_SRA(psrah, sh, int32_t)
GEN_HELPER_PACKED_SRA(psraw, sw, int64_t)
#define GEN_HELPER_PACKED_MAD(name, dst_type, t0, t1, cast, op) \
GEN_HELPER_PACKED(name, dst_type, { \
int j = i * 2; \
dst.dst_type[i] = op( \
(cast) s1.t0[j + 1] * s2.t1[j + 1] + \
(cast) s1.t0[j ] * s2.t1[j ] \
); \
})
GEN_HELPER_PACKED_MAD(pmaddh, sw, sh, sh, int32_t, ident)
GEN_HELPER_PACKED_MAD(pmaddubsh, sh, sb, ub, int32_t, satsh)
GEN_HELPER_PACKED(psadbw, ub, { dst.uw[0] += abs(s1.ub[i] - s2.ub[i]); })
GEN_HELPER_PACKED(pavgusb, ub, { dst.ub[i] = (s1.ub[i] + s2.ub[i] + 1) >> 1; })
GEN_HELPER_PACKED(pavgush, uh, { dst.uh[i] = (s1.uh[i] + s2.uh[i] + 1) >> 1; })
#define GEN_HELPER_PACKED_MULH(name, type, cast, map) \
GEN_HELPER_PACKED(name, type, { \
dst.type[i] = map(((cast) s1.type[i]) * s2.type[i]); \
})
GEN_HELPER_PACKED_MULH(pmulhh, sh, int32_t, shr16)
GEN_HELPER_PACKED_MULH(pmullh, sh, int32_t, and16)
GEN_HELPER_PACKED_MULH(pmulhuh, uh, uint32_t, shr16)
GEN_HELPER_PACKED_MULH(pmulhrsh, sh, int32_t, shr14_add1_shr1)
GEN_HELPER_PACKED(pmulubhh, uh, { \
dst.uh[i] = ((int16_t) s1.ub[i] * s2.sh[i] + 0x80) >> 8; \
})
GEN_HELPER_PACKED(mpsadbh, uh, { \
dst.uh[i] = abs((int16_t) s1.ub[i ] - s2.ub[0]) \
+ abs((int16_t) s1.ub[i + 1] - s2.ub[1]) \
+ abs((int16_t) s1.ub[i + 2] - s2.ub[2]) \
+ abs((int16_t) s1.ub[i + 3] - s2.ub[3]); \
})
#define mul_sign(a, b) ((b) < 0 ? -(a) : ((b) > 0 ? (a) : 0))
GEN_HELPER_PACKED_OP(psignb, sb, mul_sign)
GEN_HELPER_PACKED_OP(psignh, sh, mul_sign)
GEN_HELPER_PACKED_OP(psignw, sw, mul_sign)
#define MOVMASK(mask_type, type) { \
dst.mask_type[0] |= (s1.type[i] < 0) << (i + glue(vec64_, type)); \
dst.mask_type[0] |= (s2.type[i] < 0) << (i ); \
}
GEN_HELPER_PACKED(pmovmskb, sb, MOVMASK(uh, sb))
GEN_HELPER_PACKED(pmovmskps, sw, MOVMASK(ub, sw))
GEN_HELPER_PACKED(pmovmskpd, sd, MOVMASK(ub, sd))
#define PACK(dst_type, type, op) { \
dst.dst_type[i + glue(vec64_, type)] = op(s1.type[i]); \
dst.dst_type[i ] = op(s2.type[i]); \
}
GEN_HELPER_PACKED(packsshb, sh, PACK(sb, sh, satsb))
GEN_HELPER_PACKED(packushb, uh, PACK(ub, sh, satub))
GEN_HELPER_PACKED(packsswh, sw, PACK(sh, sw, satsh))
GEN_HELPER_PACKED(packuswh, sw, PACK(uh, sw, satuh))
#define GEN_HELPER_PACKED_UNPACK(name, type, offset) \
GEN_HELPER_PACKED(name, type, { \
int j = offset + i / 2; \
dst.type[i] = i & 1 ? s1.type[j] : s2.type[j]; \
})
GEN_HELPER_PACKED_UNPACK(punpcklbh, ub, 0)
GEN_HELPER_PACKED_UNPACK(punpcklhw, uh, 0)
GEN_HELPER_PACKED_UNPACK(punpcklwd, uw, 0)
GEN_HELPER_PACKED_UNPACK(punpckhbh, ub, 4)
GEN_HELPER_PACKED_UNPACK(punpckhhw, uh, 2)
GEN_HELPER_PACKED_UNPACK(punpckhwd, uw, 1)
uint64_t HELPER(pshufb)(uint64_t src1, uint64_t src2, uint64_t src3)
{
vec64 ret, s1, s2, s3;
int i;
s1.ud[0] = src1;
s2.ud[0] = src2;
s3.ud[0] = src3;
for (i = 0; i < 8; i++) {
uint8_t desc = s3.ub[i];
int index = desc & 7;
uint8_t byte = desc & 8 ? s1.ub[index] : s2.ub[index];
byte = desc & 0x10 ? ~byte : byte;
byte = desc & 0x20 ? reverse_bits(byte) : byte;
byte = desc & 0x40 ? (byte & 0x80 ? 0xff : 0) : byte;
if (desc & 0x80) {
switch ((desc & 0x70) >> 4) {
case 2: byte = 0x7f; break;
case 4: byte = 0x80; break;
case 6: byte = 0xff; break;
default: byte = 0; break;
}
}
ret.ub[i] = byte;
}
return ret.ud[0];
}
uint64_t HELPER(pmerge)(uint64_t src1, uint64_t src2, uint64_t src3)
{
vec64 r, s1, s2, s3;
int i;
s1.ud[0] = src1;
s2.ud[0] = src2;
s3.ud[0] = src3;
for (i = 0; i < 8; i++) {
r.ub[i] = s3.sb[i] < 0 ? s2.ub[i] : s1.ub[i];
}
return r.ud[0];
}
uint64_t HELPER(pshufh)(uint64_t src1, uint32_t imm8)
{
int i;
vec64 s1 = { .ud[0] = src1 }, dst;
for (i = 0; i < vec64_uh; i++) {
int j = (imm8 >> (i * 2)) & 0x3;
dst.uh[i] = s1.uh[j];
}
return dst.ud[0];
}
uint64_t HELPER(pshufw)(uint64_t src1, uint64_t src2, uint32_t imm8)
{
int i;
vec64 s1 = { .ud[0] = src1 }, s2 = { .ud[0] = src2 }, dst;
for (i = 0; i < vec64_uw; i++) {
int sel = (imm8 >> (i * 2)) & 0x3;
int j = sel & 1;
dst.uw[i] = sel > 1 ? s1.uw[j] : s2.uw[j];
}
return dst.ud[0];
}
uint64_t HELPER(phminposuh)(uint64_t src1, uint64_t src2)
{
int i;
vec64 s1 = { .ud[0] = src1 }, s2 = { .ud[0] = src2 }, dst = { .ud[0] = 0 };
dst.uh[0] = s1.uh[0];
for (i = 0; i < 4; i++) {
if (s1.uh[i] < dst.uh[0]) {
dst.uh[0] = s1.uh[i];
dst.uh[1] = i;
}
}
for (i = 0; i < 4; i++) {
if (s2.uh[i] < dst.uh[0]) {
dst.uh[0] = s2.uh[i];
dst.uh[1] = 4 + i;
}
}
return dst.ud[0];
}
void HELPER(qpmpsadbh)(E2KReg *r, E2KReg *s1, uint32_t s2)
{
r->ud[0] = helper_mpsadbh(s1->ud[0], s2);
r->ud[1] = helper_mpsadbh(s1->ud[1], s2);
}
void HELPER(qpmulubhh)(E2KReg *r, uint64_t s1, E2KReg *s2)
{
r->ud[0] = helper_pmulubhh(s1 , s2->ud[0]);
r->ud[1] = helper_pmulubhh(s1 >> 32, s2->ud[1]);
}
uint64_t HELPER(qphminposuh)(E2KReg *s1, E2KReg *s2)
{
int i;
uint16_t v = s1->uh[0];
uint16_t p = 0;
for (i = 0; i < 8; i++) {
if (s1->uh[i] < v) {
v = s1->uh[i];
p = i;
}
}
for (i = 0; i < 8; i++) {
if (s2->uh[i] < v) {
v = s2->uh[i];
p = 8 + i;
}
}
return ((uint64_t) p << 16) | v;
}
uint32_t HELPER(qpsgn2mskb)(E2KReg *s2)
{
uint32_t r = 0;
int i;
for (i = 0; i < 16; i++) {
r |= s2->sb[i] < 0 ? 1 << i : 0;
}
return r;
}
void HELPER(qpmsk2sgnb)(E2KReg *r, E2KReg *s1, uint32_t s2)
{
int i;
for (i = 0; i < 16; i++) {
r->ub[i] = s2 & (1 << i) ? s1->ub[i] | 0x80 : s1->ub[i] & 0x7f;
}
}
void HELPER(qppermb)(E2KReg *r, E2KReg *s1, E2KReg *s2, E2KReg *s3)
{
int i;
for (i = 0; i < 16; i++) {
uint8_t sel = s3->ub[i];
int index = sel & 0x0f;
uint8_t byte = sel & 0x10 ? s1->ub[index] : s2->ub[index];
byte = sel & 0x20 ? ~byte : byte;
byte = sel & 0x40 ? reverse_bits(byte) : byte;
byte = sel & 0x80 ? (byte & 0x80 ? 0xff : 0) : byte;
r->ub[i] = byte;
}
}
void HELPER(qpshufb)(E2KReg *r, E2KReg *s1, E2KReg *s2, E2KReg *s3)
{
r->ud[0] = helper_pshufb(s2->ud[1], s2->ud[0], s3->ud[0]);
r->ud[1] = helper_pshufb(s1->ud[1], s1->ud[0], s3->ud[1]);
}
static uint64_t get_value_from_truth_table(bool x, bool y, bool z, uint32_t truth_table)
{
int pos = x << 2 | y << 1 | z;
return (truth_table >> pos) & 1ULL;
}
uint64_t HELPER(plog)(uint32_t opc, uint64_t src1, uint64_t src2, uint64_t src3)
{
int i;
uint64_t ret = 0;
for (i = 0; i < 64; i++) {
uint32_t x = extract64(src1, i, 1);
uint32_t y = extract64(src2, i, 1);
uint32_t z = extract64(src3, i, 1);
uint64_t bit = get_value_from_truth_table(x, y, z, opc);
ret |= bit << i;
}
return ret;
}
#define GEN_ENV_HELPER_PACKED_N(name, n, code) \
uint64_t HELPER(name)(CPUE2KState *env, uint64_t src1, uint64_t src2) \
{ \
size_t i = 0; \
vec64 s1 = { .ud[0] = src1 }, s2 = { .ud[0] = src2 }; \
vec64 dst = { .ud[0] = 0 }; \
for (; i < n; i++) { \
code \
} \
return dst.ud[0]; \
}
#define GEN_ENV_HELPER_PACKED(name, type, code) \
GEN_ENV_HELPER_PACKED_N(name, vec64_len(type), code)
#define GEN_ENV_HELPER_PACKED_OP(name, type, op) \
GEN_ENV_HELPER_PACKED_N(name, vec64_len(type), { \
dst.type[i] = op(env, s1.type[i], s2.type[i]); \
})
#define GEN_ENV_HELPER_PACKED_HORIZONTAL_OP(name, type, op, map) \
GEN_ENV_HELPER_PACKED_N(name, vec64_len(type) / 2, { \
int j = i * 2; \
dst.type[i ] = map(op(env, s1.type[j], s1.type[j + 1])); \
dst.type[i + vec64_len(type) / 2] = map(op(env, s2.type[j], s2.type[j + 1])); \
})
#define IMPL_QPACKED_ENV_N(name, n, code) \
void HELPER(name)(E2KReg *r, CPUE2KState *env, E2KReg *s1, E2KReg *s2) \
{ \
int i; \
\
for (i = 0; i < n; i++) { \
code \
} \
}
#define IMPL_QPACKED_ENV(name, type, code) \
IMPL_QPACKED_ENV_N(name, vec128_len(type), code)
#define IMPL_QPACKED_ENV_OP(name, type, op) \
IMPL_QPACKED_ENV_N(name, vec128_len(type), { \
r->type[i] = op(env, s1->type[i], s2->type[i]); \
})
#define IMPL_QPACKED_ENV_HOP(name, type, op, map) \
IMPL_QPACKED_ENV_N(name, vec128_len(type) / 2, { \
int j = i * 2; \
r->type[i ] = map(op(env, s1->type[j], s1->type[j + 1])); \
r->type[i + vec128_len(type) / 2] = map(op(env, s2->type[j], s2->type[j + 1])); \
})
GEN_ENV_HELPER_PACKED_OP(pfadds, uw, helper_fadds)
GEN_ENV_HELPER_PACKED_OP(pfsubs, uw, helper_fsubs)
GEN_ENV_HELPER_PACKED_OP(pfmuls, uw, helper_fmuls)
GEN_ENV_HELPER_PACKED_OP(pfmaxs, uw, helper_fmaxs)
GEN_ENV_HELPER_PACKED_OP(pfmins, uw, helper_fmins)
GEN_ENV_HELPER_PACKED_HORIZONTAL_OP(pfhadds, uw, helper_fadds, ident)
GEN_ENV_HELPER_PACKED_HORIZONTAL_OP(pfhsubs, uw, helper_fsubs, ident)
IMPL_QPACKED_ENV_HOP(qpfhadds, uw, helper_fadds, ident)
IMPL_QPACKED_ENV_HOP(qpfhsubs, uw, helper_fsubs, ident)
GEN_ENV_HELPER_PACKED_OP(pfcmpeqs, uw, helper_fcmpeqs)
GEN_ENV_HELPER_PACKED_OP(pfcmplts, uw, helper_fcmplts)
GEN_ENV_HELPER_PACKED_OP(pfcmples, uw, helper_fcmples)
GEN_ENV_HELPER_PACKED_OP(pfcmpuods, uw, helper_fcmpuods)
GEN_ENV_HELPER_PACKED_OP(pfcmpneqs, uw, helper_fcmpneqs)
GEN_ENV_HELPER_PACKED_OP(pfcmpnlts, uw, helper_fcmpnlts)
GEN_ENV_HELPER_PACKED_OP(pfcmpnles, uw, helper_fcmpnles)
GEN_ENV_HELPER_PACKED_OP(pfcmpods, uw, helper_fcmpods)
GEN_ENV_HELPER_PACKED(pfaddsubs, uw, { \
if (i & 1) { \
dst.uw[i] = helper_fadds(env, s1.uw[i], s2.uw[i]); \
} else { \
dst.uw[i] = helper_fsubs(env, s1.uw[i], s2.uw[i]); \
} \
})
#define GEN_ENV_HELPER_PACKED_UNARY_N(name, n, code) \
uint64_t HELPER(name)(CPUE2KState *env, uint64_t src2) \
{ \
size_t i = 0; \
vec64 s2 = { .ud[0] = src2 }; \
vec64 dst = { .ud[0] = 0 }; \
for (; i < n; i++) { \
code \
} \
return dst.ud[0]; \
}
#define GEN_ENV_HELPER_PACKED_UNARY(name, type, code) \
GEN_ENV_HELPER_PACKED_UNARY_N(name, vec64_len(type), code)
#define GEN_ENV_HELPER_PACKED_UNARY_OP(name, type, op) \
GEN_ENV_HELPER_PACKED_UNARY_N(name, vec64_len(type), { \
dst.type[i] = op(env, s2.type[i]); \
})
#define GEN_ENV_HELPER_PACKED_OP_CVT(name, type, op) \
GEN_ENV_HELPER_PACKED_N(name, vec64_len(type), { \
dst.type[i] = op(env, s1.uw[0], s2.type[i]); \
})
GEN_ENV_HELPER_PACKED_OP_CVT(pfstoifs, uw, helper_fstoifs)
GEN_ENV_HELPER_PACKED_UNARY_OP(pistofs, uw, helper_istofs)
GEN_ENV_HELPER_PACKED_UNARY_OP(pfstois, uw, helper_fstois)
GEN_ENV_HELPER_PACKED_UNARY_OP(pfstoistr, uw, helper_fstoistr)
#define IMPL_QPACKED_ENV_CVT_EXT(name, op) \
void HELPER(name)(E2KReg *r, CPUE2KState *env, uint64_t src2) \
{ \
vec64 s2 = { .ud[0] = src2 }; \
\
r->ud[0] = op(env, s2.uw[0]); \
r->ud[1] = op(env, s2.uw[1]); \
}
IMPL_QPACKED_ENV_CVT_EXT(qpfstoid, helper_fstoid)
IMPL_QPACKED_ENV_CVT_EXT(qpfstoidtr, helper_fstoidtr)
IMPL_QPACKED_ENV_CVT_EXT(qpistofd, helper_istofd)
IMPL_QPACKED_ENV_CVT_EXT(qpfstofd, helper_fstofd)
#define IMPL_QPACKED_ENV_CVT_TRUNC(name, op) \
uint64_t HELPER(name)(CPUE2KState *env, E2KReg *s2) \
{ \
vec64 r; \
\
r.uw[0] = op(env, s2->ud[0]); \
r.uw[1] = op(env, s2->ud[1]); \
\
return r.ud[0]; \
}
IMPL_QPACKED_ENV_CVT_TRUNC(qpfdtois, helper_fdtois)
IMPL_QPACKED_ENV_CVT_TRUNC(qpfdtoistr, helper_fdtoistr)
IMPL_QPACKED_ENV_CVT_TRUNC(qpidtofs, helper_idtofs)
IMPL_QPACKED_ENV_CVT_TRUNC(qpfdtofs, helper_fdtofs)

18
target/e2k/meson.build Normal file
View File

@ -0,0 +1,18 @@
e2k_ss = ss.source_set()
e2k_ss.add(files(
'cpu.c',
'cpu-dump.c',
'gdbstub.c',
'helper.c',
'helper_aau.c',
'helper_fpu.c',
'helper_int.c',
'helper_sm.c',
'helper_vec.c',
'translate.c',
))
e2k_softmmu_ss = ss.source_set()
target_arch += {'e2k': e2k_ss}
target_softmmu_arch += {'e2k': e2k_softmmu_ss}

7
target/e2k/trace-events Normal file
View File

@ -0,0 +1,7 @@
# See docs/devel/tracing.txt for syntax documentation.
# helper.c
mmu_ind(uint64_t reg, uint64_t ret) "MMU reg read 0x%lx -> 0x%lx"
mmu_outd(uint64_t reg, uint64_t ret) "MMU reg write 0x%lx <- 0x%lx"
ioaddr_in(const char *op, uint64_t reg, uint64_t ret) "MAS_IOADDR %s read 0x%lx -> 0x%lx"
ioaddr_out(const char *op, uint64_t reg, uint64_t ret) "MAS_IOADDR %s write 0x%lx <- 0x%lx"

1
target/e2k/trace.h Normal file
View File

@ -0,0 +1 @@
#include "trace/trace-target_e2k.h"

8448
target/e2k/translate.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@ subdir('arm')
subdir('avr')
subdir('cris')
subdir('hexagon')
subdir('e2k')
subdir('hppa')
subdir('i386')
subdir('m68k')

View File

@ -96,7 +96,9 @@ ifdef CONFIG_USER_ONLY
# sub-targets (e.g. ARM & AArch64) then it is up to
# $(TARGET_NAME)/Makefile.target to include the common parent
# architecture in its VPATH.
ifneq ($(CROSS_CC_GUEST_NO_MULTIARCH_TESTS),y)
-include $(SRC_PATH)/tests/tcg/multiarch/Makefile.target
endif
-include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.target
# Add the common build options

View File

@ -48,6 +48,8 @@ fi
: ${cross_cc_cflags_aarch64_be="-mbig-endian"}
: $(cross_cc_alpha="alpha-linux-gnu-gcc")
: ${cross_cc_arm="arm-linux-gnueabihf-gcc"}
: ${cross_cc_e2k="e2k-linux-as"} # C compiler isn't public yet
: ${cross_cc_e2k_ignore_checks="yes"}
: ${cross_cc_cflags_armeb="-mbig-endian"}
: ${cross_cc_hexagon="hexagon-unknown-linux-musl-clang"}
: ${cross_cc_cflags_hexagon="-mv67 -O2 -static"}

View File

@ -0,0 +1,23 @@
# -*- Mode: makefile -*-
#
# E2K tests
#
E2K_SRC = $(SRC_PATH)/tests/tcg/e2k
E2K_ALL = $(wildcard $(E2K_SRC)/*.s)
TESTS = $(patsubst $(E2K_SRC)/%.s, %, $(E2K_ALL))
VPATH = $(E2K_SRC)
CROSS = e2k-linux-
AS = $(CROSS)as
LD = $(CROSS)ld
ASFLAGS = -mcpu=elbrus-v4 -g -I$(E2K_SRC)
LDFLAGS =
%.o: %.s
$(AS) $(ASFLAGS) $< -o $@
%: %.o
$(LD) $(LDFLAGS) $< -o $@

123
tests/tcg/e2k/macros.inc Normal file
View File

@ -0,0 +1,123 @@
.set SYSCALL32_TRAPNUM, 0x1
.set SYSCALL64_TRAPNUM, 0x3
.set __NR_exit, 0x1
.set __NR_write, 0x4
.macro e2k_syscall_1 trapnum sysnum v1
{
addd 0x0, \sysnum, %b[0]
addd 0x0, \v1, %b[1]
sdisp %ctpr1, \trapnum
}
{
call %ctpr1, wbs = 0x4
}
.endm
.macro e2k_syscall_2 trapnum sysnum v1 v2
{
sdisp %ctpr1, \trapnum
addd 0x0, \sysnum, %b[0]
addd 0x0, \v1, %b[1]
addd 0x0, \v2, %b[2]
}
{
call %ctpr1, wbs = 0x4
}
.endm
.macro e2k_syscall_3 trapnum sysnum v1 v2 v3
{
sdisp %ctpr1, \trapnum
addd 0x0, \sysnum, %b[0]
addd 0x0, \v1, %b[1]
addd 0x0, \v2, %b[2]
addd 0x0, \v3, %b[3]
}
{
call %ctpr1, wbs = 0x4
}
.endm
.macro e2k_syscall_4 trapnum sysnum v1 v2 v3 v4
{
sdisp %ctpr1, \trapnum
addd 0x0, \sysnum, %b[0]
addd 0x0, \v1, %b[1]
addd 0x0, \v2, %b[2]
addd 0x0, \v3, %b[3]
addd 0x0, \v4, %b[4]
}
{
call %ctpr1, wbs = 0x4
}
.endm
.macro e2k_syscall_5 trapnum sysnum v1 v2 v3 v4 v5
{
sdisp %ctpr1, \trapnum
addd 0x0, \sysnum, %b[0]
addd 0x0, \v1, %b[1]
addd 0x0, \v2, %b[2]
addd 0x0, \v3, %b[3]
addd 0x0, \v4, %b[4]
addd 0x0, \v5, %b[5]
}
{
call %ctpr1, wbs = 0x4
}
.endm
.macro e2k_syscall_6 trapnum sysnum v1 v2 v3 v4 v5 v6
{
sdisp %ctpr1, \trapnum
addd 0x0, \sysnum, %b[0]
addd 0x0, \v1, %b[1]
addd 0x0, \v2, %b[2]
addd 0x0, \v3, %b[3]
addd 0x0, \v4, %b[4]
addd 0x0, \v5, %b[5]
}
{
addd 0x0, \v6, %b[5]
call %ctpr1, wbs = 0x4
}
.endm
.macro e2k_syscall_7 trapnum sysnum v1 v2 v3 v4 v5 v6 v7
{
sdisp %ctpr1, \trapnum
addd 0x0, \sysnum, %b[0]
addd 0x0, \v1, %b[1]
addd 0x0, \v2, %b[2]
addd 0x0, \v3, %b[3]
addd 0x0, \v4, %b[4]
addd 0x0, \v5, %b[5]
}
{
addd 0x0, \v6, %b[6]
addd 0x0, \v7, %b[7]
call %ctpr1, wbs = 0x4
}
.endm
.macro assert op reg1 reg2 counter_reg
{
\op \reg1, \reg2, %pred0
addd 0x0, \counter_reg, %b[0]
disp %ctpr1, _test_fail
}
{
addd 0x1, \counter_reg, \counter_reg
call %ctpr1, wbs = 0x4 ? ~%pred0
}
.endm
_test_fail:
{
setwd wsz = 0x8, nfx = 0x0, dbl = 0x0
setbn rsz = 0x3, rbs = 0x4, rcur = 0x0
}
e2k_syscall_3 SYSCALL64_TRAPNUM, __NR_write, 0, [ _test_failed_str ], _test_failed_strlen
e2k_syscall_1 SYSCALL64_TRAPNUM, __NR_exit, %dr0

View File

@ -0,0 +1,6 @@
_stop:
e2k_syscall_1 SYSCALL64_TRAPNUM, __NR_exit, 0
_test_failed_str:
.ascii "TEST FAILED\n\0"
.set _test_failed_strlen, . - _test_failed_str

23
tests/tcg/e2k/test_addd.s Normal file
View File

@ -0,0 +1,23 @@
.global _start
.include "macros.inc"
_start:
{
setwd wsz=0x8, nfx=1
setbn rbs=0x4, rsz=0x3, rcur=0
}
{
addd 0x0, 0x0, %r0 ! counter
addd 0x2, 0xFFFFFFFFFFFFFFFF, %r1
}
{
addd 0x2, 0x2, %r2
adds 0x2, 0x2, %r3
adds 0x2, 0xFFFFFFFF, %r4
}
assert cmpedb, %r1, 0x1, %r0
assert cmpedb, %r2, 0x4, %r0
assert cmpesb, %r3, 0x4, %r0
assert cmpesb, %r4, 0x1, %r0
.include "macros_end.inc"