Compare commits

...

204 Commits

Author SHA1 Message Date
Alibek Omarov c8b2424581 apply termux patches 2020-12-18 14:24:28 +03:00
Alibek Omarov 2308e3519b Merge upstream master 2020-12-18 13:44:43 +03:00
Alibek Omarov 3c31d9aa44 qemu-binfmt-conf: add e2k elf header, 64-bit only as we only support it at this time 2020-12-17 15:37:15 +03:00
Denis Drakhnia f4124b594b target: e2k: Rename alc execute fns. 2020-12-17 11:58:45 +02:00
Denis Drakhnia 2caefbd238 target: e2k: HACK: Unlock mem addr forces %MLOCK condition. 2020-12-17 09:54:11 +02:00
Denis Drakhnia 2c45fb6f0b Merge branch 'e2k-fpu' into e2k 2020-12-16 22:33:50 +02:00
Denis Drakhnia a0e898c7da target: e2k: Add basic FX instrs. 2020-12-16 21:19:01 +02:00
Denis Drakhnia 7f949defe5 target: e2k: Add movfi/movif instrs. 2020-12-16 16:42:17 +02:00
Denis Drakhnia 04cfe2ca8f target: e2k: Move fpcr/fpsr to state reg helpers. 2020-12-16 15:02:00 +02:00
Denis Drakhnia 50658e7362 target: e2k: Add get_src{1,2}_i80 funcs. 2020-12-16 14:39:35 +02:00
Denis Drakhnia 858dcb013c target: e2k: Add xreg read/write functions. 2020-12-16 14:39:35 +02:00
Denis Drakhnia 6ec235945b target: e2k: Add temps for FX/SIMD ops. 2020-12-16 14:39:35 +02:00
Denis Drakhnia 7c128bae94 target: e2k: Remove rptr and tptr from state. 2020-12-16 14:39:35 +02:00
Denis Drakhnia d50082e84c target: e2k: Delete hack for saving USD registers on proc call/ret. 2020-12-16 14:39:35 +02:00
Denis Drakhnia 8c8f5fc066 target: e2k: Add psubd instr. 2020-12-16 14:39:35 +02:00
Denis Drakhnia 74f2385990 target: e2k: Delete hack for saving USD registers on proc call/ret. 2020-12-15 10:48:19 +02:00
Alibek Omarov 4546d92c64 target: e2k: set disas isa version 2020-12-15 02:32:19 +03:00
Alibek Omarov fdc6f360c6 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 2020-12-15 02:00:19 +03:00
Alibek Omarov 006d4499bf target: e2k: add conversion instructions, handle float comparison with predicate result instrs 2020-12-15 01:35:45 +03:00
Alibek Omarov afce8392d8 target: e2k: add basic fpu instructions 2020-12-15 01:35:44 +03:00
Alibek Omarov c78d3d7521 fpu: assuming e2k fp behave like x86 2020-12-15 01:35:09 +03:00
Denis Drakhnia 76ebaa78bd target: e2k: Add psubd instr. 2020-12-14 17:51:04 +02:00
Denis Drakhnia 1f05c5e625 target: e2k: Fix address generation in staa. 2020-12-14 15:08:56 +02:00
Denis Drakhnia f0f36b5c78 target: e2k: Fix udivs exception hack. 2020-12-14 09:24:55 +02:00
Denis Drakhnia d3739540cb target: e2k: Impl restore_state_to_opc. 2020-12-13 23:55:09 +02:00
Denis Drakhnia 5d6c5ac76e target: e2k: Add e2k_todo{,_illop} macros. 2020-12-13 23:45:02 +02:00
Denis Drakhnia 22f49dc828 target: e2k: Add tlb_fill handler. 2020-12-13 22:55:58 +02:00
Denis Drakhnia 0c7383ce04 target: e2k: Clear registers in new allocated range of window. 2020-12-13 20:58:32 +02:00
Denis Drakhnia 0df8b48268 target: e2k: Fix incorrect registers view in gdb after exception. 2020-12-13 19:26:45 +02:00
Denis Drakhnia 8d17c54615 target: e2k: Fix gdb run till exit from func. 2020-12-13 18:17:13 +02:00
Denis Drakhnia 802e0181d7 target: e2k: %cr0 must hold pregs and ip of previous procedure. 2020-12-13 17:40:30 +02:00
Denis Drakhnia aeb9591179 target: e2k: Remove unneeded regs array in TCG state. 2020-12-13 11:10:53 +02:00
Denis Drakhnia ed29047cd7 target: e2k: HACK: Tag storage for procedure stack. 2020-12-13 11:07:42 +02:00
Denis Drakhnia e5021e1b70 target: e2k: Save PC before reading it in rr{s,d}. 2020-12-12 20:22:38 +02:00
Denis Drakhnia 7a1c278345 target: e2k: Select tag for taken source in merge{s,d}. 2020-12-11 21:41:00 +02:00
Denis Drakhnia a3d10a3fa6 target: e2k: Add dbl window modifier. 2020-12-11 17:02:28 +02:00
Denis Drakhnia f39faef99d target: e2k: mova{b,h,w} must write to reg64. 2020-12-11 16:31:36 +02:00
Denis Drakhnia 4e93ac4ed9 target: e2k: Impl multiple pred for ALC exec. 2020-12-11 14:58:01 +02:00
Denis Drakhnia 0809a69256 target: e2k: Return aligned pointer from getsp. 2020-12-11 09:37:23 +02:00
Denis Drakhnia d6b9366d9d target: e2k: HACK: Add stack for USD registers.
CPU must restore `USD` after calls but I don't know how it should be implemented.
2020-12-11 00:47:15 +02:00
Denis Drakhnia 4a6eb86ce9 target: e2k: Add cmp{o,s,p}{s,d} instrs.
Fix cmpandp{s,d}b.
2020-12-10 22:44:12 +02:00
Denis Drakhnia d3943b9e22 target: e2k: Do not account %predN for ct in loop prologue. 2020-12-10 17:30:07 +02:00
Denis Drakhnia b35195f9ec target: e2k: Add %pcntN condition. 2020-12-10 14:52:56 +02:00
Denis Drakhnia 3928837609 target: e2k: Force ps pop in FX mode. 2020-12-10 09:44:15 +02:00
Denis Drakhnia 4d706ca329 target: e2k: Ignore unimplemented mas opc in store. 2020-12-10 09:35:45 +02:00
Denis Drakhnia 5c8136309f target: e2k: Add pmovmskb instr. 2020-12-10 09:35:18 +02:00
Denis Drakhnia f312e258db target: e2k: Add p{min,max}{ub,sh} instrs. 2020-12-10 09:31:18 +02:00
Denis Drakhnia d259496a4a target: e2k: Add staaq instr. 2020-12-10 09:27:16 +02:00
Denis Drakhnia bee1cf054d target: e2k: Execute ALES2/5 together with others channels. 2020-12-10 09:20:02 +02:00
Denis Drakhnia 1887af755a target: e2k: Add xregs. 2020-12-09 21:38:16 +02:00
Denis Drakhnia 676b4a2388 target: e2k: Log msg if wd.fx is setted. 2020-12-09 10:58:53 +02:00
Denis Drakhnia 96e7fcc99b target: e2k: Do not save IP on every instruction. 2020-12-09 10:28:49 +02:00
Denis Drakhnia 7c8bfe6e24 target: e2k: Reading %ilcr for gdb. 2020-12-09 10:13:43 +02:00
Denis Drakhnia 39fec245f6 target: e2k: Fix setting ctpr.ipd for *disp instr. 2020-12-09 09:50:42 +02:00
Denis Drakhnia 4591ac136d target: e2k: Dec store rem in loop mode. 2020-12-09 09:29:13 +02:00
Denis Drakhnia c531460961 target: e2k: Restricted loop_mode implementation. 2020-12-09 00:08:55 +02:00
Denis Drakhnia 726be4757c target: e2k: Fix reading aadN from gdb. 2020-12-08 20:33:25 +02:00
Denis Drakhnia 74d4fbcc36 target: e2k: Add basic mova{b,h,w,d} impl. 2020-12-08 18:57:28 +02:00
Denis Drakhnia 261326898d target: e2k: Fix ctpr size. 2020-12-08 10:22:01 +02:00
Denis Drakhnia 082bbcad2c target: e2k: Remove merge condition from Instr. 2020-12-08 10:00:46 +02:00
Denis Drakhnia 2ab153e322 target: e2k: Add staa{b,h} instrs. 2020-12-08 09:11:56 +02:00
Alibek Omarov 3267e9ddab target: e2k: define CPUs we're testing against, define gdb arch 2020-12-07 20:27:13 +03:00
Denis Drakhnia da7593ed5d target: e2k: Add clarification to gen_tag funcs. 2020-12-07 10:22:02 +02:00
Alibek Omarov b62f9057f5 target: e2k: add umulx/smulx instrs. 2020-12-06 23:20:07 +03:00
Denis Drakhnia f0941a1a6b target: e2k: Fix sxt/st operand sizes. 2020-12-06 16:58:07 +02:00
Denis Drakhnia 24bb677df9 target: e2k: Hack delay %rN index gen for result. 2020-12-06 15:59:06 +02:00
Denis Drakhnia dc9124a532 target: e2k: Fix based preg. 2020-12-06 14:54:48 +02:00
Denis Drakhnia c744d4eb35 target: e2k: Log msg if dbl is setted. 2020-12-05 14:59:10 +02:00
Denis Drakhnia d699173933 target: e2k: Add {u,s}mulhd instrs. 2020-12-05 14:59:10 +02:00
Denis Drakhnia 60208a8afa target: e2k: Add mova stubs. 2020-12-05 14:59:10 +02:00
Denis Drakhnia a004e745e0 target: e2k: Fix uninit plu_result.reg bug. 2020-12-05 14:52:38 +02:00
Denis Drakhnia a5a65eab53 target: e2k: Add combined int instructions. 2020-12-05 10:28:43 +02:00
Denis Drakhnia 2f1b4b5cf6 target: e2k: Add Instr struct to alc. 2020-12-05 00:21:49 +02:00
Denis Drakhnia 3c55c35c93 target: e2k: Reorganize tag usage. 2020-12-04 23:14:24 +02:00
Denis Drakhnia 4f3d78cb8e target: e2k: Fix icont bug. 2020-12-04 10:18:55 +02:00
Denis Drakhnia c5c8c39082 target: e2k: Read %idr in rrd. 2020-12-04 10:12:37 +02:00
Denis Drakhnia ac06ae3f2b target: e2k: Increase startup window size. 2020-12-04 09:40:23 +02:00
Denis Drakhnia 85dbd706d8 target: e2k: Fix bitrev{s,d} instrs. 2020-12-03 21:27:29 +02:00
Denis Drakhnia 83f9917a3c target: e2k: Impl reading some regs through rrd.
%wd, %pcsp.lo, %pcsp.hi, %pcshtp, %cr1.hi, %cr1.lo.
2020-12-03 21:24:54 +02:00
Alibek Omarov f6d13b7031 target: e2k: add reading %ip register through rrd 2020-12-03 21:05:12 +02:00
Denis Drakhnia f1fd51e5b4 target: e2k: Fix getsp src2 size. 2020-12-03 21:04:53 +02:00
Alibek Omarov 3d6f245d89 target: e2k: add lzcnt and popcnt instrs (untested!) 2020-12-03 20:41:54 +02:00
Alibek Omarov 42bbd58714 target: e2k: add bitrev instr 2020-12-03 20:40:29 +02:00
Denis Drakhnia 6b0e8814cc target: e2k: Impl pcmpeqb. 2020-12-03 20:38:46 +02:00
Denis Drakhnia dc52e237dc target: e2k: Replace some panics with messages. 2020-12-03 20:30:50 +02:00
Denis Drakhnia f651238df2 target: e2k: Add %cr1.{lo,hi} to rr{s,d}/rw{s,d}. 2020-12-03 20:29:15 +02:00
Denis Drakhnia 611bf22f2f target: e2k: Impl write AL result to ctpr. 2020-12-03 20:19:16 +02:00
Denis Drakhnia 12ba786e21 target: e2k: Partial staa{d,w} implementation. 2020-12-03 16:59:58 +02:00
Denis Drakhnia 090b58a1cf target: e2k: Increase temp i32 limit. 2020-12-02 21:12:19 +02:00
Denis Drakhnia d59e62a8a1 target: e2k: Add paddd instr. 2020-12-02 20:55:53 +02:00
Denis Drakhnia 72f880998e target: e2k: Add mul{s,d} instrs. 2020-12-02 20:43:45 +02:00
Denis Drakhnia 5f46345413 target: e2k: Add pshufb instr. 2020-12-02 20:38:14 +02:00
Denis Drakhnia c481a3c875 target: e2k: Add insf{s,d} instrs. 2020-12-02 18:16:00 +02:00
Denis Drakhnia ca1969fe1e target: e2k: Add gettag{s,d} instrs. 2020-12-02 17:39:16 +02:00
Denis Drakhnia 13dd01936d target: e2k: Add puttag{s,d} instrs. 2020-12-02 17:28:23 +02:00
Denis Drakhnia a1698a963a target: e2k: Impl speculative execution. 2020-12-02 15:06:50 +02:00
Alibek Omarov d0f3d0ed82 target: e2k: refactor instruction decoding based on active channel 2020-12-01 23:58:35 +03:00
Denis Drakhnia 9fa1537975 target: e2k: Remove unneeded ip change in syscall. 2020-12-01 14:54:48 +02:00
Denis Drakhnia 2a66866d38 target: e2k: Increace i32 temp limit. 2020-12-01 14:38:39 +02:00
Denis Drakhnia 61a3d01fe7 target: e2k: Reorg reg file. 2020-12-01 14:00:12 +02:00
Denis Drakhnia 7475849453 target: e2k: Add registers tags. 2020-11-28 18:43:24 +02:00
Denis Drakhnia 9399581696 tcg: Increase max temps limit. 2020-11-28 13:53:46 +02:00
Denis Drakhnia 64ec73ec15 target: e2k: Jump to ctpr_addr if ctpr is return. 2020-11-28 12:26:26 +02:00
Denis Drakhnia 963288c9d2 target: e2k: Fix instr return. 2020-11-28 11:32:50 +02:00
Denis Drakhnia 038eb6f4ff target: e2k: Update TODO messages. 2020-11-28 10:08:22 +02:00
Denis Drakhnia 16ef8861b7 target: e2k: Gen rt exception in udivs hack. 2020-11-28 09:57:23 +02:00
Denis Drakhnia c8dc14e3a6 target: e2k: Fix gen_goto_tb usage. 2020-11-28 09:44:53 +02:00
Denis Drakhnia 2f4cae1a19 target: e2k: Fix instr start address. 2020-11-27 09:45:35 +02:00
Denis Drakhnia b947cf9f8f target: e2k: Move int helpers to separate file. 2020-11-27 08:32:52 +02:00
Denis Drakhnia 7a7cd856c9 target: e2k: Make gdb happier. 2020-11-27 08:22:19 +02:00
Denis Drakhnia 73bc3e7d57 target: e2k: Ps push/pop with pshtp. 2020-11-27 00:03:54 +02:00
Denis Drakhnia ddd9a9aca4 target: e2k: Add setwd helper. 2020-11-26 22:02:34 +02:00
Denis Drakhnia 3cc2b2faab target: e2k: Reorg cr1. 2020-11-26 21:14:40 +02:00
Denis Drakhnia 7febde65c7 target: e2k: Reorg wd. 2020-11-26 20:35:07 +02:00
Denis Drakhnia f727916e60 target: e2k: Reorg br. 2020-11-26 20:25:43 +02:00
Denis Drakhnia dd87b0e900 target: e2k: Restore udivs dump state hack. 2020-11-26 19:03:25 +02:00
Denis Drakhnia d44b82eba3 target: e2k: Reord pcsp. 2020-11-26 18:31:25 +02:00
Denis Drakhnia 008b9b53e0 target: e2k: Reorg psp. 2020-11-26 17:02:49 +02:00
Denis Drakhnia 779932661c target: e2k: Move helper_cur_dec to TCG. 2020-11-26 14:10:55 +02:00
Denis Drakhnia 8f1771d67d target: e2k: Add exceptions to wregs access. 2020-11-26 13:34:37 +02:00
Denis Drakhnia ccb625ced0 gdb: e2k: Fix memory read. 2020-11-25 23:44:47 +02:00
Denis Drakhnia 70076f08e7 target: e2k: Fix literal loading. 2020-11-25 21:30:23 +02:00
Denis Drakhnia 93b5e74e02 target: e2k: Fix control flow condition. 2020-11-25 19:56:05 +02:00
Denis Drakhnia 88b9e44d2d target: e2k: Add {s,u}div{s,d}. 2020-11-25 19:55:35 +02:00
Denis Drakhnia 1494afd90f target: e2k: Fix mas array size. 2020-11-24 23:07:56 +02:00
Denis Drakhnia f78a8ea23f target: e2k: Remove helper unimpl. 2020-11-24 22:50:33 +02:00
Denis Drakhnia 58663bb93e target: e2k: Add basic setmas support. 2020-11-24 22:41:27 +02:00
Denis Drakhnia d240aa2b85 target: e2k: Fix extending sign 32-bit literal. 2020-11-24 20:41:12 +02:00
Denis Drakhnia 5fe6d00b05 gdb: e2k: Add stub for read tags. 2020-11-24 16:37:31 +02:00
Denis Drakhnia 8558652986 target: e2k: gdb global registers tags ids. 2020-11-24 15:23:08 +02:00
Denis Drakhnia c6f74e98be target: e2k: Add %clkr. 2020-11-24 11:19:33 +02:00
Denis Drakhnia 8f060b59f0 target: e2k: alc: Conditional execution. 2020-11-24 11:12:01 +02:00
Denis Drakhnia a10190535e target: e2k: Fix extraction of lp index. 2020-11-24 09:47:10 +02:00
Denis Drakhnia 5f4abd5e69 target: add: Add getfs/getfd instrs. 2020-11-24 09:30:01 +02:00
Denis Drakhnia aa64434455 target: e2k: Add %idr. 2020-11-24 00:02:11 +02:00
Denis Drakhnia e5b1f1c0c4 target: e2k: Add cmpand{op}{s,d}b instrs. 2020-11-23 23:45:10 +02:00
Denis Drakhnia 0c676081e3 target: e2k: Add %upsr. 2020-11-23 22:48:58 +02:00
Denis Drakhnia 31bfefe9fd target: e2k: Use start+len for GET_FIELD. 2020-11-23 22:26:47 +02:00
Denis Drakhnia ceae6abea9 target: e2k: Add PLU instructions. 2020-11-23 21:57:46 +02:00
Denis Drakhnia 971ebe9eb1 target: e2k: Fix load instrs. 2020-11-23 17:26:34 +02:00
Alibek Omarov cc5dbdb102 target: e2k: alc: support cmp{op}sb 2020-11-23 16:40:21 +03:00
Alibek Omarov d2fb083c8b target: e2k: add %ip for rrd 2020-11-23 15:59:33 +03:00
Denis Drakhnia e01acef8ad target: e2k: Fix ct in gdb. 2020-11-23 13:52:43 +02:00
Denis Drakhnia 0f10ca4949 target: e2k: Read NR in gdb. 2020-11-23 10:03:26 +02:00
Denis Drakhnia d81651b6cb target: e2k: Fix e2k_cpu_gdb_read_register. 2020-11-22 12:37:00 +02:00
Denis Drakhnia 9d2966b336 target: e2k: Fix call/return. 2020-11-22 11:44:28 +02:00
Denis Drakhnia 3834318a0f target: e2k: Fix ctpr count. 2020-11-22 09:37:45 +02:00
Denis Drakhnia 7b81657a6e target: e2k: Mov ct disp from helper to TCG. 2020-11-19 23:20:03 +02:00
Denis Drakhnia 77b439a847 target: e2k: Remove cond from ct helpers. 2020-11-19 22:59:16 +02:00
Denis Drakhnia fdd9a777e9 target: e2k: Remove has_cond from DisasContext. 2020-11-19 22:57:06 +02:00
Denis Drakhnia 49dc9ee83e target: e2k: Move ct cond to cpu env. 2020-11-19 22:47:25 +02:00
Denis Drakhnia ea24b9f07e target: e2k: Reorg + basic gdb debugging. 2020-11-18 12:21:32 +02:00
Denis Drakhnia 7ef5d88e25 target: e2k: gdb register ids. 2020-11-17 13:56:09 +02:00
Alibek Omarov c7b6b7f8bf target: e2k: initial gdb support 2020-11-16 21:54:42 +03:00
Denis Drakhnia 6bcd4980e9 disas: e2k: Fix alf print. 2020-11-16 19:55:39 +02:00
Denis Drakhnia 5376951493 target: e2k: gen_goto_tb from SPARC. 2020-11-16 18:54:28 +02:00
Denis Drakhnia a01e83ed54 target: e2k: Add exception for abn/abp instr. 2020-11-16 18:16:27 +02:00
Denis Drakhnia 74757b094d target: e2k: Fix SIGFPE error. 2020-11-16 17:50:58 +02:00
Denis Drakhnia 59bdb69c27 target: e2k: Add procedure stack. 2020-11-16 16:26:39 +02:00
Alibek Omarov 88e79dcda9 tests: tcg: add basic tests for e2k 2020-11-16 15:57:59 +03:00
Denis Drakhnia a7e726dcb4 target: e2k: Add basic getsp instr. 2020-11-15 20:25:40 +02:00
Denis Drakhnia 89b9789906 target: e2k: Rotate window registers in syscall. 2020-11-15 19:57:10 +02:00
Denis Drakhnia a23305afc0 target: e2k: Add pcs_{push,pop}. 2020-11-15 19:45:42 +02:00
Denis Drakhnia d495f0ffb3 target: e2k: Add basic call (without saving regs). 2020-11-15 17:05:27 +02:00
Denis Drakhnia aca6a33344 target: e2k: Add %pcsp_hi and %pcsp_lo registers. 2020-11-14 14:27:09 +02:00
Denis Drakhnia 6a79cc4954 target: e2k: Move %br to %cr1_hi. 2020-11-14 13:49:48 +02:00
Denis Drakhnia f010864e2d target: e2k: Reorg lcnt decrement. 2020-11-14 12:16:02 +02:00
Denis Drakhnia 5365ee90fc target: e2k: Move %br parts to %br. 2020-11-14 11:20:18 +02:00
Denis Drakhnia 3d679a2dba target: e2k: Fix bugs. 2020-11-13 22:47:31 +02:00
Denis Drakhnia d173b8feb7 target: e2k: Add loop_end/not_loop_end condition. 2020-11-13 18:40:56 +02:00
Denis Drakhnia 231b7e7919 target: e2k: Impl rotated pregs. 2020-11-13 16:49:28 +02:00
Denis Drakhnia 520053868d target: e2k: Remove type from macro GEN_MASK. 2020-11-13 11:53:21 +02:00
Denis Drakhnia 280d8192f9 target: e2k: Add store instrs. 2020-11-13 11:50:26 +02:00
Denis Drakhnia 4d14a07caf target: e2k: Add load instrs. 2020-11-13 11:39:13 +02:00
Denis Drakhnia 081bc9eeaa target: e2k: Add getsp instr. 2020-11-13 11:09:34 +02:00
Denis Drakhnia 589c905dfe target: e2k: Add read/write to %usd. 2020-11-13 10:33:55 +02:00
Denis Drakhnia 642865a2a7 target: e2k: Add merges and merged instrs. 2020-11-13 08:41:48 +02:00
Denis Drakhnia 6445d3e2ce target: e2k: Add sxt instr. 2020-11-12 23:46:57 +02:00
Denis Drakhnia baf638ddb6 target: e2k: Fix crash on conditional syscall. 2020-11-12 19:32:08 +02:00
Denis Drakhnia b546643321 target: e2k: Add basic syscall support. 2020-11-12 19:12:18 +02:00
Denis Drakhnia 3432a69a5c target: e2k: Try to impl syscall. 2020-11-12 15:52:51 +02:00
Denis Drakhnia f0d5277ccf target: e2k: Add e2k_gen get and set field. 2020-11-12 10:30:03 +02:00
Denis Drakhnia 26a18eebd3 target: e2k: Add disp and ct instrs support. 2020-11-11 23:30:14 +02:00
Denis Drakhnia c1a6627904 target: e2k: Add negated predicate ct condition. 2020-11-11 23:16:02 +02:00
Denis Drakhnia e83d027c6f target: e2k: Reorg control flow. 2020-11-11 22:45:55 +02:00
Denis Drakhnia ed1b58c984 target: e2k: Reorg. 2020-11-11 21:03:51 +02:00
Denis Drakhnia 12a0242083 target: e2k: Comment unused vars for future use. 2020-11-11 19:17:10 +02:00
Denis Drakhnia 3ba4185c39 target: e2k: Move TCG CPU State to translate.h. 2020-11-11 19:08:08 +02:00
Denis Drakhnia a28ea48d7d target: e2k: Add cpu state is_jmp. 2020-11-11 16:56:46 +02:00
Denis Drakhnia 90c70b1b66 target: e2k: Use win_ptr for regs. 2020-11-11 15:12:05 +02:00
Denis Drakhnia 03f49b2730 target: e2k: Add window ptr. 2020-11-11 11:28:06 +02:00
Denis Drakhnia d683794bee target: e2k: Commit bundle instrs at the end. 2020-11-11 10:06:13 +02:00
Denis Drakhnia 5bee731164 target: e2k: Simple condition jump. 2020-11-11 10:02:28 +02:00
Alibek Omarov 57b36ae058 target: e2k: fix instructions with speculative mode 2020-11-11 01:17:31 +03:00
Alibek Omarov 4d7defbc54 target: e2k: implement disas_log, doesn't work at all 2020-11-11 01:00:41 +03:00
Denis Drakhnia 6922a7b034 target: e2k: Basic instruction execution. 2020-11-10 22:00:20 +02:00
Alibek Omarov 032b505ec9 elf: fix wrong Elbrus elf machine id 2020-11-08 22:25:26 +03:00
Denis Drakhnia c9fcc64cea target: e2k: unpack long instructions. 2020-11-08 20:27:47 +02:00
Alibek Omarov fedef3507d disas: import disassmebler from binutils 2020-10-19 18:20:55 +03:00
Alibek Omarov 044483f2f8 target: e2k: add cpu definitions 2020-10-15 17:08:01 +03:00
Alibek Omarov a42160fad5 linux-user: add loading ELFs for e2kg 2020-10-13 23:45:25 +03:00
Alibek Omarov 4e0f0c92bb softmmu: add e2k definition 2020-10-13 23:45:02 +03:00
Alibek Omarov 774658d846 configs: add e2k-linux-user config 2020-10-13 23:44:52 +03:00
Alibek Omarov eeca891b81 include/elf.h: add MCST Elbrus definitions 2020-10-13 23:43:13 +03:00
91 changed files with 28718 additions and 62 deletions

View File

@ -47,6 +47,8 @@
#include "exec/ram_addr.h"
#endif
#include <linux/mman.h>
#include "exec/cputlb.h"
#include "exec/tb-hash.h"
#include "translate-all.h"

View File

@ -24,13 +24,15 @@
#include "qemu/osdep.h"
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include <linux/soundcard.h>
#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "qemu/host-utils.h"
#include "audio.h"
#include "trace.h"
#include <linux/mman.h>
#define AUDIO_CAP "oss"
#include "audio_int.h"

View File

@ -764,7 +764,7 @@ int get_tmp_filename(char *filename, int size)
const char *tmpdir;
tmpdir = getenv("TMPDIR");
if (!tmpdir) {
tmpdir = "/var/tmp";
tmpdir = "@TERMUX_PREFIX@/tmp";
}
if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
return -EOVERFLOW;

View File

@ -59,6 +59,7 @@
#include <sys/dkio.h>
#endif
#ifdef __linux__
#include <linux/mman.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/syscall.h>

15
configure vendored
View File

@ -2939,6 +2939,8 @@ then
fi
has_libgcrypt() {
return 0
if ! has "libgcrypt-config"
then
return 1
@ -3008,10 +3010,7 @@ if test "$gcrypt" != "no"; then
# Debian has removed -lgpg-error from libgcrypt-config
# as it "spreads unnecessary dependencies" which in
# turn breaks static builds...
if test "$static" = "yes"
then
gcrypt_libs="$gcrypt_libs -lgpg-error"
fi
gcrypt_libs="$gcrypt_libs -lgpg-error"
# Link test to make sure the given libraries work (e.g for static).
write_c_skeleton
@ -4083,6 +4082,7 @@ EOF
if compile_prog "" "" ; then
signalfd=yes
fi
signalfd=no
# check if optreset global is declared by <getopt.h>
optreset="no"
@ -5947,6 +5947,7 @@ fi
if test "$darwin" = "yes" ; then
echo "CONFIG_DARWIN=y" >> $config_host_mak
fi
ivshmem=no
if test "$solaris" = "yes" ; then
echo "CONFIG_SOLARIS=y" >> $config_host_mak
@ -6062,9 +6063,9 @@ fi
if test "$posix_fallocate" = "yes" ; then
echo "CONFIG_POSIX_FALLOCATE=y" >> $config_host_mak
fi
if test "$sync_file_range" = "yes" ; then
echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak
fi
#if test "$sync_file_range" = "yes" ; then
# echo "CONFIG_SYNC_FILE_RANGE=y" >> $config_host_mak
#fi
if test "$fiemap" = "yes" ; then
echo "CONFIG_FIEMAP=y" >> $config_host_mak
fi

View File

@ -0,0 +1 @@
TARGET_ARCH=e2k

View File

@ -208,6 +208,8 @@ static void initialize_debug_host(CPUDebug *s)
s->info.cap_insn_split = 6;
#elif defined(__hppa__)
s->info.print_insn = print_insn_hppa;
#elif defined(__e2k__)
s->info.print_insn = print_insn_e2k;
#endif
}

14902
disas/e2k-opc.h Normal file

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

@ -6,6 +6,7 @@ common_ss.add(when: 'CONFIG_ARM_A64_DIS', if_true: files('arm-a64.cc'))
common_ss.add_all(when: 'CONFIG_ARM_A64_DIS', if_true: libvixl_ss)
common_ss.add(when: 'CONFIG_ARM_DIS', if_true: files('arm.c'))
common_ss.add(when: 'CONFIG_CRIS_DIS', if_true: files('cris.c'))
common_ss.add(when: 'CONFIG_E2K_DIS', if_true: files('e2k.c'))
common_ss.add(when: 'CONFIG_HPPA_DIS', if_true: files('hppa.c'))
common_ss.add(when: 'CONFIG_I386_DIS', if_true: files('i386.c'))
common_ss.add(when: 'CONFIG_LM32_DIS', if_true: files('lm32.c'))

View File

@ -138,7 +138,7 @@ static FloatParts parts_default_nan(float_status *status)
/* !snan_bit_is_one, set all bits */
frac = (1ULL << DECOMPOSED_BINARY_POINT) - 1;
#elif defined(TARGET_I386) || defined(TARGET_X86_64) \
|| defined(TARGET_MICROBLAZE)
|| defined(TARGET_MICROBLAZE) || defined(TARGET_E2K)
/* !snan_bit_is_one, set sign and msb */
frac = 1ULL << (DECOMPOSED_BINARY_POINT - 1);
sign = 1;

View File

@ -44,6 +44,18 @@ typedef struct V9fsIattr {
int64_t mtime_nsec;
} V9fsIattr;
#ifdef st_atime_nsec
# undef st_atime_nsec
#endif
#ifdef st_mtime_nsec
# undef st_mtime_nsec
#endif
#ifdef st_ctime_nsec
# undef st_ctime_nsec
#endif
typedef struct V9fsStatDotl {
uint64_t st_result_mask;
V9fsQID qid;

View File

@ -2177,6 +2177,12 @@ static void handle_query_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
gdbserver_state.multiprocess = true;
}
#ifdef TARGET_E2K
// TODO: qXfer:tags:write+
// TODO: qXfer:packed_tags:read+
g_string_append(gdbserver_state.str_buf, ";qXfer:tags:read+");
#endif
g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+");
put_strbuf();
}
@ -2271,6 +2277,32 @@ static void handle_set_qemu_phy_mem_mode(GdbCmdContext *gdb_ctx, void *user_ctx)
}
#endif
#ifdef TARGET_E2K
static void handle_query_e2k_tags_read(GdbCmdContext *gdb_ctx, void *user_ctx)
{
E2KCPU *cpu = E2K_CPU(gdbserver_state.g_cpu);
CPUE2KState *env = &cpu->env;
target_ulong addr = gdb_ctx->params[0].val_ull;
unsigned long len = gdb_ctx->params[1].val_ul;
unsigned int i;
int tags = 0;
g_string_assign(gdbserver_state.str_buf, "l");
if (env->psp.base <= addr && addr < (env->psp.base + env->psp.size)) {
target_ulong offset = addr - env->psp.base;
tags = cpu_ldub_data(env, env->psp.base_tag + offset / 8);
}
for (i = 0; i < len; i++) {
int tag = (tags >> i * E2K_TAG_SIZE) & 0x3;
g_string_append_c(gdbserver_state.str_buf, tag);
}
put_packet_binary(gdbserver_state.str_buf->str,
gdbserver_state.str_buf->len, true);
}
#endif
static GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
/* Order is important if has same prefix */
{
@ -2357,6 +2389,14 @@ static GdbCmdParseEntry gdb_gen_query_table[] = {
.cmd = "qemu.PhyMemMode",
},
#endif
#ifdef TARGET_E2K
{
.handler = handle_query_e2k_tags_read,
.cmd = "Xfer:tags:read::",
.cmd_startswith = 1,
.schema = "L,l0",
},
#endif
};
static GdbCmdParseEntry gdb_gen_set_table[] = {

View File

@ -535,9 +535,23 @@ static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
rewinddir(fs->dir.stream);
}
struct DIR {
int fd_;
};
static long android_telldir(struct DIR *dirp)
{
return (long) lseek(dirp->fd_, 0, SEEK_CUR);
}
static void android_seekdir(DIR *dirp, long loc)
{
(void) lseek(dirp->fd_, loc, SEEK_SET);
}
static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs)
{
return telldir(fs->dir.stream);
return android_telldir(fs->dir.stream);
}
static bool local_is_mapped_file_metadata(FsContext *fs_ctx, const char *name)
@ -571,7 +585,7 @@ again:
static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
{
seekdir(fs->dir.stream, off);
android_seekdir(fs->dir.stream, off);
}
static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs,

View File

@ -675,9 +675,23 @@ static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
rewinddir(fs->dir.stream);
}
struct DIR {
int fd_;
};
static long android_telldir(struct DIR *dirp)
{
return (long) lseek(dirp->fd_, 0, SEEK_CUR);
}
static void android_seekdir(DIR *dirp, long loc)
{
(void) lseek(dirp->fd_, loc, SEEK_SET);
}
static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs)
{
return telldir(fs->dir.stream);
return android_telldir(fs->dir.stream);
}
static struct dirent *proxy_readdir(FsContext *ctx, V9fsFidOpenState *fs)
@ -687,7 +701,7 @@ static struct dirent *proxy_readdir(FsContext *ctx, V9fsFidOpenState *fs)
static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
{
seekdir(fs->dir.stream, off);
android_seekdir(fs->dir.stream, off);
}
static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs,

View File

@ -101,19 +101,19 @@ static FWCfgState *create_fw_cfg(MachineState *ms)
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, ms->ram_size);
val = cpu_to_le64(MIN_SEABIOS_HPPA_VERSION);
fw_cfg_add_file(fw_cfg, "/etc/firmware-min-version",
fw_cfg_add_file(fw_cfg, "@TERMUX_PREFIX@/etc/firmware-min-version",
g_memdup(&val, sizeof(val)), sizeof(val));
val = cpu_to_le64(HPPA_TLB_ENTRIES);
fw_cfg_add_file(fw_cfg, "/etc/cpu/tlb_entries",
fw_cfg_add_file(fw_cfg, "@TERMUX_PREFIX@/etc/cpu/tlb_entries",
g_memdup(&val, sizeof(val)), sizeof(val));
val = cpu_to_le64(HPPA_BTLB_ENTRIES);
fw_cfg_add_file(fw_cfg, "/etc/cpu/btlb_entries",
fw_cfg_add_file(fw_cfg, "@TERMUX_PREFIX@/etc/cpu/btlb_entries",
g_memdup(&val, sizeof(val)), sizeof(val));
val = cpu_to_le64(HPA_POWER_BUTTON);
fw_cfg_add_file(fw_cfg, "/etc/power-button-addr",
fw_cfg_add_file(fw_cfg, "@TERMUX_PREFIX@/etc/power-button-addr",
g_memdup(&val, sizeof(val)), sizeof(val));
fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ms->boot_order[0]);

View File

@ -417,7 +417,7 @@ static void clean_event_notifier(EmulatedState *card)
event_notifier_cleanup(&card->notifier);
}
#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
#define CERTIFICATES_DEFAULT_DB "@TERMUX_PREFIX@/etc/pki/nssdb"
#define CERTIFICATES_ARGS_TEMPLATE\
"db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)"

View File

@ -24,6 +24,7 @@
#include <linux/kvm.h>
#endif
#include <linux/vfio.h>
#include <linux/mman.h>
#include "hw/vfio/vfio-common.h"
#include "hw/vfio/vfio.h"

View File

@ -27,6 +27,8 @@
#include "pci.h"
#include "trace.h"
#include <linux/mman.h>
/*
* List of device ids/vendor ids for which to disable
* option rom loading. This avoids the guest hangs during rom

View File

@ -32,6 +32,7 @@
#include "standard-headers/linux/vhost_types.h"
#ifdef CONFIG_LINUX
#include <linux/mman.h>
#include <linux/userfaultfd.h>
#endif

View File

@ -235,6 +235,23 @@ enum bfd_architecture
#define bfd_mach_cris_v32 32
#define bfd_mach_cris_v10_v32 1032
bfd_arch_microblaze, /* Xilinx MicroBlaze. */
bfd_arch_e2k, /* MCST E2K. */
/* It's crucial that the underlying `bfd_mach_e2k*' have the same values as */
/* the corresponding `E_E2K_MACH_*'s!!! */
#define bfd_mach_e2k_generic 0
#define bfd_mach_e2k_ev1 1
/* This is interpreted as the common subset of all Elbrus V2 iterations.
Currently it is the same as the common subset of all elbrus-2c+. */
#define bfd_mach_e2k_ev2 2
#define bfd_mach_e2k_ev3 3
#define bfd_mach_e2k_ev4 4
#define bfd_mach_e2k_ev5 5
#define bfd_mach_e2k_ev6 6
/* Values 16, 17 and 18 used to be reserved for the first three iterations
of `elbrus-v2'. See `include/elf/e2k.h' for why they can't be reused right
now. */
#define bfd_mach_e2k_8c 19
#define bfd_mach_e2k_1cplus 20
bfd_arch_moxie, /* The Moxie core. */
bfd_arch_ia64, /* HP/Intel ia64 */
#define bfd_mach_ia64_elf64 64
@ -403,6 +420,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;
@ -459,6 +484,7 @@ int print_insn_xtensa (bfd_vma, disassemble_info*);
int print_insn_riscv32 (bfd_vma, disassemble_info*);
int print_insn_riscv64 (bfd_vma, disassemble_info*);
int print_insn_rx(bfd_vma, disassemble_info *);
int print_insn_e2k (bfd_vma, disassemble_info*);
#ifdef CONFIG_CAPSTONE
bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size);

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 */
@ -1415,6 +1418,82 @@ typedef struct {
#define EF_RISCV_RVE 0x0008
#define EF_RISCV_TSO 0x0010
/* E2k specific definitions. */
/* Values for Elf32/64_Ehdr.e_flags. */
#define EF_E2K_IPD 3
#define EF_E2K_X86APP 4
#define EF_E2K_4MB_PAGES 8
#define EF_E2K_INCOMPAT 16
#define EF_E2K_PM 32
#define EF_E2K_BUG_75842 64
/* E2k relocs. */
#define R_E2K_32_ABS 0 /* Direct 32 bit */
#define R_E2K_32_PC 2 /* PC relative 32 bit */
#define R_E2K_32_JMP_SLOT 8 /* Create PLT entry */
#define R_E2K_32_COPY 9 /* Copy relocation */
#define R_E2K_32_RELATIVE 10 /* Adjust by program base */
#define R_E2K_32_IRELATIVE 11
#define R_E2K_32_SIZE 12
#define R_E2K_64_ABS 50 /* Direct 64 bit */
#define R_E2K_64_ABS_LIT 51 /* Direct 64 bit for literal */
#define R_E2K_64_PC_LIT 54 /* PC relative 64 bit for literal */
#define R_E2K_64_JMP_SLOT 63 /* Create PLT entry */
#define R_E2K_64_COPY 64 /* Copy relocation */
#define R_E2K_64_RELATIVE 65 /* Adjust by program base */
#define R_E2K_64_RELATIVE_LIT 66 /* Adjust by program base for literal */
#define R_E2K_64_IRELATIVE 67
#define R_E2K_64_SIZE 68
#define R_E2K_64_GOTOFF 69
#define R_E2K_TLS_GDMOD 70
#define R_E2K_TLS_GDREL 71
#define R_E2K_TLS_IE 74
#define R_E2K_32_TLS_LE 75
#define R_E2K_64_TLS_LE 76
#define R_E2K_TLS_32_DTPMOD 80 /* ID of module containing symbol */
#define R_E2K_TLS_32_DTPREL 81
#define R_E2K_TLS_64_DTPMOD 82 /* ID of module containing symbol */
#define R_E2K_TLS_64_DTPREL 83
#define R_E2K_TLS_32_TPREL 84
#define R_E2K_TLS_64_TPREL 85
#define R_E2K_AP 100
#define R_E2K_PL 101
#define R_E2K_GOT 108 /* 32 bit GOT entry */
#define R_E2K_GOTOFF 109 /* 32 bit offset to GOT */
#define R_E2K_DISP 110 /* PC relative 28 bit for DISP */
#define R_E2K_PREF 111
#define R_E2K_NONE 112 /* No reloc */
/* Legal values for d_tag field of Elf32_Dyn. */
/* FIXME: find out whether old dynamic tags may be renamed and their names
* be used by modern ones or new names should be customized for modern tags.
* This concerns DT_E2K_LAZY renamed to DT_E2K_LAZY_DEFECTIVE. */
#define DT_E2K_LAZY_DEFECTIVE (DT_LOPROC + 0)
#define DT_E2K_LAZY (DT_LOPROC + 1)
/* This tag will be hopefully used for a limited period of time. `DT_LOPROC + 1'
* has already been reserved in glibc-2.16 and binutils-2.23.1 to mark
* non-defective lazy binding implementation without this awful Bug #75842 taken
* into account. */
#define DT_E2K_LAZY_BUG_75842 (DT_LOPROC + 2)
#define DT_E2K_LAZY_GOT (DT_LOPROC + 3)
#define DT_E2K_INIT_GOT (DT_LOPROC + 0x101c)
#define DT_E2K_EXPORT_PL (DT_LOPROC + 0x101d)
#define DT_E2K_EXPORT_PLSZ (DT_LOPROC + 0x101e)
#define DT_E2K_REAL_PLTGOT (DT_LOPROC + 0x101f)
#define DT_E2K_NUM 0x1020
typedef struct elf32_rel {
Elf32_Addr r_offset;
Elf32_Word r_info;

View File

@ -11,6 +11,10 @@
#ifndef QAPI_UTIL_H
#define QAPI_UTIL_H
#include <glib.h>
typedef struct Error Error;
typedef struct QEnumLookup {
const char *const *array;
int size;

View File

@ -275,7 +275,7 @@ typedef struct TCGPool {
#define TCG_POOL_CHUNK_SIZE 32768
#define TCG_MAX_TEMPS 512
#define TCG_MAX_TEMPS 1024
#define TCG_MAX_INSNS 512
/* when the size of the arguments of a called function is smaller than

View File

@ -38,7 +38,7 @@ struct target_ucontext {
target_stack_t tuc_stack;
target_sigset_t tuc_sigmask;
/* glibc uses a 1024-bit sigset_t */
char __unused[1024 / 8 - sizeof(target_sigset_t)];
char __qemu_unused[1024 / 8 - sizeof(target_sigset_t)];
/* last for future expansion */
struct target_sigcontext tuc_mcontext;
};

View File

@ -59,7 +59,7 @@ struct target_ucontext_v2 {
target_stack_t tuc_stack;
struct target_sigcontext tuc_mcontext;
target_sigset_t tuc_sigmask; /* mask last for extensibility */
char __unused[128 - sizeof(target_sigset_t)];
char __qemu_unused[128 - sizeof(target_sigset_t)];
abi_ulong tuc_regspace[128] __attribute__((__aligned__(8)));
};

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

@ -0,0 +1,129 @@
/*
* qemu user cpu loop
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu.h"
#include "cpu_loop-common.h"
void cpu_loop(CPUE2KState *env)
{
CPUState *cs = env_cpu(env);
int trapnr;
target_siginfo_t info;
while (1) {
cpu_exec_start(cs);
trapnr = cpu_exec(cs);
cpu_exec_end(cs);
process_queued_cpu_work(cs);
switch (trapnr) {
case E2K_EXCP_SYSCALL: {
int offset = E2K_NR_COUNT + env->wd.base + env->syscall_wbs * 2;
uint64_t *regs = env->regs;
abi_ulong ret = do_syscall(env,
regs[(0 + offset) % E2K_NR_COUNT],
regs[(1 + offset) % E2K_NR_COUNT],
regs[(2 + offset) % E2K_NR_COUNT],
regs[(3 + offset) % E2K_NR_COUNT],
regs[(4 + offset) % E2K_NR_COUNT],
regs[(5 + offset) % E2K_NR_COUNT],
regs[(6 + offset) % E2K_NR_COUNT],
regs[(7 + offset) % E2K_NR_COUNT],
regs[(8 + offset) % E2K_NR_COUNT]
);
if (ret == -TARGET_ERESTARTSYS) {
/* TODO: restart syscall */
abort();
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
unsigned int i;
env->regs[offset % E2K_NR_COUNT] = ret;
env->tags[offset % E2K_NR_COUNT] = 0;
for (i = 1; i < 8; i++) {
int idx = (offset + i) % E2K_NR_COUNT;
env->regs[idx] = 0;
env->tags[idx] = E2K_TAG_NON_NUMBER64;
}
}
break;
}
case E2K_EXCP_ILLOPC:
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPC;
info._sifields._sigfault._addr = env->ip;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case E2K_EXCP_ILLOPN:
info.si_signo = TARGET_SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->ip;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case E2K_EXCP_MAPERR:
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->ip;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
/* QEMU common interrupts */
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
case EXCP_DEBUG:
{
info.si_signo = TARGET_SIGTRAP;
info.si_errno = 0;
info.si_code = TARGET_TRAP_BRKPT;
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
}
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
case EXCP_HLT:
case EXCP_HALTED:
case EXCP_YIELD:
fprintf(stderr, "Unhandled QEMU trap: 0x%x\n", trapnr);
break;
default:
fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(cs, stderr, 0);
exit(EXIT_FAILURE);
}
process_pending_signals (env);
}
}
void target_cpu_copy_regs(CPUE2KState *env, struct target_pt_regs *regs)
{
env->ip = regs->ip;
env->pcsp = regs->pcsp;
env->psp = regs->psp;
env->usd.lo = regs->usd_lo;
env->usd.hi = regs->usd_hi;
env->sbr = regs->sbr;
e2k_break_save_state(env);
}

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

@ -0,0 +1,112 @@
/*
* Emulation of Linux signals
*
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2020 Alibek Omarov
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu.h"
#include "signal-common.h"
#include "linux-user/trace.h"
#define MAX_TC_SIZE 10
#define TIR_NUM 19
#define DAM_ENTRIES_NUM 32
#define SBBP_ENTRIES_NUM 32
/* from user.h !!! */
#define MLT_NUM (16 * 3) /* common for E3M and E3S */
struct target_sigcontext {
abi_ulong cr0_lo;
abi_ulong cr0_hi;
abi_ulong cr1_lo;
abi_ulong cr1_hi;
abi_ulong sbr; /* 21 Stack base register: top of */
/* local data (user) stack */
abi_ulong usd_lo; /* 22 Local data (user) stack */
abi_ulong usd_hi; /* 23 descriptor: base & size */
abi_ulong psp_lo; /* 24 Procedure stack pointer: */
abi_ulong psp_hi; /* 25 base & index & size */
abi_ulong pcsp_lo; /* 26 Procedure chain stack */
abi_ulong pcsp_hi; /* 27 pointer: base & index & size */
/*
* additional part (for binary compiler)
*/
uint8_t bincomp_padding[sizeof(abi_ulong)*184 + 10];
#if 0
abi_ulong rpr_hi;
abi_ulong rpr_lo;
abi_ulong nr_TIRs;
abi_ulong tir_lo[TIR_NUM];
abi_ulong tir_hi[TIR_NUM];
abi_ulong trap_cell_addr[MAX_TC_SIZE];
abi_ulong trap_cell_val[MAX_TC_SIZE];
uint8_t trap_cell_tag[MAX_TC_SIZE];
abi_ulong trap_cell_info[MAX_TC_SIZE];
abi_ulong dam[DAM_ENTRIES_NUM];
abi_ulong sbbp[SBBP_ENTRIES_NUM];
abi_ulong mlt[MLT_NUM];
abi_ulong upsr;
#endif
};
#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
void setup_frame(int sig, struct target_sigaction *ka,
target_sigset_t *set, CPUE2KState *env)
{
// TODO: setup_frame
qemu_log_mask(LOG_UNIMP, "setup_frame: not implemented\n");
}
void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUE2KState *env)
{
// TODO: setup_rt_frame
qemu_log_mask(LOG_UNIMP, "setup_rt_frame: not implemented\n");
}
long do_sigreturn(CPUE2KState *env)
{
// TODO: do_sigreturn
qemu_log_mask(LOG_UNIMP, "do_sigreturn: not implemented\n");
return 0;
}
long do_rt_sigreturn(CPUE2KState *env)
{
trace_user_do_rt_sigreturn(env, 0);
// TODO: do_rt_sigreturn
qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n");
return -TARGET_ENOSYS;
}
abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
abi_ulong unew_ctx, abi_long ctx_size)
{
// TODO: do_swapcontext
qemu_log_mask(LOG_UNIMP, "do_swapcontext: not implemented\n");
return 0;
}

View File

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

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

@ -0,0 +1,405 @@
/*
* This file contains the system call numbers.
*/
#ifndef E2K_SYSCALL_NR_H
#define E2K_SYSCALL_NR_H
#define TARGET_NR_restart_syscall 0
#define TARGET_NR_exit 1
#define TARGET_NR_fork 2
#define TARGET_NR_read 3
#define TARGET_NR_write 4
#define TARGET_NR_open 5
#define TARGET_NR_close 6
#define TARGET_NR_waitpid 7
#define TARGET_NR_creat 8
#define TARGET_NR_link 9
#define TARGET_NR_unlink 10
#define TARGET_NR_execve 11
#define TARGET_NR_chdir 12
#define TARGET_NR_time 13
#define TARGET_NR_mknod 14
#define TARGET_NR_chmod 15
#define TARGET_NR_lchown 16
#define TARGET_NR_break 17
#define TARGET_NR_oldstat 18
#define TARGET_NR_lseek 19
#define TARGET_NR_getpid 20
#define TARGET_NR_mount 21
#define TARGET_NR_umount 22
#define TARGET_NR_setuid 23
#define TARGET_NR_getuid 24
#define TARGET_NR_stime 25
#define TARGET_NR_ptrace 26
#define TARGET_NR_alarm 27
#define TARGET_NR_oldfstat 28
#define TARGET_NR_pause 29
#define TARGET_NR_utime 30
#define TARGET_NR_stty 31
#define TARGET_NR_gtty 32
#define TARGET_NR_access 33
#define TARGET_NR_nice 34
#define TARGET_NR_ftime 35
#define TARGET_NR_sync 36
#define TARGET_NR_kill 37
#define TARGET_NR_rename 38
#define TARGET_NR_mkdir 39
#define TARGET_NR_rmdir 40
#define TARGET_NR_dup 41
#define TARGET_NR_pipe 42
#define TARGET_NR_times 43
#define TARGET_NR_prof 44
#define TARGET_NR_brk 45
#define TARGET_NR_setgid 46
#define TARGET_NR_getgid 47
#define TARGET_NR_signal 48
#define TARGET_NR_geteuid 49
#define TARGET_NR_getegid 50
#define TARGET_NR_acct 51
#define TARGET_NR_umount2 52
#define TARGET_NR_lock 53
#define TARGET_NR_ioctl 54
#define TARGET_NR_fcntl 55
#define TARGET_NR_mpx 56
#define TARGET_NR_setpgid 57
#define TARGET_NR_ulimit 58
#define TARGET_NR_oldolduname 59
#define TARGET_NR_umask 60
#define TARGET_NR_chroot 61
#define TARGET_NR_ustat 62
#define TARGET_NR_dup2 63
#define TARGET_NR_getppid 64
#define TARGET_NR_getpgrp 65
#define TARGET_NR_setsid 66
#define TARGET_NR_sigaction 67
#define TARGET_NR_sgetmask 68
#define TARGET_NR_ssetmask 69
#define TARGET_NR_setreuid 70
#define TARGET_NR_setregid 71
#define TARGET_NR_sigsuspend 72
#define TARGET_NR_sigpending 73
#define TARGET_NR_sethostname 74
#define TARGET_NR_setrlimit 75
#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
#define TARGET_NR_getrusage 77
#define TARGET_NR_gettimeofday 78
#define TARGET_NR_settimeofday 79
#define TARGET_NR_getgroups 80
#define TARGET_NR_setgroups 81
#define TARGET_NR_select 82
#define TARGET_NR_symlink 83
#define TARGET_NR_oldlstat 84
#define TARGET_NR_readlink 85
#define TARGET_NR_uselib 86
#define TARGET_NR_swapon 87
#define TARGET_NR_reboot 88
#define TARGET_NR_readdir 89
#define TARGET_NR_mmap 90
#define TARGET_NR_munmap 91
#define TARGET_NR_truncate 92
#define TARGET_NR_ftruncate 93
#define TARGET_NR_fchmod 94
#define TARGET_NR_fchown 95
#define TARGET_NR_getpriority 96
#define TARGET_NR_setpriority 97
#define TARGET_NR_profil 98
#define TARGET_NR_statfs 99
#define TARGET_NR_fstatfs 100
#define TARGET_NR_ioperm 101
#define TARGET_NR_socketcall 102
#define TARGET_NR_syslog 103
#define TARGET_NR_setitimer 104
#define TARGET_NR_getitimer 105
#define TARGET_NR_stat 106
#define TARGET_NR_lstat 107
#define TARGET_NR_fstat 108
#define TARGET_NR_olduname 109
#define TARGET_NR_iopl 110
#define TARGET_NR_vhangup 111
#define TARGET_NR_idle 112
#define TARGET_NR_vm86old 113
#define TARGET_NR_wait4 114
#define TARGET_NR_swapoff 115
#define TARGET_NR_sysinfo 116
#define TARGET_NR_ipc 117
#define TARGET_NR_fsync 118
#define TARGET_NR_sigreturn 119
#define TARGET_NR_clone 120
#define TARGET_NR_setdomainname 121
#define TARGET_NR_uname 122
#define TARGET_NR_modify_ldt 123
#define TARGET_NR_adjtimex 124
#define TARGET_NR_mprotect 125
#define TARGET_NR_sigprocmask 126
#define TARGET_NR_create_module 127
#define TARGET_NR_init_module 128
#define TARGET_NR_delete_module 129
#define TARGET_NR_get_kernel_syms 130
#define TARGET_NR_quotactl 131
#define TARGET_NR_getpgid 132
#define TARGET_NR_fchdir 133
#define TARGET_NR_bdflush 134
#define TARGET_NR_sysfs 135
#define TARGET_NR_personality 136
#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
#define TARGET_NR_setfsuid 138
#define TARGET_NR_setfsgid 139
#define TARGET_NR__llseek 140
#define TARGET_NR_getdents 141
#define TARGET_NR__newselect 142
#define TARGET_NR_flock 143
#define TARGET_NR_msync 144
#define TARGET_NR_readv 145
#define TARGET_NR_writev 146
#define TARGET_NR_getsid 147
#define TARGET_NR_fdatasync 148
#define TARGET_NR__sysctl 149
#define TARGET_NR_mlock 150
#define TARGET_NR_munlock 151
#define TARGET_NR_mlockall 152
#define TARGET_NR_munlockall 153
#define TARGET_NR_sched_setparam 154
#define TARGET_NR_sched_getparam 155
#define TARGET_NR_sched_setscheduler 156
#define TARGET_NR_sched_getscheduler 157
#define TARGET_NR_sched_yield 158
#define TARGET_NR_sched_get_priority_max 159
#define TARGET_NR_sched_get_priority_min 160
#define TARGET_NR_sched_rr_get_interval 161
#define TARGET_NR_nanosleep 162
#define TARGET_NR_mremap 163
#define TARGET_NR_setresuid 164
#define TARGET_NR_getresuid 165
#define TARGET_NR_vm86 166
#define TARGET_NR_query_module 167
#define TARGET_NR_poll 168
#define TARGET_NR_nfsservctl 169
#define TARGET_NR_setresgid 170
#define TARGET_NR_getresgid 171
#define TARGET_NR_prctl 172
#define TARGET_NR_rt_sigreturn 173
#define TARGET_NR_rt_sigaction 174
#define TARGET_NR_rt_sigprocmask 175
#define TARGET_NR_rt_sigpending 176
#define TARGET_NR_rt_sigtimedwait 177
#define TARGET_NR_rt_sigqueueinfo 178
#define TARGET_NR_rt_sigsuspend 179
#define TARGET_NR_pread 180
#define TARGET_NR_pwrite 181
#define TARGET_NR_chown 182
#define TARGET_NR_getcwd 183
#define TARGET_NR_capget 184
#define TARGET_NR_capset 185
#define TARGET_NR_sigaltstack 186
#define TARGET_NR_sendfile 187
#define TARGET_NR_getpmsg 188 /* some people actually want streams */
#define TARGET_NR_putpmsg 189 /* some people actually want streams */
#define TARGET_NR_vfork 190
#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
#define TARGET_NR_mmap2 192
#define TARGET_NR_truncate64 193
#define TARGET_NR_ftruncate64 194
#define TARGET_NR_stat64 195
#define TARGET_NR_lstat64 196
#define TARGET_NR_fstat64 197
#define TARGET_NR_lchown32 198
#define TARGET_NR_getuid32 199
#define TARGET_NR_getgid32 200
#define TARGET_NR_geteuid32 201
#define TARGET_NR_getegid32 202
#define TARGET_NR_setreuid32 203
#define TARGET_NR_setregid32 204
#define TARGET_NR_getgroups32 205
#define TARGET_NR_setgroups32 206
#define TARGET_NR_fchown32 207
#define TARGET_NR_setresuid32 208
#define TARGET_NR_getresuid32 209
#define TARGET_NR_setresgid32 210
#define TARGET_NR_getresgid32 211
#define TARGET_NR_chown32 212
#define TARGET_NR_setuid32 213
#define TARGET_NR_setgid32 214
#define TARGET_NR_setfsuid32 215
#define TARGET_NR_setfsgid32 216
#define TARGET_NR_pivot_root 217
#define TARGET_NR_mincore 218
#define TARGET_NR_madvise 219
#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
#define TARGET_NR_getdents64 220
#define TARGET_NR_fcntl64 221
#define TARGET_NR_core 222 /* for analys kernel core */
#define TARGET_NR_macctl 223 /* MCST trust linux */
#define TARGET_NR_newfstatat 224
#define TARGET_NR_emergency 225
#define TARGET_NR_e2k_sigsetjmp 226 /* setjmp e2k specific */
#define TARGET_NR_e2k_longjmp 227 /* longjmp e2k specific */
#define TARGET_NR_e2k_syswork 228 /* e2k_syswork */
#define TARGET_NR_clone2 229
#define TARGET_NR_e2k_longjmp2 230 /* Second Edition */
#define TARGET_NR_soft_debug 231
#define TARGET_NR_setxattr 232
#define TARGET_NR_lsetxattr 233
#define TARGET_NR_fsetxattr 234
#define TARGET_NR_getxattr 235
#define TARGET_NR_lgetxattr 236
#define TARGET_NR_fgetxattr 237
#define TARGET_NR_listxattr 238
#define TARGET_NR_llistxattr 239
#define TARGET_NR_flistxattr 240
#define TARGET_NR_removexattr 241
#define TARGET_NR_lremovexattr 242
#define TARGET_NR_fremovexattr 243
#define TARGET_NR_gettid 244
#define TARGET_NR_readahead 245
#define TARGET_NR_tkill 246
#define TARGET_NR_sendfile64 247
#define TARGET_NR_futex 248
#define TARGET_NR_sched_setaffinity 249
#define TARGET_NR_sched_getaffinity 250
#define TARGET_NR_pipe2 251
#define TARGET_NR_set_backtrace 252
#define TARGET_NR_get_backtrace 253
#define TARGET_NR_access_hw_stacks 254
#define TARGET_NR_el_posix 255
/*
* reserved for update of kernel source codes
*/
#define TARGET_NR_reserved6 256
#define TARGET_NR_reserved7 257
#define TARGET_NR_reserved8 258
#define TARGET_NR_set_tid_address 259
#define TARGET_NR_el_binary 260
#define TARGET_NR_timer_create 261
#define TARGET_NR_timer_settime 262
#define TARGET_NR_timer_gettime 263
#define TARGET_NR_timer_getoverrun 264
#define TARGET_NR_timer_delete 265
#define TARGET_NR_clock_settime 266
#define TARGET_NR_clock_gettime 267
#define TARGET_NR_clock_getres 268
#define TARGET_NR_clock_nanosleep 269
/*
* reserved for update of kernel source codes
*/
#define TARGET_NR_reserved9 270
#define TARGET_NR_reserved10 271
#define TARGET_NR_reserved11 272
#define TARGET_NR_reserved12 273
#define TARGET_NR_reserved13 274
#define TARGET_NR_reserved14 275
#define TARGET_NR_reserved15 276
#define TARGET_NR_reserved16 277
#define TARGET_NR_reserved17 278
#define TARGET_NR_reserved18 279
#define TARGET_NR_reserved19 280
#define TARGET_NR_reserved20 281
#define TARGET_NR_reserved21 282
#define TARGET_NR_reserved22 283
#define TARGET_NR_reserved23 284
#define TARGET_NR_reserved24 285
#define TARGET_NR_reserved25 286
#define TARGET_NR_sched_setattr 287
#define TARGET_NR_sched_getattr 288
#define TARGET_NR_ioprio_set 289
#define TARGET_NR_ioprio_get 290
#define TARGET_NR_inotify_init 291
#define TARGET_NR_inotify_add_watch 292
#define TARGET_NR_inotify_rm_watch 293
#define TARGET_NR_io_setup 294
#define TARGET_NR_io_destroy 295
#define TARGET_NR_io_getevents 296
#define TARGET_NR_io_submit 297
#define TARGET_NR_io_cancel 298
#define TARGET_NR_fadvise64 299
#define TARGET_NR_exit_group 300
#define TARGET_NR_lookup_dcookie 301
#define TARGET_NR_epoll_create 302
#define TARGET_NR_epoll_ctl 303
#define TARGET_NR_epoll_wait 304
#define TARGET_NR_remap_file_pages 305
#define TARGET_NR_statfs64 306
#define TARGET_NR_fstatfs64 307
#define TARGET_NR_tgkill 308
#define TARGET_NR_utimes 309
#define TARGET_NR_fadvise64_64 310
#define TARGET_NR_vserver 311
#define TARGET_NR_mbind 312
#define TARGET_NR_get_mempolicy 313
#define TARGET_NR_set_mempolicy 314
#define TARGET_NR_mq_open 315
#define TARGET_NR_mq_unlink (TARGET_NR_mq_open+1)
#define TARGET_NR_mq_timedsend (TARGET_NR_mq_open+2)
#define TARGET_NR_mq_timedreceive (TARGET_NR_mq_open+3)
#define TARGET_NR_mq_notify (TARGET_NR_mq_open+4)
#define TARGET_NR_mq_getsetattr (TARGET_NR_mq_open+5)
#define TARGET_NR_kexec_load 321
#define TARGET_NR_waitid 322
#define TARGET_NR_add_key 323
#define TARGET_NR_request_key 324
#define TARGET_NR_keyctl 325
#define TARGET_NR_mcst_rt 326
#define TARGET_NR_getcpu 327
#define TARGET_NR_move_pages 328
#define TARGET_NR_splice 329
#define TARGET_NR_vmsplice 330
#define TARGET_NR_tee 331
#define TARGET_NR_migrate_pages 332
#define TARGET_NR_utimensat 333
#define TARGET_NR_rt_tgsigqueueinfo 334
#define TARGET_NR_openat 335
#define TARGET_NR_mkdirat 336
#define TARGET_NR_mknodat 337
#define TARGET_NR_fchownat 338
#define TARGET_NR_unlinkat 339
#define TARGET_NR_renameat 340
#define TARGET_NR_linkat 341
#define TARGET_NR_symlinkat 342
#define TARGET_NR_readlinkat 343
#define TARGET_NR_fchmodat 344
#define TARGET_NR_faccessat 345
#define TARGET_NR_epoll_pwait 346
#define TARGET_NR_signalfd4 347
#define TARGET_NR_eventfd2 348
#define TARGET_NR_recvmmsg 349
#define TARGET_NR_cnt_point 350
#define TARGET_NR_timerfd_create 351
#define TARGET_NR_timerfd_settime 352
#define TARGET_NR_timerfd_gettime 353
#define TARGET_NR_preadv 354
#define TARGET_NR_pwritev 355
#define TARGET_NR_fallocate 356
#define TARGET_NR_sync_file_range 357
#define TARGET_NR_dup3 358
#define TARGET_NR_inotify_init1 359
#define TARGET_NR_epoll_create1 360
#define TARGET_NR_fstatat64 361
#define TARGET_NR_futimesat 362
#define TARGET_NR_perf_event_open 363
#define TARGET_NR_unshare 364
#define TARGET_NR_get_robust_list 365
#define TARGET_NR_set_robust_list 366
#define TARGET_NR_pselect6 367
#define TARGET_NR_ppoll 368
#define TARGET_NR_setcontext 369
#define TARGET_NR_makecontext 370
#define TARGET_NR_swapcontext 371
#define TARGET_NR_freecontext 372
#define TARGET_NR_fanotify_init 373
#define TARGET_NR_fanotify_mark 374
#define TARGET_NR_prlimit64 375
#define TARGET_NR_clock_adjtime 376
#define TARGET_NR_syncfs 377
#define TARGET_NR_sendmmsg 378
#define TARGET_NR_setns 379
#define TARGET_NR_process_vm_readv 380
#define TARGET_NR_process_vm_writev 381
#define TARGET_NR_kcmp 382
#define TARGET_NR_finit_module 383
#define TARGET_NR_syscalls 384
#endif /* E2K_SYSCALL_NR_H */

View File

@ -0,0 +1,42 @@
#ifndef E2K_TARGET_CPU_H
#define E2K_TARGET_CPU_H
#include "qemu/log.h"
static inline void cpu_clone_regs_child(CPUE2KState *env, target_ulong newsp,
unsigned flags)
{
if (newsp) {
// FIXME: what size must be?
env->usd.size = 0x20000;
env->usd.base = newsp;
env->usd.read = 1;
env->usd.write = 1;
}
}
static inline void cpu_clone_regs_parent(CPUE2KState *env, unsigned flags)
{
qemu_log_mask(LOG_UNIMP, "cpu_clone_regs_parent: unimplemented\n");
// TODO: cpu_clone_regs_parent
}
static inline void cpu_set_tls(CPUE2KState *env, target_ulong newtls)
{
qemu_log_mask(LOG_UNIMP, "cpu_set_tls: unimplemented\n");
// TODO: cpu_set_tls
}
static inline target_ulong cpu_get_tls(CPUE2KState *env)
{
// TODO: cpu_get_tls
qemu_log_mask(LOG_UNIMP, "cpu_get_tls: unimplemented\n");
return 0;
}
static inline abi_ulong get_sp_from_cpustate(CPUE2KState *env)
{
return env->usd.base;
}
#endif /* E2K_TARGET_CPU_H */

View File

@ -0,0 +1,7 @@
#ifndef E2K_TARGET_ELF_H
#define E2K_TARGET_ELF_H
static inline const char *cpu_get_model(uint32_t eflags)
{
return "any";
}
#endif /* E2K_TARGET_ELF_H */

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,27 @@
#ifndef TARGET_SIGNAL_H
#define TARGET_SIGNAL_H
/*
* sigaltstack controls
*/
#define TARGET_SS_ONSTACK 1
#define TARGET_SS_DISABLE 2
#define TARGET_MINSIGSTKSZ 4096
#define TARGET_SIGSTKSZ 8192
#define TARGET_MCL_CURRENT 1
#define TARGET_MCL_FUTURE 2
// TODO: check
#define TARGET_MCL_ONFAULT 4
#define TARGET_ARCH_HAS_SETUP_FRAME
typedef struct target_sigaltstack {
abi_ulong ss_sp;
abi_int ss_flags;
abi_ulong ss_size;
} target_stack_t;
#include "../generic/signal.h"
#endif /* TARGET_SIGNAL_H */

View File

@ -0,0 +1,28 @@
#ifndef E2K_TARGET_STRUCTS_H
#define E2K_TARGET_STRUCTS_H
struct target_ipc_perm {
abi_int __key;
abi_uint uid;
abi_uint gid;
abi_uint cuid;
abi_uint cgid;
abi_uint mode;
abi_ushort __seq;
};
struct target_shmid_ds {
struct target_ipc_perm shm_perm;
abi_int shm_segsz;
abi_long shm_atime;
abi_long shm_dtime;
abi_long shm_ctime;
abi_int shm_cpid;
abi_int shm_lpid;
abi_ushort shm_nattch;
abi_ushort shm_unused;
void *shm_unused2;
void *shm_unused3;
};
#endif

View File

@ -0,0 +1,66 @@
#ifndef E2K_TARGET_SYSCALL_H
#define E2K_TARGET_SYSCALL_H
#define UNAME_MACHINE "e2k"
#define UNAME_MINIMUM_RELEASE "2.6.32"
#define E2K_MAXNR 128 /* The total number of */
/* quad-NRs */
#define E2K_MAXGR 16 /* The total number of global */
/* quad-NRs */
#define E2K_MAXSR (E2K_MAXNR - E2K_MAXGR) /* The total number of stack */
/* quad-NRs */
#define E2K_MAXNR_d (E2K_MAXNR * 2) /* The total number of */
/* double-NRs */
#define E2K_MAXGR_d (E2K_MAXGR * 2) /* The total number of global */
/* double-NRs */
#define E2K_MAXSR_d (E2K_MAXSR * 2) /* The total number of stack */
/* double-NRs */
typedef uint64_t e2k_greg_t; // double word
struct target_pt_regs {
/* special registers */
uint64_t wd; // Current window descriptor (WD)
uint64_t sbr; // User Stack Base Register (USBR/SBR)
// SBR - contains the base (top) virtual address of the current User Stack area.
// uint64_t tr; // current type register
E2KPcsState pcsp;
E2KPsState psp;
uint32_t psr; // Processor State Register (PSR)
uint32_t upsr; // User processor status register (UPSR)
uint64_t ip; // instruction pointer
uint64_t nip; // next instruction pointer
uint64_t ctpr1; // Control Transfer Preparation Register (CTPR)
uint64_t ctpr2;
uint64_t ctpr3;
uint32_t pfpfr; // Packed Floating Point Flag Register (PFPFR)
uint32_t fpcr; // Floating point control register (FPCR)
uint32_t fpsr; // Floating point state register (FPSR)
// borrowed from Embox OS
uint64_t lsr; // Loop status register (LSR)
uint64_t ilcr; // Loop counter register (ILCR)
uint64_t dr0;
uint64_t cr0_hi;
uint64_t cr1_lo;
uint64_t cr1_hi;
uint64_t pcsp_hi;
uint64_t pcsp_lo;
uint64_t usd_lo; // User data
uint64_t usd_hi;
uint64_t gbase[32];
uint16_t gext[32];
};
#endif /* E2K_TARGET_SYSCALL_H */

View File

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

View File

@ -2,6 +2,8 @@
#include "qemu/osdep.h"
#include <sys/param.h>
#include <linux/mman.h>
#include <sys/resource.h>
#include <sys/shm.h>
@ -1485,6 +1487,73 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
#endif /* TARGET_XTENSA */
#ifdef TARGET_E2K
#define elf_check_arch(x) ((x) == EM_MCST_ELBRUS || (x) == EM_E2K_OLD)
#define ELF_START_MMAP 0x80000000
#define ELF_CLASS ELFCLASS64
#define ELF_ARCH EM_MCST_ELBRUS
#define ELF_EXEC_PAGESIZE 4096
#define ELF_NREG 256
typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
#define USE_ELF_CORE_DUMP
static inline abi_ulong e2k_mmap(abi_ulong size)
{
abi_ulong addr;
abi_ulong guard = TARGET_PAGE_SIZE;
if (size < TARGET_PAGE_SIZE) {
size = TARGET_PAGE_SIZE;
}
if (guard < qemu_real_host_page_size) {
guard = qemu_real_host_page_size;
}
addr = target_mmap(0, size + guard, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (addr == -1) {
perror("mmap e2k stack");
exit(-1);
}
target_mprotect(addr + size, guard, PROT_NONE);
return addr;
}
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
{
abi_ulong start_stack = infop->start_stack & ~0xf;
regs->ip = infop->entry;
// FIXME: set real start stack address
regs->sbr = infop->arg_strings & ~0xf;
regs->usd_lo = (0x1800UL << 48) | start_stack;
regs->usd_hi = (regs->sbr - start_stack) << 32;
regs->pcsp.is_readable = true;
regs->pcsp.is_writable = true;
regs->pcsp.index = 0;
regs->pcsp.size = TARGET_PAGE_SIZE;
regs->pcsp.base = e2k_mmap(regs->pcsp.size);
regs->psp.is_readable = true;
regs->psp.is_writable = true;
regs->psp.index = 0;
regs->psp.size = TARGET_PAGE_SIZE * 8;
regs->psp.base = e2k_mmap(regs->psp.size);
regs->psp.base_tag = e2k_mmap(regs->psp.size / 8);
}
static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUE2KState *env)
{
/* TODO */
qemu_log_mask(LOG_UNIMP, "elf_core_copy_regs: not implemented\n");
}
#endif /* TARGET_E2K */
#ifndef ELF_PLATFORM
#define ELF_PLATFORM (NULL)
#endif
@ -2379,7 +2448,7 @@ void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
abi_ulong guest_hiaddr)
{
/* In order to use host shmat, we must be able to honor SHMLBA. */
uintptr_t align = MAX(SHMLBA, qemu_host_page_size);
uintptr_t align = MAX(/* SHMLBA */ getpagesize(), qemu_host_page_size);
if (have_guest_base) {
pgb_have_guest_base(image_name, guest_loaddr, guest_hiaddr, align);

View File

@ -35,6 +35,8 @@
#include "qemu/osdep.h"
#include <linux/mman.h>
#include "qemu.h"
#include "flat.h"
#include "target_flat.h"

View File

@ -22,6 +22,8 @@
#include "qemu.h"
#include "cpu_loop-common.h"
#include <linux/mman.h>
/***********************************************************/
/* CPUX86 core interface */

View File

@ -21,6 +21,8 @@
#include "exec/log.h"
#include "qemu.h"
#include <linux/mman.h>
static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
static __thread int mmap_lock_count;

View File

@ -41,7 +41,7 @@ struct target_ucontext {
struct target_ucontext *uc_link;
target_stack_t uc_stack;
target_sigset_t uc_sigmask;
uint8_t __unused[1024 / 8 - sizeof(target_sigset_t)];
uint8_t __qemu_unused[1024 / 8 - sizeof(target_sigset_t)];
struct target_sigcontext uc_mcontext QEMU_ALIGNED(16);
};

View File

@ -198,6 +198,27 @@ int block_signals(void)
return qatomic_xchg(&ts->signal_pending, 1);
}
#ifdef _NSIG_WORDS
static int sigorset(sigset_t *dest, const sigset_t *a, const sigset_t *b)
{
int i;
if (!dest || !a || !b)
return -1;
for (i = 0; i < _NSIG_WORDS; i++)
dest->sig[i] = a->sig[i] | b->sig[i];
return 0;
}
#else
static int sigorset(sigset_t *dest, const sigset_t *a, const sigset_t *b)
{
int i;
if (!dest || !a || !b)
return -1;
*dest = *a | *b;
return 0;
}
#endif
/* Wrapper for sigprocmask function
* Emulates a sigprocmask in a safe way for the guest. Note that set and oldset
* are host signal set, not guest ones. Returns -TARGET_ERESTARTSYS if

View File

@ -1,7 +1,7 @@
#include "qemu/osdep.h"
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <linux/sem.h>
#include <sys/shm.h>
#include <sys/select.h>
#include <sys/mount.h>

View File

@ -36,6 +36,7 @@
#include <sys/resource.h>
#include <sys/swap.h>
#include <linux/capability.h>
#include <linux/mman.h>
#include <sched.h>
#include <sys/timex.h>
#include <sys/socket.h>
@ -45,7 +46,7 @@
#include <poll.h>
#include <sys/times.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <linux/sem.h>
#include <sys/statfs.h>
#include <utime.h>
#include <sys/sysinfo.h>
@ -78,12 +79,17 @@
#endif
#define termios host_termios
#define termios2 host_termios2
#define ktermios host_ktermios
#define winsize host_winsize
#define termio host_termio
#define sgttyb host_sgttyb /* same as target */
#define tchars host_tchars /* same as target */
#define ltchars host_ltchars /* same as target */
#undef __ASM_GENERIC_TERMBITS_H
#include <asm/termbits.h>
#include <linux/termios.h>
#include <linux/unistd.h>
#include <linux/cdrom.h>
@ -268,6 +274,59 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
#define __NR__llseek __NR_lseek
#endif
_syscall0(int, vhangup)
#ifdef __NR_msgctl
_syscall3(int, msgctl, int, msqid, int, cmd, struct msqid_ds *, buf)
#else
static int
msgctl (int msqid, int cmd, struct msqid_ds *buf)
{
return syscall (__NR_ipc, IPCOP_msgctl, msqid, cmd | 0x100, 0, buf);
}
#endif
#ifdef __NR_semget
_syscall3(int, semget, key_t, key, int, nsems, int, semflg)
#else
static int
semget (key_t key, int nsems, int semflg)
{
return syscall (__NR_ipc, IPCOP_semget, key, nsems, semflg, NULL);
}
#endif
_syscall2(int, setdomainname, const char *, name, size_t, len)
#ifdef __NR_msgget
_syscall2(int, msgget, key_t, key, int, msgflg)
#else
static int
msgget (key_t key, int msgflg)
{
return syscall(__NR_ipc, 5, IPCOP_msgget, key, msgflg, 0, NULL);
}
#endif
#ifdef _NSIG_WORDS
static int sigorset(sigset_t *dest, const sigset_t *a, const sigset_t *b)
{
int i;
if (!dest || !a || !b)
return -1;
for (i = 0; i < _NSIG_WORDS; i++)
dest->sig[i] = a->sig[i] | b->sig[i];
return 0;
}
#else
static int sigorset(sigset_t *dest, const sigset_t *a, const sigset_t *b)
{
int i;
if (!dest || !a || !b)
return -1;
*dest = *a | *b;
return 0;
}
#endif
/* Newer kernel ports have llseek() instead of _llseek() */
#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
#define TARGET_NR__llseek TARGET_NR_llseek
@ -812,6 +871,9 @@ safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr,
defined(TARGET_NR_mq_timedreceive_time64)
safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr,
size_t, len, unsigned *, prio, const struct timespec *, timeout)
_syscall1(int, mq_unlink, const char *, name)
_syscall4(__kernel_mqd_t, mq_open, const char *, name, int, oflag, mode_t, mode,
struct mq_attr *, attr)
#endif
/* We do ioctl like this rather than via safe_syscall3 to preserve the
* "third argument might be integer or pointer or not present" behaviour of
@ -1336,7 +1398,7 @@ static inline abi_long copy_from_user_timezone(struct timezone *tz,
#endif
#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
#include <mqueue.h>
#include <linux/mqueue.h>
static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
abi_ulong target_mq_attr_addr)
@ -3871,6 +3933,8 @@ static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr,
return 0;
}
#define semid_ds __kernel_legacy_semid_ds
static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
abi_ulong target_addr)
{
@ -3950,6 +4014,16 @@ union target_semun {
abi_ulong __buf;
};
#ifdef __NR_semctl
_syscall4(int, semctl, int, semid, int, semnum, int, cmd, union semun, arg4)
#else
static int semctl(int semid, int semnum, int cmd, union semun arg4)
{
return syscall(__NR_ipc, IPCOP_semctl, semid, semnum, cmd | 0x100,
arg4.__buf);
}
#endif
static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
abi_ulong target_addr)
{
@ -4080,7 +4154,7 @@ static inline abi_long do_semctl(int semid, int semnum, int cmd,
case GETPID:
case GETNCNT:
case GETZCNT:
ret = get_errno(semctl(semid, semnum, cmd, NULL));
ret = get_errno(semctl(semid, semnum, cmd, (union semun) {.buf = NULL}));
break;
}
@ -4215,7 +4289,7 @@ static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
host_md->msg_stime = tswapal(target_md->msg_stime);
host_md->msg_rtime = tswapal(target_md->msg_rtime);
host_md->msg_ctime = tswapal(target_md->msg_ctime);
host_md->__msg_cbytes = tswapal(target_md->__msg_cbytes);
host_md->msg_cbytes = tswapal(target_md->__msg_cbytes);
host_md->msg_qnum = tswapal(target_md->msg_qnum);
host_md->msg_qbytes = tswapal(target_md->msg_qbytes);
host_md->msg_lspid = tswapal(target_md->msg_lspid);
@ -4236,7 +4310,7 @@ static inline abi_long host_to_target_msqid_ds(abi_ulong target_addr,
target_md->msg_stime = tswapal(host_md->msg_stime);
target_md->msg_rtime = tswapal(host_md->msg_rtime);
target_md->msg_ctime = tswapal(host_md->msg_ctime);
target_md->__msg_cbytes = tswapal(host_md->__msg_cbytes);
target_md->__msg_cbytes = tswapal(host_md->msg_cbytes);
target_md->msg_qnum = tswapal(host_md->msg_qnum);
target_md->msg_qbytes = tswapal(host_md->msg_qbytes);
target_md->msg_lspid = tswapal(host_md->msg_lspid);
@ -4602,7 +4676,7 @@ static inline abi_ulong do_shmat(CPUArchState *cpu_env,
abi_ulong mmap_start;
/* In order to use the host shmat, we need to honor host SHMLBA. */
mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(SHMLBA, shmlba));
mmap_start = mmap_find_vma(0, shm_info.shm_segsz, MAX(/* SHMLBA */ getpagesize(), shmlba));
if (mmap_start == -1) {
errno = ENOMEM;
@ -5703,6 +5777,9 @@ static abi_long do_ioctl_drm_i915(const IOCTLEntry *ie, uint8_t *buf_temp,
#endif
#undef winsize
#undef termio
IOCTLEntry ioctl_entries[] = {
#define IOCTL(cmd, access, ...) \
{ TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
@ -8045,7 +8122,7 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags,
/* create temporary file to map stat to */
tmpdir = getenv("TMPDIR");
if (!tmpdir)
tmpdir = "/tmp";
tmpdir = "@TERMUX_PREFIX@/tmp";
snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
fd = mkstemp(filename);
if (fd < 0) {
@ -8599,7 +8676,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
unlock_user(p, arg1, 0);
return ret;
#endif
#ifdef TARGET_NR_stime /* not on alpha */
#if 0 //def TARGET_NR_stime /* not on alpha */
case TARGET_NR_stime:
{
struct timespec ts;
@ -8663,7 +8740,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
}
return ret;
#endif
#if defined(TARGET_NR_futimesat)
#if 0 && defined(TARGET_NR_futimesat)
case TARGET_NR_futimesat:
{
struct timeval *tvp, tv[2];
@ -12424,7 +12501,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
/* Not implemented for now... */
/* case TARGET_NR_mq_notify: */
/* break; */
#if 0
case TARGET_NR_mq_getsetattr:
{
struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
@ -12442,6 +12519,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
}
return ret;
#endif
#endif
#ifdef CONFIG_SPLICE
#ifdef TARGET_NR_tee

View File

@ -86,7 +86,7 @@
#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) || \
defined(TARGET_MIPS)
defined(TARGET_MIPS) || defined(TARGET_E2K)
#define TARGET_IOC_SIZEBITS 13
#define TARGET_IOC_DIRBITS 3
@ -1576,6 +1576,55 @@ struct target_stat64 {
unsigned int __unused2;
};
#elif defined(TARGET_E2K)
#define TARGET_STAT_HAVE_NSEC
struct target_stat {
unsigned long st_dev;
unsigned long st_ino;
unsigned int st_mode;
unsigned int st_nlink;
unsigned int st_uid;
unsigned int st_gid;
unsigned long st_rdev;
unsigned long __pad1;
long st_size;
int st_blksize;
int __pad2;
long st_blocks;
int target_st_atime;
unsigned int target_st_atime_nsec;
int target_st_mtime;
unsigned int target_st_mtime_nsec;
int target_st_ctime;
unsigned int target_st_ctime_nsec;
unsigned int __unused4;
unsigned int __unused5;
};
#define TARGET_HAS_STRUCT_STAT64
struct target_stat64 {
unsigned long long st_dev;
unsigned long long st_ino;
unsigned int st_mode;
unsigned int st_nlink;
unsigned int st_uid;
unsigned int st_gid;
unsigned long long st_rdev;
unsigned long long __pad0;
long long st_size;
int st_blksize;
int __pad1;
long long st_blocks;
int target_st_atime;
unsigned int target_st_atime_nsec;
int target_st_mtime;
unsigned int target_st_mtime_nsec;
int target_st_ctime;
unsigned int target_st_ctime_nsec;
unsigned int __unused4;
unsigned int __unused5;
};
#elif defined(TARGET_PPC)
#define TARGET_STAT_HAVE_NSEC
@ -1929,7 +1978,7 @@ struct target_stat64 {
abi_ulong target_st_mtime_nsec;
abi_ulong target_st_ctime;
abi_ulong target_st_ctime_nsec;
abi_long __unused[3];
abi_long __qemu_unused[3];
};
#elif defined(TARGET_SH4)
@ -2016,7 +2065,7 @@ struct target_stat {
abi_ulong target_st_ctime;
abi_ulong target_st_ctime_nsec;
abi_long __unused[3];
abi_long __qemu_unused[3];
};
#elif defined(TARGET_S390X)
struct target_stat {
@ -2037,7 +2086,7 @@ struct target_stat {
abi_ulong target_st_ctime_nsec;
abi_ulong st_blksize;
abi_long st_blocks;
abi_ulong __unused[3];
abi_ulong __qemu_unused[3];
};
#elif defined(TARGET_AARCH64)
#define TARGET_STAT_HAVE_NSEC
@ -2060,7 +2109,7 @@ struct target_stat {
abi_ulong target_st_mtime_nsec;
abi_long target_st_ctime;
abi_ulong target_st_ctime_nsec;
unsigned int __unused[2];
unsigned int __qemu_unused[2];
};
#elif defined(TARGET_XTENSA)
#define TARGET_STAT_HAVE_NSEC

View File

@ -94,11 +94,11 @@ endif
# Specify linker-script with add_project_link_arguments so that it is not placed
# within a linker --start-group/--end-group pair
if 'CONFIG_FUZZ' in config_host
add_project_link_arguments(['-Wl,-T,',
(meson.current_source_dir() / 'tests/qtest/fuzz/fork_fuzz.ld')],
native: false, language: ['c', 'cpp', 'objc'])
endif
#if 'CONFIG_FUZZ' in config_host
# add_project_link_arguments(['-Wl,-T,',
# (meson.current_source_dir() / 'tests/qtest/fuzz/fork_fuzz.ld')],
# native: false, language: ['c', 'cpp', 'objc'])
#endif
add_project_arguments(config_host['QEMU_CFLAGS'].split(),
native: false, language: ['c', 'objc'])
@ -884,6 +884,7 @@ disassemblers = {
'arm' : ['CONFIG_ARM_DIS'],
'avr' : ['CONFIG_AVR_DIS'],
'cris' : ['CONFIG_CRIS_DIS'],
'e2k' : ['CONFIG_E2K_DIS'],
'hppa' : ['CONFIG_HPPA_DIS'],
'i386' : ['CONFIG_I386_DIS'],
'x86_64' : ['CONFIG_I386_DIS'],
@ -1611,8 +1612,8 @@ linux_user_ss.add(files('gdbstub.c', 'thunk.c'))
specific_ss.add_all(when: 'CONFIG_LINUX_USER', if_true: linux_user_ss)
# needed for fuzzing binaries
subdir('tests/qtest/libqos')
subdir('tests/qtest/fuzz')
#subdir('tests/qtest/libqos')
#subdir('tests/qtest/fuzz')
########################
# Library dependencies #

View File

@ -28,7 +28,7 @@
void exec_start_outgoing_migration(MigrationState *s, const char *command, Error **errp)
{
QIOChannel *ioc;
const char *argv[] = { "/bin/sh", "-c", command, NULL };
const char *argv[] = { "@TERMUX_PREFIX@/bin/sh", "-c", command, NULL };
trace_migration_exec_outgoing(command);
ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv,
@ -55,7 +55,7 @@ static gboolean exec_accept_incoming_migration(QIOChannel *ioc,
void exec_start_incoming_migration(const char *command, Error **errp)
{
QIOChannel *ioc;
const char *argv[] = { "/bin/sh", "-c", command, NULL };
const char *argv[] = { "@TERMUX_PREFIX@/bin/sh", "-c", command, NULL };
trace_migration_exec_incoming(command);
ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv,

View File

@ -31,6 +31,8 @@
#include "trace.h"
#include "hw/boards.h"
#include <linux/mman.h>
/* Arbitrary limit on size of each discard command,
* keeps them around ~200 bytes
*/

View File

@ -533,7 +533,7 @@ static int net_bridge_run_helper(const char *helper, const char *bridge,
*parg++ = helper_cmd;
*parg++ = NULL;
execv("/bin/sh", args);
execv("@TERMUX_PREFIX@/bin/sh", args);
g_free(helper_cmd);
} else {
/* assume helper is just the executable path name */

View File

@ -52,7 +52,6 @@
#define HAVE_NBD_DEVICE 0
#endif
#define SOCKET_PATH "/var/lock/qemu-nbd-%s"
#define QEMU_NBD_OPT_CACHE 256
#define QEMU_NBD_OPT_AIO 257
#define QEMU_NBD_OPT_DISCARD 258
@ -91,7 +90,7 @@ static void usage(const char *name)
" -p, --port=PORT port to listen on (default `%d')\n"
" -b, --bind=IFACE interface to bind to (default `0.0.0.0')\n"
" -k, --socket=PATH path to the unix socket\n"
" (default '"SOCKET_PATH"')\n"
" (default '@TERMUX_PREFIX@/tmp/nbd-%s')\n"
" -e, --shared=NUM device can be shared by NUM clients (default '1')\n"
" -t, --persistent don't exit on the last connection\n"
" -v, --verbose display extra debugging information\n"
@ -964,7 +963,7 @@ int main(int argc, char **argv)
if (device != NULL && sockpath == NULL) {
sockpath = g_malloc(128);
snprintf(sockpath, 128, SOCKET_PATH, basename(device));
snprintf(sockpath, 128, "@TERMUX_PREFIX@/tmp/nbd-%s", basename(device));
}
server = qio_net_listener_new();

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"
microblaze microblazeel or1k x86_64 e2k"
i386_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00'
i386_mask='\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
@ -136,6 +136,10 @@ or1k_magic='\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\
or1k_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'
or1k_family=or1k
e2k_magic='\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xaf\x00'
e2k_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'
e2k_family=e2k
qemu_get_family() {
cpu=${HOST_ARCH:-$(uname -m)}
case "$cpu" in

View File

@ -92,6 +92,8 @@ int graphic_depth = 32;
#define QEMU_ARCH QEMU_ARCH_XTENSA
#elif defined(TARGET_AVR)
#define QEMU_ARCH QEMU_ARCH_AVR
#elif defined(TARGET_E2K)
#define QEMU_ARCH QEMU_ARCH_E2K
#endif
const uint32_t arch_type = QEMU_ARCH;

View File

@ -17,6 +17,8 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/mman.h>
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qapi/error.h"

View File

@ -29,6 +29,7 @@
#include <endian.h>
#if defined(__linux__)
#include <linux/mman.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <sys/ioctl.h>

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

@ -0,0 +1,16 @@
/*
* E2K cpu parameters for qemu.
*
* SPDX-License-Identifier: LGPL-2.0+
*/
#ifndef E2K_CPU_PARAM_H
#define E2K_CPU_PARAM_H 1
# define TARGET_LONG_BITS 64
# define TARGET_PAGE_BITS 12 /* 4k */
# define TARGET_PHYS_ADDR_SPACE_BITS 40
# define TARGET_VIRT_ADDR_SPACE_BITS 48
# define NB_MMU_MODES 4
#endif

50
target/e2k/cpu-qom.h Normal file
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

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

@ -0,0 +1,348 @@
/*
* Sparc CPU init helpers
*
* Copyright (c) 2003-2005 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "cpu.h"
#include "qemu/module.h"
#include "qemu/qemu-print.h"
#include "exec/exec-all.h"
#include "hw/qdev-properties.h"
#include "qapi/visitor.h"
//#define DEBUG_FEATURES
void cpu_e2k_set_id(CPUE2KState *env, unsigned int cpu);
void e2k_cpu_dump_state(CPUState *cs, FILE *f, int flags);
static void e2k_cpu_reset(DeviceState *dev)
{
CPUState *cs = CPU(dev);
E2KCPU *cpu = E2K_CPU(cs);
E2KCPUClass *ecc = E2K_CPU_GET_CLASS(cpu);
CPUE2KState *env = &cpu->env;
ecc->parent_reset(dev);
memset(env, 0, offsetof(CPUE2KState, end_reset_fields));
env->cr1.wpsz = 4;
env->cr1.wbs = 4;
env->wd.base = 0;
env->wd.size = 16;
env->wd.psize = 8;
env->bn.base = 8;
env->bn.size = 8;
env->bn.cur = 0;
env->aau.incrs[0] = 1; /* always one */
env->fpcr._one = 1;
// FIXME: testing
env->idr = 0x3a207; // mimic 8c
}
static bool e2k_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
qemu_log_mask(LOG_UNIMP, "e2k_cpu_exec_interrupt: not implemented\n");
if (interrupt_request & CPU_INTERRUPT_HARD) {
e2k_cpu_do_interrupt(cs);
return true;
}
return false;
}
void e2k_cpu_do_interrupt(CPUState *cs)
{
qemu_log_mask(LOG_UNIMP, "e2k_cpu_do_interrupt: not implemented\n");
cs->exception_index = -1;
}
static void cpu_e2k_disas_set_info(CPUState *cs, disassemble_info *info)
{
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
info->mach = env->version * 3;
info->print_insn = print_insn_e2k;
}
void cpu_e2k_set_id(CPUE2KState *env, unsigned int cpu)
{
// TODO: cpu_e2k_set_id
qemu_log_mask(LOG_UNIMP, "cpu_e2k_set_id: not implemented\n");
}
/* https://www.altlinux.org/Модели_процессоров_Эльбрус */
#define DEFAULT_CPU_MODEL "e8c"
static const struct e2k_def_t e2k_defs[] = {
{
.name = "e8c", // default choice
.canonical_name = "MCST Elbrus 8C",
.gdb_arch = "elbrus-8c",
.isa_version = 4,
},
{
.name = "e2c+", // however it works better
.canonical_name = "MCST Elbrus 2C+ (Monocube)",
.gdb_arch = "elbrus-v2",
.isa_version = 2,
},
#if 0 /* for reference, never tested */
{
.name = "e2s",
.canonical_name = "MCST Elbrus 4C",
.gdb_arch = "elbrus-v3",
.isa_version = 3,
},
{
.name = "e8c2",
.canonical_name = "MCST Elbrus 8CB",
.gdb_arch = "elbrus-v5",
.isa_version = 5,
},
{
.name = "e16c",
.canonical_name = "MCST Elbrus 16C",
.gdb_arch = "elbrus-v6",
.isa_version = 6,
},
#endif
};
static inline void cpu_dump_state_br(CPUE2KState *env, FILE *f, int flags)
{
uint32_t br = e2k_state_br(env);
E2KBnState *bn = &env->bn;
E2KBpState *bp = &env->bp;
qemu_fprintf(f, "br 0x%x\n", br);
qemu_fprintf(f, " rbs %d\n", bn->base / 2);
qemu_fprintf(f, " rsz %d\n", bn->size / 2 - 1);
qemu_fprintf(f, " rcur %d\n", bn->cur / 2);
qemu_fprintf(f, " psz %d\n", bp->size);
qemu_fprintf(f, " pcur %d\n", bp->cur);
}
void e2k_cpu_dump_state(CPUState *cs, FILE *f, int flags)
{
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
unsigned int i;
qemu_fprintf(f, " ip = 0x%016lx\n", env->ip);
qemu_fprintf(f, " pregs = 0x%016lx\n", env->pregs);
qemu_fprintf(f, " cr0_lo = 0x%016lx\n", env->cr0_lo);
qemu_fprintf(f, " cr0_hi = 0x%016lx\n", env->cr0_hi);
qemu_fprintf(f, " cr1_lo = 0x%016lx\n", env->cr1.lo);
qemu_fprintf(f, " cr1_hi = 0x%016lx\n", env->cr1.hi);
qemu_fprintf(f, " pcsp_lo = 0x%016lx\n", e2k_state_pcsp_lo(env));
qemu_fprintf(f, " pcsp_hi = 0x%016lx\n", e2k_state_pcsp_hi(env));
qemu_fprintf(f, " psp_lo = 0x%016lx\n", e2k_state_psp_lo(env));
qemu_fprintf(f, " psp_hi = 0x%016lx\n", e2k_state_psp_hi(env));
qemu_fprintf(f, " usd_lo = 0x%016lx\n", env->usd.lo);
qemu_fprintf(f, " usd_hi = 0x%016lx\n", env->usd.hi);
qemu_fprintf(f, " lsr = 0x%016lx\n", env->lsr);
cpu_dump_state_br(env, f, flags);
for (i = 0; i < E2K_REG_COUNT; i++) {
char name = i < E2K_NR_COUNT ? 'r' : 'g';
int tag = env->tags[i];
qemu_fprintf(f, "%%%c%d\t<%d%d> 0x%lx\n", name, i, tag >> 2, tag & 3,
env->regs[i]);
}
for (i = 0; i < 32; i++) {
int preg = (env->pregs >> (i * 2)) & 3;
qemu_fprintf(f, "pred%d\t<%d> %s\n", i, preg >> 1,
preg & 1 ? "true" : "false");
}
}
static void e2k_cpu_set_pc(CPUState *cs, vaddr value)
{
E2KCPU *cpu = E2K_CPU(cs);
qemu_log_mask(LOG_UNIMP, "e2k_cpu_synchronize_from_tb: not implemented\n");
cpu->env.ip = value;
}
static void e2k_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
{
E2KCPU *cpu = E2K_CPU(cs);
qemu_log_mask(LOG_UNIMP, "e2k_cpu_synchronize_from_tb: not implemented\n");
cpu->env.ip = tb->pc;
}
static bool e2k_cpu_has_work(CPUState *cs)
{
// TODO: e2k_cpu_has_work
qemu_log_mask(LOG_UNIMP, "e2k_cpu_has_work: not implemented\n");
return true;
}
static char *e2k_cpu_type_name(const char *cpu_model)
{
return g_strdup(cpu_model);
}
static ObjectClass *e2k_cpu_class_by_name(const char *cpu_model)
{
ObjectClass *oc;
char *typename;
#ifdef CONFIG_USER_ONLY
if (!strcasecmp(cpu_model, "any")) {
cpu_model = DEFAULT_CPU_MODEL;
}
#endif // CONFIG_USER_ONLY
typename = e2k_cpu_type_name(cpu_model);
oc = object_class_by_name(typename);
g_free(typename);
return oc;
}
static void e2k_cpu_realizefn(DeviceState *dev, Error **errp)
{
CPUState *cs = CPU(dev);
E2KCPUClass *ecc = E2K_CPU_GET_CLASS(dev);
Error *local_err = NULL;
E2KCPU *cpu = E2K_CPU(dev);
CPUE2KState *env = &cpu->env;
env->version = env->def.isa_version;
cpu_exec_realizefn(cs, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
qemu_init_vcpu(cs);
ecc->parent_realize(dev, errp);
}
static void e2k_cpu_initfn(Object* obj)
{
E2KCPU *cpu = E2K_CPU(obj);
E2KCPUClass *ecc = E2K_CPU_GET_CLASS(obj);
CPUE2KState *env = &cpu->env;
cpu_set_cpustate_pointers(cpu);
if (ecc->cpu_def) {
env->def = *ecc->cpu_def;
}
}
static gchar* e2k_cpu_gdb_arch_name(CPUState *cs)
{
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
return g_strdup_printf("%s:%d", env->def.gdb_arch, TARGET_LONG_BITS);
}
static void e2k_cpu_class_init(ObjectClass *oc, void *data)
{
E2KCPUClass *ecc = E2K_CPU_CLASS(oc);
CPUClass *cc = CPU_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
device_class_set_parent_realize(dc, e2k_cpu_realizefn,
&ecc->parent_realize);
device_class_set_parent_reset(dc, e2k_cpu_reset, &ecc->parent_reset);
cc->has_work = e2k_cpu_has_work;
cc->dump_state = e2k_cpu_dump_state;
cc->set_pc = e2k_cpu_set_pc;
cc->do_interrupt = e2k_cpu_do_interrupt;
cc->cpu_exec_interrupt = e2k_cpu_exec_interrupt;
cc->synchronize_from_tb = e2k_cpu_synchronize_from_tb;
cc->class_by_name = e2k_cpu_class_by_name;
cc->disas_set_info = cpu_e2k_disas_set_info;
cc->tcg_initialize = e2k_tcg_initialize;
cc->tlb_fill = e2k_cpu_tlb_fill;
cc->gdb_arch_name = e2k_cpu_gdb_arch_name;
cc->gdb_read_register = e2k_cpu_gdb_read_register;
cc->gdb_write_register = e2k_cpu_gdb_write_register;
cc->gdb_num_core_regs = 574;
}
static const TypeInfo e2k_cpu_type_info = {
.name = TYPE_E2K_CPU,
.parent = TYPE_CPU,
.instance_size = sizeof(E2KCPU),
.instance_init = e2k_cpu_initfn,
.abstract = true,
.class_size = sizeof(E2KCPUClass),
.class_init = e2k_cpu_class_init,
};
static void e2k_cpu_cpudef_class_init(ObjectClass *oc, void *data)
{
E2KCPUClass *ecc = E2K_CPU_CLASS(oc);
ecc->cpu_def = data;
}
static void e2k_register_cpudef_type(const struct e2k_def_t *def)
{
char *typename = e2k_cpu_type_name(def->name);
TypeInfo ti = {
.name = typename,
.parent = TYPE_E2K_CPU,
.class_init = e2k_cpu_cpudef_class_init,
.class_data = (void *)def,
};
type_register(&ti);
g_free(typename);
}
static void e2k_cpu_register_types(void)
{
int i;
type_register_static(&e2k_cpu_type_info);
for (i = 0; i < ARRAY_SIZE(e2k_defs); i++) {
e2k_register_cpudef_type(&e2k_defs[i]);
}
}
type_init(e2k_cpu_register_types)
void e2k_cpu_list(void)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(e2k_defs); i++) {
qemu_printf("%6s (%-30s) ISA version: v%d\n",
e2k_defs[i].name,
e2k_defs[i].canonical_name,
e2k_defs[i].isa_version
);
}
}

777
target/e2k/cpu.h Normal file
View File

@ -0,0 +1,777 @@
#ifndef E2K_CPU_H
#define E2K_CPU_H
#include "qemu/bswap.h"
#include "cpu-qom.h"
#include "exec/cpu-defs.h"
#include "fpu/softfloat.h"
void e2k_tcg_initialize(void);
#define GEN_MASK(start, len) (((1UL << (len)) - 1) << (start))
#define GET_BIT(v, index) (((v) >> (index)) & 1)
#define GET_FIELD(v, s, l) (((v) >> (s)) & GEN_MASK(0, l))
#define SET_FIELD(v, f, s, l) \
( \
((v) & ~GEN_MASK((s), (l))) | \
((((typeof((v))) (f)) << (s)) & GEN_MASK((s), (l))) \
)
#define MMU_USER_IDX 1
#define CPU_RESOLVING_TYPE TYPE_E2K_CPU
#define E2K_TAG_SIZE 2 /* 2-bit tag for 32-bit value */
#define E2K_REG_LEN sizeof(uint64_t)
#define E2K_REG_SIZE (E2K_REG_LEN * 8)
#define E2K_REG_TAGS_SIZE (E2K_TAG_SIZE * 2) /* two tags for 32-bit halves */
#define E2K_WR_COUNT 64 /* %rN [0, 64) */
#define E2K_BR_COUNT 128 /* %b[N] [0, 128) */
#define E2K_NR_COUNT (E2K_WR_COUNT + E2K_BR_COUNT)
#define E2K_GR_COUNT 32 /* %gN [0, 32) */
#define E2K_BGR_COUNT 8 /* %gN [24, 32) */
#define E2K_REG_COUNT (E2K_NR_COUNT + E2K_GR_COUNT)
#define E2K_PR_COUNT 32 /* %predN [0, 32) */
typedef enum {
E2K_TAG_NUMBER32 = 0,
E2K_TAG_NUMBER64 = 0,
E2K_TAG_NON_NUMBER32 = 1,
E2K_TAG_NON_NUMBER64 = 5,
} E2kRegisterTag;
#define CTPR_BASE_OFF 0
#define CTPR_BASE_END 47
#define CTPR_BASE_LEN (CTPR_BASE_END - CTPR_BASE_OFF + 1)
#define CTPR_TAG_OFF 54
#define CTPR_TAG_END 56
#define CTPR_TAG_LEN (CTPR_TAG_END - CTPR_TAG_OFF + 1)
#define CTPR_OPC_OFF 57
#define CTPR_OPC_END 58
#define CTPR_OPC_LEN (CTPR_OPC_END - CTPR_OPC_OFF + 1)
#define CTPR_IPD_OFF 59
#define CTPR_IPD_END 60
#define CTPR_IPD_LEN (CTPR_IPD_END - CTPR_IPD_OFF + 1)
typedef enum {
CTPR_TAG_NONE = 0x0,
CTPR_TAG_RETURN = 0x2,
CTPR_TAG_DISP = 0x3,
CTPR_TAG_SDISP = 0x5,
} CtprTag;
typedef enum {
CTPR_OPC_LDISP = 0x1,
} CtprOpc;
#define WD_BASE_OFF 0
#define WD_BASE_END 10
#define WD_BASE_LEN (WD_BASE_END - WD_BASE_OFF + 1)
#define WD_SIZE_OFF 16
#define WD_SIZE_END 26
#define WD_SIZE_LEN (WD_SIZE_END - WD_SIZE_OFF + 1)
#define WD_PSIZE_OFF 32
#define WD_PSIZE_END 42
#define WD_PSIZE_LEN (WD_PSIZE_END - WD_PSIZE_OFF + 1)
#define WD_FX_OFF 48
#define WD_FX_BIT (1UL << WD_FX_OFF)
#define DESC_HI_IND_OFF 0 /* index for SPILL */
#define DESC_HI_IND_END 31
#define DESC_HI_IND_LEN (DESC_HI_IND_END - DESC_HI_IND_OFF + 1)
#define DESC_HI_SIZE_OFF 32 /* stack size */
#define DESC_HI_SIZE_END 63
#define DESC_HI_SIZE_LEN (DESC_HI_SIZE_END - DESC_HI_SIZE_OFF + 1)
#define DESC_LO_BASE_OFF 0 /* stack address */
#define DESC_LO_BASE_END 47
#define DESC_LO_BASE_LEN (DESC_LO_BASE_END - DESC_LO_BASE_OFF + 1)
#define DESC_LO_READ_OFF 59
#define DESC_LO_READ_BIT (1UL << DESC_LO_READ_OFF)
#define DESC_LO_WRITE_OFF 60
#define DESC_LO_WRITE_BIT (1UL << DESC_LO_WRITE_OFF)
#define PSHTP_IND_OFF 0
#define PSHTP_IND_END 11
#define PSHTP_IND_LEN (PSHTP_IND_END - PSHTP_IND_OFF + 1)
#define PSHTP_FXIND_OFF 16
#define PSHTP_FXIND_END 26
#define PSHTP_FXIND_LEN (PSHTP_FXIND_END - PSHTP_FXIND_OFF + 1)
#define PSHTP_TIND_OFF 32
#define PSHTP_TIND_END 42
#define PSHTP_TIND_LEN (PSHTP_TIND_END - PSHTP_TIND_OFF + 1)
#define PSHTP_FX_OFF 48
#define PSHTP_FX_BIT (1UL << PSHTP_FX_OFF)
#define USD_LO_BASE_OFF 0
#define USD_LO_BASE_END 47
#define USD_LO_BASE_LEN (USD_LO_BASE_END - USD_LO_BASE_OFF + 1)
#define USD_LO_PROTECTED_OFF 58
#define USD_LO_PROTECTED_BIT (1UL << USD_LO_PROTECTED_OFF)
#define USD_LO_READ_OFF 59
#define USD_LO_READ_BIT (1UL << USD_LO_READ_OFF)
#define USD_LO_WRITE_OFF 60
#define USD_LO_WRITE_BIT (1UL << USD_LO_WRITE_OFF)
#define USD_HI_CURPTR_OFF 0
#define USD_HI_CURPTR_END 31
#define USD_HI_CURPTR_LEN (USD_HI_CURPTR_END - USD_HI_CURPTR_OFF + 1)
#define USD_HI_SIZE_OFF 32
#define USD_HI_SIZE_END 63
#define USD_HI_SIZE_LEN (USD_HI_SIZE_END - USD_HI_SIZE_OFF + 1)
#define CR1_HI_BR_OFF 0
#define CR1_HI_BR_END 27
#define CR1_HI_BR_LEN (CR1_HI_BR_END - CR1_HI_BR_OFF + 1)
#define CR1_HI_WDBL_OFF 35
#define CR1_HI_WDBL_BIT (1UL << CR1_HI_WDBL_OFF)
#define CR1_HI_USSZ_OFF 36
#define CR1_HI_USSZ_END 63
#define CR1_HI_USSZ_LEN (CR1_HI_USSZ_END - CR1_HI_USSZ_OFF + 1)
#define CR1_LO_TR_OFF 0
#define CR1_LO_TR_END 14
#define CR1_LO_TR_LEN (CR1_LO_TR_END - CR1_LO_TR_OFF + 1)
#define CR1_LO_EIN_OFF 16
#define CR1_LO_EIN_END 23
#define CR1_LO_EIN_LEN (CR1_LO_EIN_END - CR1_LO_EIN_OFF + 1)
#define CR1_LO_SS_OFF 24
#define CR1_LO_SS_BIT (1UL << CR1_LO_SS_OFF)
#define CR1_LO_WFX_OFF 25
#define CR1_LO_WFX_BIT (1UL << CR1_LO_WFX_OFF)
#define CR1_LO_WPSZ_OFF 26
#define CR1_LO_WPSZ_END 32
#define CR1_LO_WPSZ_LEN (CR1_LO_WPSZ_END - CR1_LO_WPSZ_OFF + 1)
#define CR1_LO_WBS_OFF 33
#define CR1_LO_WBS_END 39
#define CR1_LO_WBS_LEN (CR1_LO_WBS_END - CR1_LO_WBS_OFF + 1)
#define CR1_LO_CUIR_OFF 40
#define CR1_LO_CUIR_END 56
#define CR1_LO_CUIR_LEN (CR1_LO_CUIR_END - CR1_LO_CUIR_OFF + 1)
#define CR1_LO_PSR_OFF 57
#define CR1_LO_PSR_END 63
#define CR1_LO_PSR_LEN (CR1_LO_PSR_END - CR1_LO_PSR_OFF + 1)
#define BR_RBS_OFF 0 /* based regs window offset */
#define BR_RBS_END 5
#define BR_RBS_LEN (BR_RBS_END - BR_RBS_OFF + 1)
#define BR_RSZ_OFF 6 /* based regs window size */
#define BR_RSZ_END 11
#define BR_RSZ_LEN (BR_RSZ_END - BR_RSZ_OFF + 1)
#define BR_RCUR_OFF 12 /* based regs current index */
#define BR_RCUR_END 17
#define BR_RCUR_LEN (BR_RCUR_END - BR_RCUR_OFF + 1)
#define BR_BN_OFF BR_RBS_OFF
#define BR_BN_END BR_RCUR_END
#define BR_BN_LEN (BR_BN_END - BR_BN_OFF + 1)
#define BR_PSZ_OFF 18 /* based pregs window size */
#define BR_PSZ_END 22
#define BR_PSZ_LEN (BR_PSZ_END - BR_PSZ_OFF + 1)
#define BR_PCUR_OFF 23 /* based pregs current index */
#define BR_PCUR_END 27
#define BR_PCUR_LEN (BR_PCUR_END - BR_PCUR_OFF + 1)
#define BR_BP_OFF BR_PSZ_OFF
#define BR_BP_END BR_PCUR_END
#define BR_BP_LEN (BR_BP_END - BR_BP_OFF + 1)
#define LSR_LCNT_OFF 0 /* loop counter */
#define LSR_LCNT_END 31
#define LSR_LCNT_LEN (LSR_LCNT_END - LSR_LCNT_OFF + 1)
#define LSR_ECNT_OFF 32 /* epilogue counter */
#define LSR_ECNT_END 36
#define LSR_ECNT_LEN (LSR_ECNT_END - LSR_ECNT_OFF + 1)
#define LSR_VLC_OFF 37 /* loop count valid bit */
#define LSR_VLC_BIT (1UL << LSR_VLC_OFF)
#define LSR_OVER_OFF 38 /* loop count overflow */
#define LSR_LDMC_OFF 39 /* loads manual control */
#define LSR_LDOVL_OFF 40 /* load overlap */
#define LSR_LDOVL_END 47
#define LSR_LDOVL_SIZE (LSR_LDOVL_END - LSR_LDOVL_OFF + 1)
#define LSR_PCNT_OFF 48 /* prologue counter */
#define LSR_PCNT_END 52
#define LSR_PCNT_LEN (LSR_PCNT_END - LSR_PCNT_OFF + 1)
#define LSR_STRMD_OFF 53 /* store remainder counter */
#define LSR_STRMD_END 59
#define LSR_STRMD_LEN (LSR_STRMD_END - LSR_STRMD_OFF + 1)
#define LSR_SEMC_OFF /* side effects manual control */
#define LSR_ILCR_MASK 0x1f001fffffffffUL
#define UPSR_FE_OFF 0 /* floating point enable */
#define UPSR_FE_BIT 1
#define UPSR_SE_OFF 1 /* supervisor mode enable (only for Intel) */
#define UPSR_SE_BIT (1 << UPSR_SE_OFF)
#define UPSR_AC_OFF 2 /* not-aligned access control */
#define UPSR_AC_BIT (1 << UPSR_AC_OFF)
#define UPSR_DI_OFF 3 /* delayed interrupt (only for Intel) */
#define UPSR_DI_BIT (1 << UPSR_DI_OFF)
#define UPSR_WP_OFF 4 /* write protection (only for Intel) */
#define UPSR_WP_BIT (1 << UPSR_WP_OFF)
#define UPSR_IE_OFF 5 /* interrupt enable */
#define UPSR_IE_BIT (1 << UPSR_IE_OFF)
#define UPSR_A20_OFF 6 /* emulation of 1 Mb memory (only for Intel) */
#define UPSR_A20_BIT (1 << UPSR_A20_OFF)
#define UPSR_NMIE_OFF 7 /* not masked interrupt enable */
#define UPSR_NMIE_BIT (1 << UPSR_NMIE_OFF)
/* next field of register exist only on E3S/ES2/E2S/E8C/E1C+ CPUs */
#define UPSR_FSM_OFF 8 /* floating comparison mode flag */
/* 1 - compatible with x86/x87 */
#define UPSR_FSM_BIT (1 << UPSR_FSM_OFF)
#define UPSR_IMPT_OFF 9 /* ignore Memory Protection Table flag */
#define UPSR_IMPT_BIT (1 << UPSR_IMPT_OFF)
#define UPSR_IUC_OFF 10 /* ignore access right for uncached pages */
#define UPSR_IUC_BIT (1 << UPSR_IUC_OFF)
#define IDR_MDL_OFF 0 /* CPU model number */
#define IDR_MDL_END 7
#define IDR_MDL_LEN (IDR_MDL_END - IDR_MDL_OFF + 1)
#define IDR_REV_OFF 8 /* revision number */
#define IDR_REV_END 11
#define IDR_REV_LEN (IDR_REV_END - IDR_REV_OFF + 1)
#define IDR_WBL_OFF 12 /* write-back length of L2 */
#define IDR_WBL_END 14
#define IDR_WBL_LEN (IDR_WBL_END - IDR_WBL_OFF + 1)
#define IDR_MS_OFF 15 /* model specific info */
#define IDR_MS_END 63
#define IDR_MS_LEN (IDR_MS_END - IDR_MS_OFF + 1)
/* Cache write-back length */
#define IDR_WBL_0 0x0 /* none CPU internal cache */
#define IDR_WBL_32 0x1
#define IDR_WBL_64 0x2
#define IDR_WBL_128 0x3
#define IDR_WBL_256 0x4
#define IDR_WBL_TO_BYTES(wbl) ((wbl) ? (1 << ((wbs) + 4)) : 1)
typedef enum {
E2K_EXCP_SYSCALL = 0x02,
E2K_EXCP_ILLOPC = 0x03,
E2K_EXCP_ILLOPN = 0x04,
E2K_EXCP_MAPERR = 0x05,
} Exception;
struct e2k_def_t {
const char *name;
const char *canonical_name;
const char *gdb_arch;
uint32_t isa_version;
};
typedef struct {
uint32_t base;
uint32_t size;
uint32_t cur;
} E2KBnState;
typedef struct {
uint32_t size;
uint32_t cur;
} E2KBpState;
typedef struct {
union {
struct {
uint64_t tr: 15;
uint64_t unused1: 1;
uint64_t ein: 8;
uint64_t ss: 1;
uint64_t wfx: 1;
uint64_t wpsz: 7;
uint64_t wbs: 7;
uint64_t cuir: 17;
uint64_t psr: 7;
};
struct {
uint64_t unused2: 40;
uint64_t cui: 16;
uint64_t ic: 1;
uint64_t pm: 1;
uint64_t ie: 1;
uint64_t sge: 1;
uint64_t lw: 1;
uint64_t uie: 1;
uint64_t nmie: 1;
uint64_t unmie: 1;
};
uint64_t lo;
};
union {
struct {
uint64_t br: 28;
uint64_t unused3: 7;
uint64_t wdbl: 1;
/* user stack size */
uint64_t ussz: 28;
};
struct {
uint64_t rbs: 6;
uint64_t rsz: 6;
uint64_t rcur: 6;
uint64_t psz: 5;
uint64_t pcur: 5;
uint64_t unused4: 36;
};
uint64_t hi;
};
} E2KCr1State;
typedef struct {
target_ulong base;
target_ulong base_tag;
uint32_t index;
uint32_t size;
bool is_readable;
bool is_writable;
} E2KStackState, E2KPsState, E2KPcsState;
typedef struct {
int16_t index;
uint16_t fx_index;
uint16_t t_index;
bool fx;
} E2KPshtpState;
typedef struct {
int32_t base;
uint32_t size;
uint32_t psize;
bool fx;
} E2KWdState;
typedef enum {
AASR_NULL = 0,
AASR_READY = 1,
AASR_ACTIVE = 3,
AASR_STOPPED = 5,
} E2KAasrState;
typedef union {
struct {
uint32_t unused : 5;
uint32_t stb : 1;
uint32_t iab : 1;
uint32_t lds : 3;
};
uint32_t raw;
} E2KAasr;
typedef enum {
AAD_TAG_UNV = 0,
AAD_TAG_UDT = 1,
AAD_TAG_UET = 2,
AAD_TAG_UAP = 4,
AAD_TAG_USAP = 5,
AAD_TAG_UDS = 6,
} E2KAadTag;
typedef struct {
union {
struct {
uint64_t base : 48; /* 48:0 */
uint64_t unused1 : 6; /* 53:48 */
uint64_t tag : 3; /* 56:54 */
uint64_t mb : 1; /* 57 */
uint64_t ed : 1; /* 58 */
uint64_t rw : 2; /* 60:59 */
uint64_t unused2 : 3; /* 63:60 */
};
uint64_t lo;
};
union {
struct {
uint64_t unused3 : 32;
uint64_t size : 32;
};
uint64_t hi;
};
} E2KAad;
typedef enum {
AALDA_EXC_EIO = 1,
AALDA_EXC_EPM = 2,
AALDA_EXC_EPMSI = 3,
} E2KAaldaExc;
typedef union {
struct {
uint8_t exc: 2;
uint8_t cincr: 1;
uint8_t unused1: 1;
uint8_t root: 1;
uint8_t unused2: 3;
};
uint8_t raw;
} E2KAalda;
/* AAU prefetch instruction */
typedef union {
struct {
union {
struct {
uint32_t abs: 5;
uint32_t asz: 3;
/* version >= 2 || si == 0 */
uint32_t ind: 4;
uint32_t incr: 3;
uint32_t aad: 5;
uint32_t mrng: 5;
uint32_t fmt: 3;
uint32_t dcd: 2;
uint32_t si: 1;
uint32_t ct: 1;
};
struct {
uint32_t unused1: 8;
/* version <= 1 && si == 1 */
uint32_t area: 5;
uint32_t am: 1;
uint32_t be: 1;
uint32_t unused2: 16;
uint32_t dpl: 1;
};
uint32_t lo;
};
union {
uint32_t disp;
uint32_t hi;
};
};
uint64_t raw;
} E2KAauPrefInstr;
typedef struct {
E2KAauPrefInstr pi; /* prefetch instr */
uint32_t cdi; /* current data index */
uint32_t ldi; /* loaded data index */
} E2KAauAreaState;
typedef struct {
E2KAauAreaState area[32];
} E2KAauPrefState;
typedef struct {
E2KAasr sr;
uint32_t fstr;
uint64_t ldm;
uint64_t ldv;
uint32_t stis[16];
uint32_t sti_tags;
uint32_t incrs[8];
uint32_t incr_tags;
uint32_t inds[16];
uint32_t ind_tags;
E2KAad ds[32];
E2KAalda lda[64];
E2KAauPrefState pl, pr;
} E2KAauState;
typedef union {
struct {
uint64_t base: 48; /* 47:0 */
uint64_t unused1: 6; /* 53:48 */
uint64_t tag: 3; /* 56:54 */
uint64_t opc: 2; /* 58:57 */
uint64_t ipd: 2; /* 60:59 */
uint64_t unused2: 3; /* 63:61 */
};
uint64_t raw;
} E2KCtpr;
/* E2K FPU regs are compatible with x87 regs */
#define FPSR_IE (1U << 0) /* invalid operation */
#define FPSR_DE (1U << 1) /* denormalized operand */
#define FPSR_ZE (1U << 2) /* zero divide */
#define FPSR_OE (1U << 3) /* overflow */
#define FPSR_UE (1U << 4) /* underflow */
#define FPSR_PE (1U << 5) /* precision */
typedef union {
struct {
uint32_t ef : 6; /* exception flags */
uint32_t sf : 1; /* stack fault, unused */
uint32_t es : 1; /* error summary status */
uint32_t _c0 : 1; /* condition code 0, unused */
uint32_t c1 : 1; /* condition code 1 */
uint32_t _c2 : 1; /* condition code 2, unused */
uint32_t top: 3; /* stack top, unused */
uint32_t _c3 : 1; /* condition code 3, unused */
uint32_t b : 1; /* fpu busy */
};
uint32_t raw;
} E2KFpsrState;
#define FPCR_EM (FPSR_IE|FPSR_DE|FPSR_ZE|FPSR_OE|FPSR_UE|FPSR_PE)
#define FPCR_PC_SP 0 /* single precision (32 bits) */
#define FPCR_PC_RESERVED 1 /* reserved */
#define FPCR_PC_DP 2 /* double precision (64 bits) */
#define FPCR_PC_XP 3 /* extended precision (80 bits) */
#define FPCR_RC_NEAR 0 /* round to nearest */
#define FPCR_RC_DOWN 1 /* round down */
#define FPCR_RC_UP 2 /* round up */
#define FPCR_RC_CHOP 3 /* round toward zero (truncate) */
typedef union {
struct {
uint32_t em : 6; /* masks flags */
uint32_t _one : 1; /* reserved, always 1 (?) */
uint32_t _zero0 : 1; /* reserved, always 0 */
uint32_t pc : 2; /* precision control */
uint32_t rc : 2; /* rounding control */
uint32_t ic : 1; /* infinity control */
uint32_t _zero1 : 3; /* reserved */
};
uint32_t raw;
} E2KFpcrState;
typedef struct {
union {
uint64_t lo;
struct {
uint64_t base: 48;
uint64_t unused1: 10;
uint64_t protected: 1;
uint64_t read: 1;
uint64_t write: 1;
uint64_t unsued2: 3;
};
};
union {
uint64_t hi;
struct {
uint64_t curptr: 32;
uint64_t size: 32;
};
};
} E2KUserStackDesc;
typedef union {
struct {
uint64_t l1col: 2; /* 1:0 */
uint64_t l1msb: 2; /* 3:2 */
uint64_t word: 9; /* 12:4 */
uint64_t page: 28; /* 40:13 */
uint64_t mask: 8; /* 48:41 */
uint64_t rg: 8; /* 56:49 */
uint64_t quadro: 1; /* 57 */
uint64_t val: 1; /* 58 */
uint64_t unused: 5; /* 63:59 */
};
uint64_t raw;
} E2KDamEntry;
typedef union {
uint32_t u32;
uint64_t u64;
floatx80 f80;
uint8_t u8v[16];
uint16_t u16v[8];
uint32_t u32v[4];
uint64_t u64v[2];
int8_t i8v[16];
int16_t i16v[8];
int32_t i32v[4];
int64_t i64v[2];
} E2KReg;
typedef struct {
/* register file */
uint8_t tags[E2K_REG_COUNT]; /* registers tags */
uint64_t regs[E2K_REG_COUNT]; /* low parts of registers */
uint64_t xregs[E2K_REG_COUNT]; /* high parts of registers */
uint64_t pregs; /* predicate file */
target_ulong ip; /* instruction address */
/* temporaries for FX/SIMD ops */
E2KReg t0, t1, t2, t3;
/* DAM */
E2KDamEntry dam[32];
/* procedure chain info */
uint64_t cr0_lo;
uint64_t cr0_hi;
E2KCr1State cr1;
/* Procedure chain info = cr0_lo, cr0_hi, cr1_lo, cr1_hi */
E2KPcsState pcsp;
uint64_t pcshtp;
/* Procedure stack pointer (for regs) */
E2KPsState psp;
E2KPshtpState pshtp;
E2KWdState wd;
E2KBnState bn;
E2KBpState bp;
uint64_t lsr; /* loop status register */
uint64_t sbr;
E2KUserStackDesc usd;
/* control registers */
E2KCtpr ctprs[3]; // Control Transfer Preparation Register (CTPR)
target_ulong ct_cond;
target_ulong nip; /* next instruction address */
uint64_t upsr;
uint64_t idr;
uint32_t pfpfr; // Packed Floating Point Flag Register (PFPFR)
E2KFpsrState fpsr; // Floating point state register (FPSR)
E2KFpcrState fpcr; // Floating point control register (FPCR)
float_status fp_status;
E2KAauState aau;
int interrupt_index;
/* internal use */
uint32_t is_bp; /* breakpoint flag */
int syscall_wbs; // FIXME: temp for syscall
/* zeroing upper register half for 32-bit instructions */
uint32_t wdbl;
/* Fields up to this point are cleared by a CPU reset */
struct {} end_reset_fields;
uint32_t version;
struct e2k_def_t def;
} CPUE2KState;
/**
* E2KCPU:
* @env: #CPUE2KState
*
* An Elbrus CPU.
*/
struct E2KCPU {
/*< private >*/
CPUState parent_obj;
/*< public >*/
CPUNegativeOffsetState neg;
CPUE2KState env;
};
static inline void cpu_get_tb_cpu_state(CPUE2KState *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *pflags)
{
*pc = env->ip;
*cs_base = 0;
*pflags = MMU_USER_IDX;
}
void e2k_cpu_do_interrupt(CPUState *cs);
void e2k_cpu_list(void);
int e2k_cpu_signal_handler(int host_signum, void *pinfo, void *puc);
int e2k_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n);
int e2k_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n);
void e2k_break_save_state(CPUE2KState *env);
bool e2k_cpu_tlb_fill(CPUState *cpu, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr);
void e2k_update_fp_status(CPUE2KState *env);
#define cpu_signal_handler e2k_cpu_signal_handler
#define cpu_list e2k_cpu_list
#define e2k_wrap_reg_index(i) (E2K_NR_COUNT + i) % E2K_NR_COUNT
static inline uint64_t e2k_state_desc_lo(E2KStackState *desc)
{
uint64_t lo = 0;
lo = deposit64(lo, DESC_LO_BASE_OFF, DESC_LO_BASE_LEN,
(uint64_t) desc->base);
lo = deposit64(lo, DESC_LO_READ_OFF, 1, desc->is_readable);
lo = deposit64(lo, DESC_LO_WRITE_OFF, 1, desc->is_writable);
return lo;
}
static inline uint64_t e2k_state_desc_hi(E2KStackState *env)
{
uint64_t hi = 0;
hi = deposit64(hi, DESC_HI_IND_OFF, DESC_HI_IND_LEN, env->index);
hi = deposit64(hi, DESC_HI_SIZE_OFF, DESC_HI_SIZE_OFF, env->size);
return hi;
}
#define e2k_state_pcsp_lo(env) e2k_state_desc_lo(&(env)->pcsp)
#define e2k_state_pcsp_hi(env) e2k_state_desc_hi(&(env)->pcsp)
#define e2k_state_psp_lo(env) e2k_state_desc_lo(&(env)->psp)
#define e2k_state_psp_hi(env) e2k_state_desc_hi(&(env)->psp)
static inline uint64_t e2k_state_pshtp(CPUE2KState *env)
{
E2KPshtpState *s = &env->pshtp;
uint64_t ret = 0;
ret = deposit64(ret, PSHTP_IND_OFF, PSHTP_IND_LEN, s->index);
ret = deposit64(ret, PSHTP_FXIND_OFF, PSHTP_FXIND_LEN, s->fx_index);
ret = deposit64(ret, PSHTP_TIND_OFF, PSHTP_TIND_LEN, s->t_index);
ret = deposit64(ret, PSHTP_FX_OFF, 1, s->fx);
return ret;
}
static inline uint64_t e2k_state_wd(CPUE2KState *env)
{
E2KWdState *wd = &env->wd;
uint64_t ret = 0;
ret = deposit64(ret, WD_BASE_OFF, WD_BASE_LEN, wd->base * 8);
ret = deposit64(ret, WD_SIZE_OFF, WD_SIZE_LEN, wd->size * 8);
ret = deposit64(ret, WD_PSIZE_OFF, WD_PSIZE_LEN, wd->psize * 8);
ret = deposit64(ret, WD_FX_OFF, 1, wd->fx);
return ret;
}
static inline uint32_t e2k_state_br(CPUE2KState *env)
{
E2KBnState *bn = &env->bn;
E2KBpState *bp = &env->bp;
uint32_t ret = 0;
ret = deposit32(ret, BR_RBS_OFF, BR_RBS_LEN, bn->base / 2);
ret = deposit32(ret, BR_RSZ_OFF, BR_RSZ_LEN, bn->size / 2 - 1);
ret = deposit32(ret, BR_RCUR_OFF, BR_RCUR_LEN, bn->cur / 2);
ret = deposit32(ret, BR_PSZ_OFF, BR_PSZ_LEN, bp->size);
ret = deposit32(ret, BR_PCUR_OFF, BR_PCUR_LEN, bp->cur);
return ret;
}
static inline void e2k_state_br_set(CPUE2KState *env, uint32_t br)
{
E2KBnState *bn = &env->bn;
E2KBpState *bp = &env->bp;
bn->base = extract32(br, BR_RBS_OFF, BR_RBS_LEN) * 2;
bn->size = extract32(br, BR_RSZ_OFF, BR_RSZ_LEN) * 2 + 2;
bn->cur = extract32(br, BR_RCUR_OFF, BR_RCUR_LEN) * 2;
bp->size = extract32(br, BR_PSZ_OFF, BR_PSZ_LEN);
bp->cur = extract32(br, BR_PCUR_OFF, BR_PCUR_LEN);
}
typedef CPUE2KState CPUArchState;
typedef E2KCPU ArchCPU;
#include "exec/cpu-all.h"
#endif

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

@ -0,0 +1,274 @@
/*
* Elbrus 2000 gdb server stub
*
* Copyright (c) 2003-2005 Fabrice Bellard
* Copyright (c) 2013 SUSE LINUX Products GmbH
* Copyright (c) 2020 Alibek Omarov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu/timer.h"
#include "cpu.h"
#include "exec/gdbstub.h"
/* TODO: reverse engineer e2k-linux-gdb register ids */
int e2k_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
E2KCPU *cpu = E2K_CPU(cs);
// CPUClass *cc = CPU_GET_CLASS(cs);
CPUE2KState *env = &cpu->env;
switch (n) {
case 0: return gdb_get_reg64(mem_buf, 0); // unk
case 1: return gdb_get_reg64(mem_buf, 0); // b0
case 2: return gdb_get_reg64(mem_buf, 0); // b1
default: break;
}
if (3 <= n && n < 35) {
return gdb_get_reg64(mem_buf, env->regs[E2K_NR_COUNT + n - 3]);
}
switch (n) {
case 35: return gdb_get_reg64(mem_buf, 0); // psr
case 36: return gdb_get_reg64(mem_buf, env->upsr); // upsr
case 37: return gdb_get_reg64(mem_buf, 0); // oscud_lo
case 38: return gdb_get_reg64(mem_buf, 0); // oscud_hi
case 39: return gdb_get_reg64(mem_buf, 0); // osgd_lo
case 40: return gdb_get_reg64(mem_buf, 0); // osgd_hi
case 41: return gdb_get_reg64(mem_buf, 0); // osem
case 42: return gdb_get_reg64(mem_buf, 0); // osr0
case 43: return gdb_get_reg64(mem_buf, 0); // pfpfr
case 44: return gdb_get_reg64(mem_buf, 0); // fpcr
case 45: return gdb_get_reg64(mem_buf, 0); // fpsr
case 46: return gdb_get_reg64(mem_buf, 0); // usbr
case 47: return gdb_get_reg64(mem_buf, env->usd.lo); // usd_lo
case 48: return gdb_get_reg64(mem_buf, env->usd.hi); // usd_hi
case 49: return gdb_get_reg64(mem_buf, e2k_state_psp_lo(env)); // psp_lo
case 50: return gdb_get_reg64(mem_buf, e2k_state_psp_hi(env)); // psp_hi
case 51: return gdb_get_reg64(mem_buf, e2k_state_pshtp(env)); // pshtp
case 52: return gdb_get_reg64(mem_buf, env->pregs); // pregs
case 53: return gdb_get_reg64(mem_buf, env->ip); // ip
case 54: return gdb_get_reg64(mem_buf, env->cr1.lo); // cr1_lo
case 55: return gdb_get_reg64(mem_buf, env->cr1.hi); // cr1_hi
case 56: return gdb_get_reg64(mem_buf, 0); // cwd
case 57: return gdb_get_reg64(mem_buf, e2k_state_pcsp_lo(env)); // pcsp_lo
case 58: return gdb_get_reg64(mem_buf, e2k_state_pcsp_hi(env)); // pcsp_hi
case 59: return gdb_get_reg64(mem_buf, env->pcshtp); // pcshtp
case 60: return gdb_get_reg64(mem_buf, 0); // cud_lo
case 61: return gdb_get_reg64(mem_buf, 0); // cud_hi
case 62: return gdb_get_reg64(mem_buf, 0); // gd_lo
case 63: return gdb_get_reg64(mem_buf, 0); // gd_hi
case 64: return gdb_get_reg64(mem_buf, 0); // cs_lo
case 65: return gdb_get_reg64(mem_buf, 0); // cs_hi
case 66: return gdb_get_reg64(mem_buf, 0); // ds_lo
case 67: return gdb_get_reg64(mem_buf, 0); // ds_hi
case 68: return gdb_get_reg64(mem_buf, 0); // es_lo
case 69: return gdb_get_reg64(mem_buf, 0); // es_hi
case 70: return gdb_get_reg64(mem_buf, 0); // fs_lo
case 71: return gdb_get_reg64(mem_buf, 0); // fs_hi
case 72: return gdb_get_reg64(mem_buf, 0); // gs_lo
case 73: return gdb_get_reg64(mem_buf, 0); // gs_hi
case 74: return gdb_get_reg64(mem_buf, 0); // ss_lo
case 75: return gdb_get_reg64(mem_buf, 0); // ss_hi
default:
break;
}
if (76 <= n && n < 140) {
int idx = (n - 76) >> 1;
if (n & 1) {
return gdb_get_reg64(mem_buf, env->aau.ds[idx].hi); // addN_hi
} else {
return gdb_get_reg64(mem_buf, env->aau.ds[idx].lo); // addN_lo
}
}
if (140 <= n && n < 156) {
return gdb_get_reg64(mem_buf, env->aau.inds[n - 140]); // aaindN
}
if (156 <= n && n < 164) {
return gdb_get_reg64(mem_buf, env->aau.incrs[n - 156]); // aaincrN
}
if (164 <= n && n < 196) {
return gdb_get_reg64(mem_buf, env->aau.pl.area[n - 164].ldi); // aaldiN
}
if (196 <= n && n < 228) {
return gdb_get_reg64(mem_buf, env->aau.pr.area[n - 196].ldi); // aaldiN
}
if (n == 228) {
return gdb_get_reg64(mem_buf, env->aau.ldv); // aaldv
}
if (229 <= n && n < 293) {
return gdb_get_reg64(mem_buf, env->aau.lda[n - 229].raw); // aaldaN
}
switch (n) {
case 293: return gdb_get_reg64(mem_buf, env->aau.ldm); // aaldm
case 294: return gdb_get_reg64(mem_buf, env->aau.sr.raw); // aasr
case 295: return gdb_get_reg64(mem_buf, env->aau.fstr); // aafstr
default:
break;
}
if (296 <= n && n < 312) {
return gdb_get_reg64(mem_buf, env->aau.stis[n - 296]); // aastiN
}
switch (n) {
case 312: return gdb_get_reg64(mem_buf, cpu_get_host_ticks()); // clkr
case 313: return gdb_get_reg64(mem_buf, 0); // dibcr
case 314: return gdb_get_reg64(mem_buf, 0); // ddbcr
default:
break;
}
if (315 <= n && n < 319) {
return gdb_get_reg64(mem_buf, 0); // dibarN
}
if (319 <= n && n < 323) {
return gdb_get_reg64(mem_buf, 0); // ddbarN
}
switch (n) {
case 323: return gdb_get_reg64(mem_buf, 0); // dimcr
case 324: return gdb_get_reg64(mem_buf, 0); // ddmcr
case 325: return gdb_get_reg64(mem_buf, 0); // dimar0
case 326: return gdb_get_reg64(mem_buf, 0); // dimar1
case 327: return gdb_get_reg64(mem_buf, 0); // ddmar0
case 328: return gdb_get_reg64(mem_buf, 0); // ddmar1
case 329: return gdb_get_reg64(mem_buf, 0); // dibsr
case 330: return gdb_get_reg64(mem_buf, 0); // ddbsr
case 331: return gdb_get_reg64(mem_buf, 0); // dtcr
case 332: return gdb_get_reg64(mem_buf, 0); // dtarf
case 333: return gdb_get_reg64(mem_buf, 0); // dtart
case 334: return gdb_get_reg64(mem_buf, e2k_state_wd(env)); // wd
case 335: return gdb_get_reg64(mem_buf, 0); // unk
case 336: return gdb_get_reg64(mem_buf, 0); // bgr
case 337: return gdb_get_reg64(mem_buf, 0); // unk
case 338: return gdb_get_reg64(mem_buf, 0); // nip
case 339: return gdb_get_reg64(mem_buf, env->ctprs[0].raw); // ctpr1
case 340: return gdb_get_reg64(mem_buf, env->ctprs[1].raw); // ctpr2
case 341: return gdb_get_reg64(mem_buf, env->ctprs[2].raw); // ctpr3
case 342: return gdb_get_reg64(mem_buf, 0); // eir
case 343: return gdb_get_reg64(mem_buf, 0); // tr
case 344: return gdb_get_reg64(mem_buf, 0); // cutd
case 345: return gdb_get_reg64(mem_buf, 0); // cuir
case 346: return gdb_get_reg64(mem_buf, 0); // tsd
case 347: return gdb_get_reg64(mem_buf, env->lsr); // lsr
case 348: return gdb_get_reg64(mem_buf, env->lsr & LSR_ILCR_MASK); // ilcr
default:
break;
}
if (349 <= n && n < 356) {
return gdb_get_reg64(mem_buf, 0); // unk
}
if (356 <= n && n < 360) {
return gdb_get_reg64(mem_buf, 0); // gN tags (tag len is 1 byte)
}
if (360 <= n && n < 368) {
return gdb_get_reg64(mem_buf, 0); // xgN
}
if (n == 368) {
return gdb_get_reg64(mem_buf, 0); // rpr_hi
}
if (n == 369) {
return gdb_get_reg64(mem_buf, 0); // rpr_lo
}
if (370 <= n && n < 389) {
return gdb_get_reg64(mem_buf, 0); // tir_N_lo
}
if (389 <= n && n < 408) {
return gdb_get_reg64(mem_buf, 0); // tir_N_hi
}
if (408 <= n && n < 418) {
return gdb_get_reg64(mem_buf, 0); // trap_cell_addr_N
}
if (418 <= n && n < 428) {
return gdb_get_reg64(mem_buf, 0); // trap_cell_val_N
}
if (n == 428) {
return gdb_get_reg64(mem_buf, 0); // trap_cell_tag_N [0, 7)
}
if (n == 429) {
return gdb_get_reg64(mem_buf, 0); // trap_cell_tag_N [8, 9)
}
if (430 <= n && n < 440) {
return gdb_get_reg64(mem_buf, 0); // trap_cell_info_N
}
if (440 <= n && n < 472) {
return gdb_get_reg64(mem_buf, env->dam[n - 440].raw); // dam_N
}
if (472 <= n && n < 504) {
return gdb_get_reg64(mem_buf, 0); // sbbp_N
}
if (504 <= n && n < 552) {
return gdb_get_reg64(mem_buf, 0); // mlt_N (3 regs)
}
if (n == 552) {
return gdb_get_reg64(mem_buf, env->pcsp.base); // pcsp_base
}
if (n == 553) {
return gdb_get_reg64(mem_buf, env->psp.base); // psp_base
}
if (554 <= n && n < 573) {
return gdb_get_reg64(mem_buf, 0); // unk
}
if (n == 573) {
return gdb_get_reg32(mem_buf, 0); // unk
}
fprintf(stderr, "%s: unknown register %d\n", __FUNCTION__, n);
return 0;
}
int e2k_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
// E2KCPU *cpu = E2K_CPU(cs);
// CPUClass *cc = CPU_GET_CLASS(cs);
// CPUE2KState *env = &cpu->env;
fprintf(stderr, "%s: unknown register %d\n", __FUNCTION__, n);
// TODO: e2k_cpu_gdb_write_register
return 0;
}

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

@ -0,0 +1,304 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "translate.h"
#define PS_FORCE_FX true
static inline void reset_ctprs(CPUE2KState *env)
{
unsigned int i;
for (i = 0; i < 3; i++) {
env->ctprs[i].tag = CTPR_TAG_NONE;
}
}
static inline void stack_push(CPUE2KState *env, E2KStackState *s, uint64_t value)
{
if ((s->index + 8) > s->size) {
helper_raise_exception(env, E2K_EXCP_MAPERR);
return;
}
cpu_stq_le_data_ra(env, s->base + s->index, value, GETPC());
s->index += 8;
}
static inline uint64_t stack_pop(CPUE2KState *env, E2KStackState *s)
{
if (s->index < 8) {
helper_raise_exception(env, E2K_EXCP_MAPERR);
return 0;
}
s->index -= 8;
return cpu_ldq_le_data(env, s->base + s->index);
}
#define pcs_push(env, value) stack_push(env, &env->pcsp, (value))
#define pcs_pop(env) stack_pop(env, &env->pcsp)
static inline void ps_push(CPUE2KState *env, uint64_t value, uint8_t tag)
{
cpu_stb_data(env, env->psp.base_tag + env->psp.index / 8, tag);
stack_push(env, &env->psp, value);
}
static inline uint64_t ps_pop(CPUE2KState *env, uint8_t *ret_tag)
{
uint64_t ret = stack_pop(env, &env->psp);
if (ret_tag != NULL) {
*ret_tag = cpu_ldub_data(env, env->psp.base_tag + env->psp.index / 8);
}
return ret;
}
static void proc_chain_save(CPUE2KState *env, int wbs)
{
pcs_push(env, env->cr0_lo);
pcs_push(env, env->cr0_hi);
pcs_push(env, env->cr1.lo);
pcs_push(env, env->cr1.hi);
env->pshtp.index += wbs * 2;
env->cr0_lo = env->pregs;
env->cr0_hi = env->ip;
env->cr1.wbs = wbs;
env->cr1.wpsz = env->wd.psize / 2;
env->cr1.wfx = env->wd.fx;
env->cr1.br = e2k_state_br(env);
env->cr1.ussz = env->usd.size >> 4;
env->wd.fx = true;
env->wd.base = e2k_wrap_reg_index(env->wd.base + wbs * 2);
env->wd.size -= wbs * 2;
env->wd.psize = env->wd.size;
}
static inline void proc_chain_restore(CPUE2KState *env)
{
int wbs;
env->pregs = env->cr0_lo;
env->ip = env->cr0_hi;
wbs = env->cr1.wbs;
e2k_state_br_set(env, env->cr1.br);
env->wd.size = env->wd.psize + wbs * 2;
env->wd.psize = env->cr1.wpsz * 2;
env->wd.base = e2k_wrap_reg_index(env->wd.base - wbs * 2);
env->wd.fx = env->cr1.wfx;
env->wdbl = env->cr1.wdbl;
env->usd.size = env->cr1.ussz << 4;
env->usd.base = env->sbr - env->usd.size;
env->pshtp.index -= wbs * 2;
env->cr1.hi = pcs_pop(env);
env->cr1.lo = pcs_pop(env);
env->cr0_hi = pcs_pop(env);
env->cr0_lo = pcs_pop(env);
}
static inline void ps_spill(CPUE2KState *env, bool force, bool force_fx)
{
while (E2K_NR_COUNT < env->pshtp.index + env->wd.size ||
(force && env->wd.size + env->pshtp.index))
{
int i = e2k_wrap_reg_index(env->wd.base - env->pshtp.index);
ps_push(env, env->regs[i], env->tags[i]);
ps_push(env, env->regs[i + 1], env->tags[i + 1]);
// TODO: push fx
if (force_fx) {
ps_push(env, env->xregs[i], 0);
ps_push(env, env->xregs[i + 1], 0);
}
env->regs[i] = 0;
env->tags[i] = E2K_TAG_NON_NUMBER64;
env->regs[i + 1] = 0;
env->tags[i + 1] = E2K_TAG_NON_NUMBER64;
env->pshtp.index -= 2;
}
}
static inline void ps_fill(CPUE2KState *env, bool force_fx)
{
while(env->pshtp.index < 0) {
env->pshtp.index += 2;
int i = e2k_wrap_reg_index(env->wd.base - env->pshtp.index);
if (force_fx) {
env->xregs[i + 1] = ps_pop(env, NULL);
env->xregs[i] = ps_pop(env, NULL);
}
env->regs[i + 1] = ps_pop(env, &env->tags[i + 1]);
env->regs[i] = ps_pop(env, &env->tags[i]);
}
}
static inline void do_call(CPUE2KState *env, int wbs, target_ulong pc_next)
{
env->ip = pc_next;
proc_chain_save(env, wbs);
reset_ctprs(env);
}
void helper_setwd(CPUE2KState *env, uint32_t lts)
{
int old_size = env->wd.size, size = extract32(lts, 5, 7) * 2;
if (size < env->wd.psize) {
helper_raise_exception(env, E2K_EXCP_ILLOPN);
return;
}
env->wd.size = size;
env->wd.fx = extract32(lts, 4, 1) == 0;
if (env->version >= 3) {
bool dbl = extract32(lts, 3, 1);
env->cr1.wdbl = dbl;
env->wdbl = dbl;
}
ps_spill(env, false, PS_FORCE_FX);
if (old_size < size) {
unsigned int i, offset = env->wd.base + old_size;
for (i = 0; i < size - old_size; i++) {
int idx = e2k_wrap_reg_index(offset + i);
env->regs[idx] = 0;
env->tags[idx] = E2K_TAG_NON_NUMBER64;
}
}
}
uint64_t helper_prep_return(CPUE2KState *env, int ipd)
{
E2KCtpr ret = { 0 };
if (env->pcsp.index < 32) {
helper_raise_exception(env, E2K_EXCP_MAPERR);
return 0;
}
ret.base = env->cr0_hi;
ret.tag = CTPR_TAG_RETURN;
ret.ipd = ipd;
return ret.raw;
}
void helper_return(CPUE2KState *env)
{
proc_chain_restore(env);
ps_fill(env, PS_FORCE_FX);
reset_ctprs(env);
}
static inline void do_syscall(CPUE2KState *env, int call_wbs,
target_ulong pc_next)
{
CPUState *cs = env_cpu(env);
env->ip = pc_next;
env->syscall_wbs = call_wbs;
reset_ctprs(env);
cs->exception_index = E2K_EXCP_SYSCALL;
cpu_loop_exit(cs);
}
void helper_call(CPUE2KState *env, uint64_t ctpr_raw, int call_wbs,
target_ulong pc_next)
{
E2KCtpr ctpr = { .raw = ctpr_raw };
switch (ctpr.tag) {
case CTPR_TAG_DISP:
do_call(env, call_wbs, pc_next);
env->ip = ctpr.base;
break;
case CTPR_TAG_SDISP:
do_syscall(env, call_wbs, pc_next);
break;
default:
abort();
break;
}
}
void helper_raise_exception(CPUE2KState *env, int tt)
{
CPUState *cs = env_cpu(env);
cs->exception_index = tt;
proc_chain_save(env, env->wd.size / 2);
ps_spill(env, true, true);
cpu_loop_exit(cs);
}
void HELPER(raise_exception_no_spill)(CPUE2KState *env, int tt)
{
CPUState *cs = env_cpu(env);
cs->exception_index = tt;
cpu_loop_exit(cs);
}
void e2k_break_save_state(CPUE2KState *env)
{
env->is_bp = true;
proc_chain_save(env, env->wd.size / 2);
ps_spill(env, true, true);
}
void helper_break_restore_state(CPUE2KState *env)
{
env->is_bp = false;
proc_chain_restore(env);
ps_fill(env, true);
}
bool e2k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr)
{
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
proc_chain_save(env, env->wd.size / 2);
ps_spill(env, true, true);
cs->exception_index = E2K_EXCP_MAPERR;
cpu_loop_exit_restore(cs, retaddr);
}
void helper_debug(CPUE2KState *env)
{
CPUState *cs = env_cpu(env);
e2k_break_save_state(env);
cs->exception_index = EXCP_DEBUG;
cpu_loop_exit(cs);
}
void helper_debug_i32(uint32_t x)
{
qemu_log_mask(LOG_UNIMP, "log %#x\n", x);
}
void helper_debug_i64(uint64_t x)
{
qemu_log_mask(LOG_UNIMP, "log %#lx\n", x);
}
void helper_debug_ptr(void *x)
{
qemu_log_mask(LOG_UNIMP, "log %p\n", x);
}

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

@ -0,0 +1,87 @@
#define dh_alias_Reg ptr
#define dh_alias_f80 ptr
#define dh_ctype_Reg E2KReg *
#define dh_ctype_f80 floatx80 *
#define dh_is_signed_Reg dh_is_signed_ptr
#define dh_is_signed_f80 dh_is_signed_ptr
DEF_HELPER_2(raise_exception, noreturn, env, int)
DEF_HELPER_2(raise_exception_no_spill, noreturn, env, int)
DEF_HELPER_1(debug, void, env)
DEF_HELPER_2(prep_return, i64, env, int)
DEF_HELPER_1(return, void, env)
DEF_HELPER_4(call, void, env, i64, int, tl)
DEF_HELPER_2(sxt, i64, i64, i32)
DEF_HELPER_1(debug_i32, void, i32)
DEF_HELPER_1(debug_i64, void, i64)
DEF_HELPER_1(debug_ptr, void, ptr)
DEF_HELPER_2(state_reg_read_i64, i64, env, int)
DEF_HELPER_2(state_reg_read_i32, i32, env, int)
DEF_HELPER_3(state_reg_write_i64, void, env, int, i64)
DEF_HELPER_3(state_reg_write_i32, void, env, int, i32)
DEF_HELPER_2(getsp, i64, env, i32) /* FIXME: return tl? */
DEF_HELPER_1(break_restore_state, void, env)
DEF_HELPER_2(setwd, void, env, i32)
DEF_HELPER_2(probe_read_access, int, env, tl)
DEF_HELPER_2(probe_write_access, int, env, tl)
DEF_HELPER_3(packed_shuffle_i64, i64, i64, i64, i64)
DEF_HELPER_2(pcmpeqb, i64, i64, i64)
DEF_HELPER_2(pminub, i64, i64, i64)
DEF_HELPER_2(pminsh, i64, i64, i64)
DEF_HELPER_2(pmaxub, i64, i64, i64)
DEF_HELPER_2(pmaxsh, i64, i64, i64)
DEF_HELPER_2(pmovmskb, i64, i64, i64)
DEF_HELPER_1(aau_load_program, void, env)
DEF_HELPER_3(mova_ptr, tl, env, int, int)
DEF_HELPER_3(aau_am, void, env, int, int)
DEF_HELPER_4(dam_lock_addr, void, env, i64, int, int)
DEF_HELPER_4(dam_unlock_addr, int, env, i64, int, int)
#define DEF_HELPER_3_32_64(name) \
DEF_HELPER_3(name##s, i32, env, i32, i32) \
DEF_HELPER_3(name##d, i64, env, i64, i64)
DEF_HELPER_3_32_64(fadd)
DEF_HELPER_3_32_64(fsub)
DEF_HELPER_3_32_64(fmin)
DEF_HELPER_3_32_64(fmax)
DEF_HELPER_3_32_64(fmul)
DEF_HELPER_3_32_64(fdiv)
DEF_HELPER_3_32_64(fcmpeq)
DEF_HELPER_3_32_64(fcmpneq)
DEF_HELPER_3_32_64(fcmple)
DEF_HELPER_3_32_64(fcmpnle)
DEF_HELPER_3_32_64(fcmplt)
DEF_HELPER_3_32_64(fcmpnlt)
DEF_HELPER_3_32_64(fcmpuod)
DEF_HELPER_3_32_64(fcmpod)
#undef DEF_HELPER_3_32_64
DEF_HELPER_2(fstois, i32, env, i32)
DEF_HELPER_2(istofs, i32, env, i32)
DEF_HELPER_2(fstoistr, i32, env, i32)
DEF_HELPER_3(fstofx, void, f80, env, i32)
DEF_HELPER_2(fdtoid, i64, env, i64)
DEF_HELPER_2(idtofd, i64, env, i64)
DEF_HELPER_2(fdtoidtr, i64, env, i64)
DEF_HELPER_3(fdtofx, void, f80, env, i64)
DEF_HELPER_2(fstofd, i64, env, i32)
DEF_HELPER_2(fstoid, i64, env, i32)
DEF_HELPER_2(istofd, i64, env, i32)
DEF_HELPER_2(fstoidtr, i64, env, i32)
DEF_HELPER_2(fdtofs, i32, env, i64)
DEF_HELPER_2(fdtois, i32, env, i64)
DEF_HELPER_2(idtofs, i32, env, i64)
DEF_HELPER_2(fdtoistr, i32, env, i64)
DEF_HELPER_2(fxtofs, i32, env, f80)
DEF_HELPER_2(fxtofd, i64, env, f80)
DEF_HELPER_3(fxaddxx, void, env, f80, f80)
DEF_HELPER_3(fxsubxx, void, env, f80, f80)
DEF_HELPER_3(fxrsubxx, void, env, f80, f80)
DEF_HELPER_3(fxmulxx, void, env, f80, f80)
DEF_HELPER_3(fxdivxx, void, env, f80, f80)

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

@ -0,0 +1,72 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
static inline void init_prefetch_area(E2KAauAreaState *s, E2KAauPrefInstr pi,
uint32_t *inds)
{
if (pi.fmt != 0) {
s->pi = pi;
s->ldi = 0;
s->cdi = inds[pi.ind] & ~((1 << pi.fmt) - 1);
} else {
s->pi.raw = 0;
s->ldi = 0;
s->cdi = 0;
}
}
void HELPER(aau_load_program)(CPUE2KState *env)
{
unsigned int i;
E2KCtpr ctpr = env->ctprs[1];
if (ctpr.tag != CTPR_TAG_DISP || ctpr.opc != CTPR_OPC_LDISP) {
helper_raise_exception(env, E2K_EXCP_ILLOPC);
return;
}
for (i = 0; i < 32; i++) {
E2KAauPrefInstr l, r;
size_t offset = i * 16;
l.raw = cpu_ldq_le_data(env, ctpr.base + offset);
r.raw = cpu_ldq_le_data(env, ctpr.base + offset + 8);
init_prefetch_area(&env->aau.pl.area[i], l, env->aau.inds);
init_prefetch_area(&env->aau.pr.area[i], r, env->aau.inds);
if (l.ct || r.ct) {
break;
}
}
}
target_ulong HELPER(mova_ptr)(CPUE2KState *env, int chan, int area)
{
E2KAauPrefState *ps = chan < 2 ? &env->aau.pl : &env->aau.pr;
E2KAauAreaState *as = &ps->area[area];
E2KAauPrefInstr instr = as->pi;
E2KAad aad = env->aau.ds[instr.aad];
return aad.base + as->cdi;
}
void HELPER(aau_am)(CPUE2KState *env, int chan, int area)
{
E2KAauPrefState *ps = chan < 2 ? &env->aau.pl : &env->aau.pr;
E2KAauAreaState *as = &ps->area[area];
E2KAauPrefInstr instr = as->pi;
uint32_t incr = env->aau.incrs[instr.incr];
int size;
if (instr.fmt == 0) {
return;
}
size = 1 << (instr.fmt - 1);
as->cdi += size * incr;
}

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

@ -0,0 +1,183 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#define glue3(x, y, z) glue(glue(x, y), z)
#define deref(x) *(x)
static inline void fpu_set_exception(CPUE2KState *env, int mask)
{
env->fpsr.ef |= mask;
if (env->fpsr.ef & (~env->fpcr.em & FPCR_EM)) {
env->fpsr.es = 1;
env->fpsr.b = 1;
}
}
static inline uint8_t save_exception_flags(CPUE2KState *env)
{
uint8_t old_flags = get_float_exception_flags(&env->fp_status);
set_float_exception_flags(0, &env->fp_status);
return old_flags;
}
static inline void merge_exception_flags(CPUE2KState *env, uint8_t old_flags)
{
uint8_t new_flags = get_float_exception_flags(&env->fp_status);
float_raise(old_flags, &env->fp_status);
fpu_set_exception(env,
((new_flags & float_flag_invalid ? FPSR_IE : 0) |
(new_flags & float_flag_divbyzero ? FPSR_ZE : 0) |
(new_flags & float_flag_overflow ? FPSR_OE : 0) |
(new_flags & float_flag_underflow ? FPSR_UE : 0) |
(new_flags & float_flag_inexact ? FPSR_PE : 0) |
(new_flags & float_flag_input_denormal ? FPSR_DE : 0)));
}
void e2k_update_fp_status(CPUE2KState *env)
{
int x;
switch(env->fpcr.rc) {
case FPCR_RC_UP:
x = float_round_up;
break;
case FPCR_RC_DOWN:
x = float_round_down;
break;
case FPCR_RC_CHOP:
x = float_round_to_zero;
break;
case FPCR_RC_NEAR:
x = float_round_nearest_even;
break;
default:
abort();
break;
}
set_float_rounding_mode(x, &env->fp_status);
switch(env->fpcr.pc) {
case FPCR_PC_XP: x = 80; break;
case FPCR_PC_DP: x = 64; break;
case FPCR_PC_SP: x = 32; break;
case FPCR_PC_RESERVED:
default:
abort();
break;
}
set_floatx80_rounding_precision(x, &env->fp_status);
}
#define GENERATE_SIMPLE_FLOAT2_OP(name, function, size) \
uint##size##_t HELPER(name)(CPUE2KState *env, uint##size##_t x, uint##size##_t y) \
{ \
uint8_t old_flags = save_exception_flags(env); \
float##size z = float##size##_##function (make_float##size (x), make_float##size (y), &env->fp_status); \
merge_exception_flags(env, old_flags); \
return float##size##_val(z); \
}
#define GENERATE_CMP_FLOAT2_OP(name, function, expr, size) \
uint##size##_t HELPER(name)(CPUE2KState *env, uint##size##_t x, uint##size##_t y) \
{ \
uint8_t old_flags = save_exception_flags(env); \
uint##size##_t z = expr float##size##_##function (make_float##size (x), make_float##size (y), &env->fp_status); \
merge_exception_flags(env, old_flags); \
return z; \
}
#define no_cvt(x) (x) // when function already returns in correct type
#define GENERATE_CVT_FLOAT1_OP(name, from_t, to_t, size_from, size_to, func_from, func_to) \
size_to HELPER(name)(CPUE2KState *env, size_from x) \
{\
uint8_t old_flags = save_exception_flags(env); \
size_to z = func_to( glue3(from_t, _to_, to_t) (func_from(x), &env->fp_status) );\
merge_exception_flags(env, old_flags); \
return z; \
}
#define GENERATE_SIMPLE_FLOAT2_OPS_32_64(name, function) \
GENERATE_SIMPLE_FLOAT2_OP(glue(name, s), function, 32) \
GENERATE_SIMPLE_FLOAT2_OP(glue(name, d), function, 64)
#define GENERATE_CMP_FLOAT2_OPS_32_64(name, function, expr) \
GENERATE_CMP_FLOAT2_OP(glue(name, s), function, expr, 32) \
GENERATE_CMP_FLOAT2_OP(glue(name, d), function, expr, 64)
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fadd, add)
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fsub, sub)
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fmin, min)
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fmax, max)
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fmul, mul)
GENERATE_SIMPLE_FLOAT2_OPS_32_64(fdiv, div)
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpeq, eq, )
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpneq, eq, !)
GENERATE_CMP_FLOAT2_OPS_32_64(fcmple, le, )
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpnle, le, !)
GENERATE_CMP_FLOAT2_OPS_32_64(fcmplt, lt, )
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpnlt, lt, !)
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpuod, unordered, )
GENERATE_CMP_FLOAT2_OPS_32_64(fcmpod, unordered, !)
GENERATE_CVT_FLOAT1_OP(fstois, float32, int32, uint32_t, uint32_t, make_float32, no_cvt)
GENERATE_CVT_FLOAT1_OP(istofs, int32, float32, uint32_t, uint32_t, no_cvt, float32_val)
GENERATE_CVT_FLOAT1_OP(fstoistr, float32, int32_round_to_zero, uint32_t, uint32_t, make_float32, no_cvt)
GENERATE_CVT_FLOAT1_OP(fdtoid, float64, int64, uint64_t, uint64_t, make_float64, no_cvt)
GENERATE_CVT_FLOAT1_OP(idtofd, int64, float64, uint64_t, uint64_t, no_cvt, float64_val)
GENERATE_CVT_FLOAT1_OP(fdtoidtr, float64, int64_round_to_zero, uint64_t, uint64_t, make_float64, no_cvt)
GENERATE_CVT_FLOAT1_OP(fstofd, float32, float64, uint32_t, uint64_t, make_float32, float64_val)
GENERATE_CVT_FLOAT1_OP(fstoid, float32, int64, uint32_t, uint64_t, make_float32, no_cvt)
GENERATE_CVT_FLOAT1_OP(istofd, int32, float64, uint32_t, uint64_t, no_cvt, float64_val)
GENERATE_CVT_FLOAT1_OP(fstoidtr, float32, int64_round_to_zero, uint32_t, uint64_t, make_float32, no_cvt)
GENERATE_CVT_FLOAT1_OP(fdtofs, float64, float32, uint64_t, uint32_t, make_float64, float32_val)
GENERATE_CVT_FLOAT1_OP(fdtois, float64, int32, uint64_t, uint32_t, make_float64, no_cvt)
GENERATE_CVT_FLOAT1_OP(idtofs, int64, float32, uint64_t, uint32_t, no_cvt, float32_val)
GENERATE_CVT_FLOAT1_OP(fdtoistr, float64, int32_round_to_zero, uint64_t, uint32_t, make_float64, no_cvt)
GENERATE_CVT_FLOAT1_OP(fxtofs, floatx80, float32, floatx80*, uint32_t, deref, float32_val)
GENERATE_CVT_FLOAT1_OP(fxtofd, floatx80, float64, floatx80*, uint64_t, deref, float64_val)
void HELPER(fstofx)(floatx80 *ret, CPUE2KState *env, uint32_t x)
{
uint8_t old_flags = save_exception_flags(env);
*ret = float32_to_floatx80(make_float32(x), &env->fp_status);
merge_exception_flags(env, old_flags);
}
void HELPER(fdtofx)(floatx80 *ret, CPUE2KState *env, uint64_t x)
{
uint8_t old_flags = save_exception_flags(env);
*ret = float64_to_floatx80(make_float64(x), &env->fp_status);
merge_exception_flags(env, old_flags);
}
#define GEN_OP2_XX(name, op) \
void HELPER(name)(CPUE2KState *env, floatx80 *x, floatx80 *y) \
{ \
uint8_t old_flags = save_exception_flags(env); \
*x = glue(floatx80_, op)(*x, *y, &env->fp_status); \
merge_exception_flags(env, old_flags); \
}
GEN_OP2_XX(fxaddxx, add)
GEN_OP2_XX(fxsubxx, sub)
GEN_OP2_XX(fxmulxx, mul)
GEN_OP2_XX(fxdivxx, div)
void HELPER(fxrsubxx)(CPUE2KState *env, floatx80 *x, floatx80 *y)
{
uint8_t old_flags = save_exception_flags(env);
*x = floatx80_sub(*y, *x, &env->fp_status);
merge_exception_flags(env, old_flags);
}

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

@ -0,0 +1,140 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "translate.h"
uint64_t helper_sxt(uint64_t x, uint32_t y)
{
int size;
switch (x & 3) {
case 0:
size = 8;
break;
case 1:
size = 16;
break;
default:
size = 32;
break;
}
if (x & 4) {
return y & GEN_MASK(0, size);
} else {
return (((int64_t) y) << (64 - size) >> (64 - size));
}
}
static uint64_t* state_reg_ptr(CPUE2KState *env, int idx)
{
switch (idx) {
case 0x80: return &env->upsr; /* %upsr */
case 0x83: return &env->lsr; /* %lsr */
default: return NULL;
}
}
uint64_t helper_state_reg_read_i64(CPUE2KState *env, int idx)
{
switch (idx) {
case 0x01: return e2k_state_wd(env); /* %wd */
case 0x0f: return e2k_state_pcsp_lo(env); /* %pcsp.lo */
case 0x0d: return e2k_state_pcsp_hi(env); /* %pcsp.hi */
case 0x13: return env->pcshtp; /* %pcshtp */
case 0x2c: return env->usd.hi; /* %usd.hi */
case 0x2d: return env->usd.lo; /* %usd.lo */
case 0x51: return env->cr0_hi; /* %cr0.hi */
case 0x53: return env->cr0_lo; /* %cr0.lo */
case 0x55: return env->cr1.hi; /* %cr1.hi */
case 0x57: return env->cr1.lo; /* %cr1.lo */
case 0x81: return env->ip; /* %ip */
case 0x85: return env->fpcr.raw; /* %fpcr */
case 0x86: return env->fpsr.raw; /* %fpsr */
case 0x8a: return env->idr; /* %idr */
case 0x90: return cpu_get_host_ticks(); /* %clkr */
default: {
uint64_t *p = state_reg_ptr(env, idx);
if (p != NULL) {
return *p;
} else {
qemu_log_mask(LOG_UNIMP, "read unknown state register 0x%x\n", idx);
return 0;
}
}
}
}
uint32_t helper_state_reg_read_i32(CPUE2KState *env, int idx)
{
return helper_state_reg_read_i64(env, idx);
}
void helper_state_reg_write_i64(CPUE2KState *env, int idx, uint64_t val)
{
switch(idx) {
case 0x85: /* %fpcr */
env->fpcr.raw = val;
e2k_update_fp_status(env);
break;
case 0x86: env->fpsr.raw = val; break; /* %fpsr */
default: {
uint64_t *p = state_reg_ptr(env, idx);
if (p != NULL) {
*p = val;
} else {
qemu_log_mask(LOG_UNIMP, "unknown state register 0x%x\n", idx);
abort();
}
break;
}
}
}
void helper_state_reg_write_i32(CPUE2KState *env, int idx, uint32_t val)
{
switch (idx) {
case 0x85: /* %fpcr */
env->fpcr.raw = val;
e2k_update_fp_status(env);
break;
case 0x86: env->fpsr.raw = val; break; /* %fpsr */
default: {
uint32_t *p = (uint32_t*) state_reg_ptr(env, idx);
if (p != NULL) {
*p = val;
} else {
qemu_log_mask(LOG_UNIMP, "unknown state register 0x%x\n", idx);
abort();
}
break;
}
}
}
uint64_t helper_getsp(CPUE2KState *env, uint32_t src2)
{
int32_t s2 = src2 & ~0xf;
env->usd.base += s2;
env->usd.size -= s2;
return env->usd.base;
}
void HELPER(dam_lock_addr)(CPUE2KState *env, uint64_t addr, int size, int reg)
{
// TODO: helper_dam_lock_addr
}
int HELPER(dam_unlock_addr)(CPUE2KState *env, uint64_t addr, int size, int reg)
{
// TODO: helper_dam_unlock_addr
return 1;
}

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

@ -0,0 +1,27 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "translate.h"
int HELPER(probe_read_access)(CPUE2KState *env, target_ulong addr)
{
int flags;
void *ignore;
flags = probe_access_flags(env, addr, MMU_DATA_LOAD, 0, true, &ignore, 0);
return (flags & TLB_INVALID_MASK) == 0;
}
int HELPER(probe_write_access)(CPUE2KState *env, target_ulong addr)
{
int flags;
void *ignore;
flags = probe_access_flags(env, addr, MMU_DATA_STORE, 0, true, &ignore, 0);
return (flags & TLB_INVALID_MASK) == 0;
}

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

@ -0,0 +1,196 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "cpu.h"
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "translate.h"
static uint8_t reverse_bits(uint8_t b)
{
b = ((b & 0xf0) >> 4) | ((b & 0x0f) << 4);
b = ((b & 0xcc) >> 2) | ((b & 0x33) << 2);
b = ((b & 0xaa) >> 1) | ((b & 0x55) << 1);
return b;
}
typedef union {
uint8_t ub[8];
uint16_t uh[4];
uint32_t uw[2];
uint64_t uq;
int8_t sb[8];
int16_t sh[4];
int32_t sw[2];
int64_t sq;
} vec64;
uint64_t HELPER(packed_shuffle_i64)(uint64_t src1, uint64_t src2, uint64_t src3)
{
vec64 ret, s1, s2, s3;
unsigned int i;
s1.uq = src1;
s2.uq = src2;
s3.uq = src3;
for (i = 0; i < 8; i++) {
uint8_t desc = s3.ub[i];
int index = extract8(desc, 0, 3);
uint8_t byte;
if (desc < 0x80) {
if (desc & 0x08) {
byte = s1.ub[index];
} else {
byte = s2.ub[index];
}
switch(desc >> 5) {
case 0x1:
byte = reverse_bits(byte);
break;
case 0x2:
if ((byte & 0x80) != 0) {
byte = 0xff;
} else {
byte = 0;
}
break;
case 0x3:
if ((byte & 1) != 0) {
byte = 0xff;
} else {
byte = 0;
}
break;
default:
break;
}
if (desc & 0x10) {
byte = ~byte;
}
} else {
switch(desc >> 6) {
case 0xa:
byte = 0x7f;
break;
case 0xc:
byte = 0x80;
break;
case 0xe:
byte = 0xff;
break;
default:
byte = 0;
break;
}
}
ret.ub[i] = byte;
}
return ret.uq;
}
// FIXME: not tested
uint64_t HELPER(pcmpeqb)(uint64_t src1, uint64_t src2)
{
unsigned int i;
vec64 s1, s2, ret;
s1.uq = src1;
s2.uq = src2;
for (i = 0; i < 8; i++) {
if (s1.ub[i] == s2.ub[i]) {
ret.ub[i] = 0xff;
} else {
ret.ub[i] = 0;
}
}
return ret.uq;
}
uint64_t HELPER(pminub)(uint64_t src1, uint64_t src2)
{
unsigned int i;
vec64 s1, s2, ret;
s1.uq = src1;
s2.uq = src2;
for (i = 0; i < 8; i++) {
ret.ub[i] = MIN(s1.ub[i], s2.ub[i]);
}
return ret.uq;
}
uint64_t HELPER(pminsh)(uint64_t src1, uint64_t src2)
{
unsigned int i;
vec64 s1, s2, ret;
s1.uq = src1;
s2.uq = src2;
for (i = 0; i < 4; i++) {
ret.sh[i] = MIN(s1.sh[i], s2.sh[i]);
}
return ret.uq;
}
uint64_t HELPER(pmaxub)(uint64_t src1, uint64_t src2)
{
unsigned int i;
vec64 s1, s2, ret;
s1.uq = src1;
s2.uq = src2;
for (i = 0; i < 8; i++) {
ret.ub[i] = MAX(s1.ub[i], s2.ub[i]);
}
return ret.uq;
}
uint64_t HELPER(pmaxsh)(uint64_t src1, uint64_t src2)
{
unsigned int i;
vec64 s1, s2, ret;
s1.uq = src1;
s2.uq = src2;
for (i = 0; i < 4; i++) {
ret.sh[i] = MAX(s1.sh[i], s2.sh[i]);
}
return ret.uq;
}
uint64_t HELPER(pmovmskb)(uint64_t src1, uint64_t src2)
{
unsigned int i;
vec64 s1, s2;
uint16_t ret = 0;
s1.uq = src1;
s2.uq = src2;
for (i = 0; i < 8; i++) {
if (s1.sb[i] < 0) {
ret |= 1 << (i + 8);
}
if (s2.sb[i] < 0) {
ret |= 1 << i;
}
}
return ret;
}

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

@ -0,0 +1,21 @@
e2k_ss = ss.source_set()
e2k_ss.add(files(
'cpu.c',
'gdbstub.c',
'helper.c',
'helper_aau.c',
'helper_fpu.c',
'helper_int.c',
'helper_sm.c',
'helper_vec.c',
'translate.c',
'translate/alc.c',
'translate/aau.c',
'translate/control.c',
'translate/plu.c',
'translate/state.c',
))
# no softmmu support yet
target_arch += {'e2k': e2k_ss}

562
target/e2k/translate.c Normal file
View File

@ -0,0 +1,562 @@
#include "qemu/osdep.h"
#include "qemu.h"
#include "exec/log.h"
#include "disas/disas.h"
#include "translate.h"
struct CPUE2KStateTCG e2k_cs;
/* returns zero if bundle is invalid */
static size_t unpack_bundle(CPUE2KState *env,
target_ulong pc, UnpackedBundle *bundle)
{
unsigned int gap;
unsigned int pos = 0;
unsigned int mdl;
unsigned int hsyll_cntr = 0;
unsigned int i;
uint32_t hs;
memset(bundle, 0, sizeof(UnpackedBundle));
bundle->hs = hs = translator_ldl(env, pc + pos);
pos += 4;
/* Check for SS. */
if (GET_BIT(hs, 12)) {
bundle->ss_present = true;
bundle->ss = translator_ldl(env, pc + pos);
pos += 4;
}
/* Check for available ALS syllables. */
for (i = 0; i < 6; i++) {
if (GET_BIT(hs, 26 + i)) {
bundle->als_present[i] = true;
bundle->als[i] = translator_ldl(env, pc + pos);
pos += 4;
}
}
/* Check for CS0. */
if (GET_BIT(hs, 14)) {
bundle->cs0_present = true;
bundle->cs0 = translator_ldl(env, pc + pos);
pos += 4;
}
if (GET_BIT(hs, 25)) {
bundle->ales_present[5] = ALES_ALLOCATED;
bundle->ales[5] = 0x01c0;
}
if (GET_BIT(hs, 22)) {
bundle->ales_present[2] = ALES_ALLOCATED;
bundle->ales[2] = 0x01c0;
}
/* Calculate the size of f1 fragment in bytes. For a valid bundle it
should be equal to either of `pos', `pos + 4' or `pos + 8'. What should I
do if it's not? */
/* TODO: exception */
mdl = ((hs & 0xf) + 1) * 4;
/* The following condition means that ALES{2,5} are physically present within
the wide instruction. However, they should be probably taken into account
only if HS.ale{2,5} are set. Should I disassemble them if these bits are
not set but the syllables physically exist? */
if ((GET_BIT(hs, 15) && mdl == pos + 8) ||
(!GET_BIT(hs, 15) && mdl == pos + 4)) {
/* Fill in ALES5 and ALES2 syllables even if none of them is specified in
HS as present. This will let me output this syllable into disassembly
whichever case takes place. */
bundle->ales[5] = translator_lduw(env, pc + pos);
bundle->ales[2] = translator_lduw(env, pc + pos + 2);
/* Adjust `ALES_PRESENT[{5,2}]' as proposed above now that we know that
they are allocated. */
bundle->ales_present[5] |= ALES_PRESENT;
bundle->ales_present[2] |= ALES_PRESENT;
pos += 4;
}
/* Check for CS1. */
if (GET_BIT(hs, 15)) {
bundle->cs1_present = 1;
bundle->cs1 = translator_ldl(env, pc + pos);
pos += 4;
}
/* A primitive control just for a moment. */
if (mdl != pos) {
/* This is either an APB instruction or an invalid one. Let's stupidly
believe that the former takes place and signalize our caller about
that by returning 0. */
return 0;
}
/* Check for ALES{0,1,3,4}. */
for (i = 0; i < 5; i++) {
if (i == 2)
continue;
if (GET_BIT(hs, 20 + i)) {
unsigned int offset = 2 * ((hsyll_cntr & ~0x1) + 1 - (hsyll_cntr & 0x1));
bundle->ales_present[i] = ALES_PRESENT;
/* Recall the idiotic order of half-syllables in the packed wide
instruction. */
bundle->ales[i] = translator_lduw(env, pc + pos + offset);
hsyll_cntr++;
}
}
/* Check for AASj half-syllables. To encode them SS syllable of SF1 type
should be present. */
if (bundle->ss_present && !GET_BIT(bundle->ss, 20)) {
for (i = 0; i < 4; i++) {
if (GET_BIT(bundle->ss, 12 + i)) {
bundle->aas_present[i >> 1] = true;
bundle->aas_present[i + 2] = true;
}
}
for (i = 0; i < 6; i++) {
if (bundle->aas_present[i]) {
unsigned int offset = 2 * ((hsyll_cntr & ~0x1) + 1 - (hsyll_cntr & 0x1));
/* Recall the idiotic order of half-syllables in the packed wide
instruction. Note that the first AAS half-syllable may share a
syllable with the last ALES. */
bundle->aas[i] = translator_lduw(env, pc + pos + offset);
hsyll_cntr++;
}
}
}
/* align half-syllables */
hsyll_cntr += hsyll_cntr & 1;
/* Calculate the next 32-bit syllable's position. It may be the uppermost LTS
syllable. Note that I don't consider the case when LTS syllables reuse the
values encoded in the preceding ones, though according to `iset-v5.single'
this is quite legal. GAS doesn't produce such a code. Hopefully neither LAS
has ever done that . . . */
gap = pos + 2 * hsyll_cntr;
/* Set POS to point to the last syllable in the current wide instruction and
extract CDSj and PLSj syllables if any. */
pos = ((GET_FIELD(hs, 4, 3) + 1) << 3) - 4;
/* Check for CDSj syllables. */
for (i = 0; i < GET_FIELD(hs, 16, 2); i++) {
bundle->cds_present[i] = true;
bundle->cds[i] = translator_ldl(env, pc + pos);
pos -= 4;
}
/* Check for PLSj syllables. */
for (i = 0; i < GET_FIELD(hs, 18, 2); i++) {
bundle->pls_present[i] = true;
bundle->pls[i] = translator_ldl(env, pc + pos);
pos -= 4;
}
/* Now POS should point to the lowermost LTS0 syllable if any. If there are
no LTSj syllables in this instruction, POS should point to the last
syllable consisting of half-syllables.
If neither of these conditions holds true, believe that it's not a valid
synchronous instruction by analogy with the middle point test above.
Engineers are said to customize instructions with references to missing
literal syllables occasionally, but the lack of space for more substantial
syllables should not be allowed for. */
if (pos < gap && pos != gap - 4) {
return 0;
}
/* Extract available LTSj syllables. */
for (i = 0; i < 4 && pos >= gap; i++) {
bundle->lts_present[i] = true;
bundle->lts[i] = translator_ldl(env, pc + pos);
pos -= 4;
}
return 8 + GET_FIELD(hs, 4, 3) * 8;
}
static inline bool use_goto_tb(DisasContext *s, target_ulong pc,
target_ulong npc)
{
if (unlikely(s->base.singlestep_enabled || singlestep)) {
return false;
}
#ifndef CONFIG_USER_ONLY
return (pc & TARGET_PAGE_MASK) == (s->base.tb->pc & TARGET_PAGE_MASK) &&
(npc & TARGET_PAGE_MASK) == (s->base.tb->pc & TARGET_PAGE_MASK);
#else
return true;
#endif
}
static inline void gen_goto_tb(DisasContext *ctx, int tb_num,
target_ulong pc, target_ulong npc)
{
if (use_goto_tb(ctx, pc, npc)) {
/* jump to same page: we can use a direct jump */
tcg_gen_goto_tb(tb_num);
tcg_gen_movi_tl(e2k_cs.pc, npc);
tcg_gen_exit_tb(ctx->base.tb, tb_num);
} else {
/* jump to another page: currently not optimized */
tcg_gen_movi_tl(e2k_cs.pc, npc);
tcg_gen_exit_tb(NULL, 0);
}
}
void e2k_tr_gen_exception(DisasContext *ctx, int which)
{
TCGv_i32 t = tcg_const_i32(which);
e2k_gen_save_cpu_state(ctx);
gen_helper_raise_exception(cpu_env, t);
ctx->base.is_jmp = DISAS_NORETURN;
tcg_temp_free_i32(t);
}
void e2k_tr_gen_exception_no_spill(DisasContext *ctx, int excp)
{
TCGv_i32 t0 = tcg_const_i32(excp);
e2k_gen_save_cpu_state(ctx);
gen_helper_raise_exception_no_spill(cpu_env, t0);
ctx->base.is_jmp = DISAS_NORETURN;
tcg_temp_free_i32(t0);
}
static inline void gen_ctpr_tag(TCGv_i64 ret, TCGv_i64 ctpr)
{
tcg_gen_extract_i64(ret, ctpr, CTPR_TAG_OFF, CTPR_TAG_LEN);
}
static inline void gen_goto_ctpr_disp(TCGv_i64 ctpr)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv t1 = tcg_temp_new();
tcg_gen_extract_i64(t0, ctpr, CTPR_BASE_OFF, CTPR_BASE_LEN);
tcg_gen_trunc_i64_tl(t1, t0);
tcg_gen_mov_tl(e2k_cs.pc, t1);
tcg_gen_lookup_and_goto_ptr();
tcg_temp_free(t1);
tcg_temp_free_i64(t0);
}
static inline void do_reset(DisasContext *ctx)
{
memset(ctx->mas, 0, sizeof(ctx->mas));
ctx->illtag = e2k_get_temp_i32(ctx);
tcg_gen_movi_i32(ctx->illtag, 0);
}
static inline target_ulong do_decode(DisasContext *ctx, CPUState *cs)
{
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
unsigned int len;
ctx->pc = ctx->base.pc_next;
len = unpack_bundle(env, ctx->pc, &ctx->bundle);
if (len == 0) {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
}
return ctx->pc + len;
}
/*
* Executes instructions from a bundle and store the results to
* temporary buffer.
*/
static inline void do_execute(DisasContext *ctx)
{
e2k_control_execute(ctx);
e2k_alc_execute(ctx);
e2k_aau_execute(ctx);
e2k_plu_execute(ctx);
}
/*
* Writes results of instructions from a bundle to the state
*
* Note
* ====
*
* Must not generate any exception.
* */
static inline void do_commit(DisasContext *ctx)
{
e2k_control_window_change(ctx);
e2k_alc_commit(ctx);
e2k_aau_commit(ctx);
e2k_plu_commit(ctx);
e2k_stubs_commit(ctx);
}
static inline void do_branch(DisasContext *ctx, target_ulong pc_next)
{
TCGLabel *l0 = gen_new_label();
tcg_gen_brcondi_i32(TCG_COND_EQ, ctx->illtag, 0, l0);
e2k_gen_exception(E2K_EXCP_ILLOPC);
gen_set_label(l0);
if (ctx->ct.type == CT_NONE) {
e2k_gen_save_pc(ctx->base.pc_next);
return;
}
ctx->base.is_jmp = DISAS_NORETURN;
if (ctx->ct.is_branch) {
TCGLabel *l0 = gen_new_label();
tcg_gen_brcondi_i32(TCG_COND_NE, e2k_cs.ct_cond, 0, l0);
gen_goto_tb(ctx, TB_EXIT_IDX0, ctx->pc, pc_next);
gen_set_label(l0);
}
switch(ctx->ct.type) {
case CT_IBRANCH:
gen_goto_tb(ctx, TB_EXIT_IDX1, ctx->pc, ctx->ct.u.target);
break;
case CT_JUMP: {
TCGLabel *l0 = gen_new_label();
TCGLabel *l1 = gen_new_label();
TCGv_i64 t0 = tcg_temp_local_new_i64();
gen_ctpr_tag(t0, ctx->ct.u.ctpr);
tcg_gen_brcondi_i64(TCG_COND_EQ, t0, CTPR_TAG_DISP, l0);
tcg_gen_brcondi_i64(TCG_COND_EQ, t0, CTPR_TAG_RETURN, l1);
tcg_temp_free_i64(t0);
// TODO: ldisp, sdisp
e2k_gen_exception(0);
gen_set_label(l1);
gen_helper_return(cpu_env);
gen_set_label(l0);
gen_goto_ctpr_disp(ctx->ct.u.ctpr);
break;
}
case CT_CALL: {
TCGv_i32 wbs = tcg_const_i32(ctx->ct.wbs);
TCGv npc = tcg_const_tl(pc_next);
gen_helper_call(cpu_env, ctx->ct.u.ctpr, wbs, npc);
tcg_gen_lookup_and_goto_ptr();
tcg_temp_free(npc);
tcg_temp_free_i32(wbs);
break;
}
default:
break;
}
}
static void e2k_tr_init_disas_context(DisasContextBase *db, CPUState *cs)
{
DisasContext *ctx = container_of(db, DisasContext, base);
E2KCPU *cpu = E2K_CPU(cs);
CPUE2KState *env = &cpu->env;
ctx->version = env->version;
}
static bool e2k_tr_breakpoint_check(DisasContextBase *db, CPUState *cs,
const CPUBreakpoint *bp)
{
DisasContext *ctx = container_of(db, DisasContext, base);
e2k_gen_save_pc(ctx->base.pc_next);
gen_helper_debug(cpu_env);
tcg_gen_exit_tb(NULL, TB_EXIT_IDX0);
ctx->base.is_jmp = DISAS_NORETURN;
/*
* The address covered by the breakpoint must be included in
* [tb->pc, tb->pc + tb->size) in order to for it to be
* properly cleared -- thus we increment the PC here so that
* the logic setting tb->size below does the right thing.
*/
ctx->base.pc_next += 1;
return true;
}
static void e2k_tr_tb_start(DisasContextBase *db, CPUState *cs)
{
// DisasContext *ctx = container_of(db, DisasContext, base);
tcg_gen_movi_i32(e2k_cs.ct_cond, 0);
}
static void e2k_tr_insn_start(DisasContextBase *db, CPUState *cs)
{
DisasContext *ctx = container_of(db, DisasContext, base);
tcg_gen_insn_start(ctx->base.pc_next);
}
static void e2k_tr_translate_insn(DisasContextBase *db, CPUState *cs)
{
DisasContext *ctx = container_of(db, DisasContext, base);
TCGLabel *l0 = gen_new_label();
target_ulong pc_next;
tcg_gen_brcondi_i32(TCG_COND_EQ, e2k_cs.is_bp, 0, l0);
gen_helper_break_restore_state(cpu_env);
gen_set_label(l0);
do_reset(ctx);
pc_next = do_decode(ctx, cs);
do_execute(ctx);
do_commit(ctx);
do_branch(ctx, pc_next);
ctx->base.pc_next = pc_next;
/* Free temporary values */
while(ctx->t32_len) {
tcg_temp_free_i32(ctx->t32[--ctx->t32_len]);
}
while(ctx->t64_len) {
tcg_temp_free_i64(ctx->t64[--ctx->t64_len]);
}
while(ctx->ttl_len) {
tcg_temp_free(ctx->ttl[--ctx->ttl_len]);
}
}
static void e2k_tr_tb_stop(DisasContextBase *db, CPUState *cs)
{
DisasContext *ctx = container_of(db, DisasContext, base);
if (ctx->base.is_jmp == DISAS_TOO_MANY) {
gen_goto_tb(ctx, TB_EXIT_IDX0, ctx->pc, ctx->base.pc_next);
}
}
static void e2k_tr_disas_log(const DisasContextBase *db, CPUState *cpu)
{
DisasContext *dc = container_of(db, DisasContext, base);
qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size);
}
static const TranslatorOps e2k_tr_ops = {
.init_disas_context = e2k_tr_init_disas_context,
.tb_start = e2k_tr_tb_start,
.breakpoint_check = e2k_tr_breakpoint_check,
.insn_start = e2k_tr_insn_start,
.translate_insn = e2k_tr_translate_insn,
.tb_stop = e2k_tr_tb_stop,
.disas_log = e2k_tr_disas_log,
};
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
{
DisasContext dc = { 0 };
translator_loop(&e2k_tr_ops, &dc.base, cs, tb, max_insns);
}
void restore_state_to_opc(CPUE2KState *env, TranslationBlock *tb,
target_ulong *data)
{
env->ip = data[0];
}
void e2k_tcg_initialize(void) {
char buf[16] = { 0 };
static const struct { TCGv_i32 *ptr; int off; const char *name; } r32[] = {
{ &e2k_cs.wd_base, offsetof(CPUE2KState, wd.base), "woff" },
{ &e2k_cs.wd_size, offsetof(CPUE2KState, wd.size), "wsize" },
{ &e2k_cs.boff, offsetof(CPUE2KState, bn.base), "boff" },
{ &e2k_cs.bsize, offsetof(CPUE2KState, bn.size), "bsize" },
{ &e2k_cs.bcur, offsetof(CPUE2KState, bn.cur), "bcur" },
{ &e2k_cs.psize, offsetof(CPUE2KState, bp.size), "psize" },
{ &e2k_cs.pcur, offsetof(CPUE2KState, bp.cur), "pcur" },
{ &e2k_cs.is_bp, offsetof(CPUE2KState, is_bp), "is_bp" },
{ &e2k_cs.wdbl, offsetof(CPUE2KState, wdbl), "wdbl" },
{ &e2k_cs.aasti_tags, offsetof(CPUE2KState, aau.sti_tags), "aasti_tags" },
{ &e2k_cs.aaind_tags, offsetof(CPUE2KState, aau.ind_tags), "aaind_tags" },
{ &e2k_cs.aaincr_tags, offsetof(CPUE2KState, aau.incr_tags), "aaincr_tags" },
{ &e2k_cs.ct_cond, offsetof(CPUE2KState, ct_cond), "cond" },
};
static const struct { TCGv_i64 *ptr; int off; const char *name; } r64[] = {
{ &e2k_cs.pregs, offsetof(CPUE2KState, pregs), "pregs" },
{ &e2k_cs.lsr, offsetof(CPUE2KState, lsr), "lsr" },
};
static const struct { TCGv *ptr; int off; const char *name; } rtl[] = {
{ &e2k_cs.pc, offsetof(CPUE2KState, ip), "pc" },
{ &e2k_cs.npc, offsetof(CPUE2KState, nip), "npc" },
};
unsigned int i;
for (i = 0; i < ARRAY_SIZE(r32); i++) {
*r32[i].ptr = tcg_global_mem_new_i32(cpu_env, r32[i].off, r32[i].name);
}
for (i = 0; i < ARRAY_SIZE(r64); i++) {
*r64[i].ptr = tcg_global_mem_new_i64(cpu_env, r64[i].off, r64[i].name);
}
for (i = 0; i < ARRAY_SIZE(rtl); i++) {
*rtl[i].ptr = tcg_global_mem_new(cpu_env, rtl[i].off, rtl[i].name);
}
for (i = 0; i < 3; i++) {
snprintf(buf, ARRAY_SIZE(buf), "%%ctpr%d", i + 1);
e2k_cs.ctprs[i] = tcg_global_mem_new_i64(cpu_env,
offsetof(CPUE2KState, ctprs[i].raw), buf);
}
for (i = 0; i < 16; i++) {
snprintf(buf, ARRAY_SIZE(buf), "%%aasti%d", i);
e2k_cs.aasti[i] = tcg_global_mem_new_i32(cpu_env,
offsetof(CPUE2KState, aau.stis[i]), buf);
}
for (i = 0; i < 16; i++) {
snprintf(buf, ARRAY_SIZE(buf), "%%aaind%d", i);
e2k_cs.aaind[i] = tcg_global_mem_new_i32(cpu_env,
offsetof(CPUE2KState, aau.inds[i]), buf);
}
for (i = 0; i < 7; i++) {
snprintf(buf, ARRAY_SIZE(buf), "%%aaincr%d", i);
e2k_cs.aaincr[i] = tcg_global_mem_new_i32(cpu_env,
offsetof(CPUE2KState, aau.incrs[i]), buf);
}
for (i = 0; i < 32; i++) {
snprintf(buf, ARRAY_SIZE(buf), "%%aad%d_lo", i);
e2k_cs.aad_lo[i] = tcg_global_mem_new_i64(cpu_env,
offsetof(CPUE2KState, aau.ds[i].lo), buf);
snprintf(buf, ARRAY_SIZE(buf), "%%aad%d_hi", i);
e2k_cs.aad_hi[i] = tcg_global_mem_new_i64(cpu_env,
offsetof(CPUE2KState, aau.ds[i].hi), buf);
}
}

570
target/e2k/translate.h Normal file
View File

@ -0,0 +1,570 @@
#ifndef E2K_TRANSLATE_H
#define E2K_TRANSLATE_H
#include "tcg/tcg-op.h"
#include "exec/translator.h"
#define IS_BASED(i) (((i) & 0x80) == 0)
#define IS_REGULAR(i) (((i) & 0xc0) == 0x80)
#define IS_IMM5(i) (((i) & 0xe0) == 0xc0)
#define IS_IMM4(i) (((i) & 0xf0) == 0xc0)
#define IS_LIT(i) (((i) & 0xf0) == 0xd0)
#define IS_LIT16_LO(i) (((i) & 0x0e) == 0x00)
#define IS_LIT16_HI(i) (((i) & 0x0e) == 0x04)
#define IS_LIT32(i) (((i) & 0x0c) == 0x08)
#define IS_LIT64(i) (((i) & 0x0c) == 0x0c)
#define IS_GLOBAL(i) (((i) & 0xe0) == 0xe0)
#define GET_BASED(i) ((i) & 0x7f)
#define GET_REGULAR(i) ((i) & 0x3f)
#define GET_IMM5(i) ((i) & 0x1f)
#define GET_IMM4(i) ((i) & 0x0f)
#define GET_LIT(i) ((i) & 0x03)
#define GET_GLOBAL(i) ((i) & 0x1f)
typedef enum {
ALES_NONE = 0x00,
ALES_PRESENT = 0x01,
ALES_ALLOCATED = 0x02,
} AlesFlag;
typedef struct {
TCGv_i32 cdi[32];
TCGv_i64 pib[32];
} CPUE2KAauPrefStateTCG;
typedef struct CPUE2KStateTCG {
TCGv pc;
TCGv npc;
TCGv_i64 ctprs[3];
TCGv_i32 ct_cond;
TCGv_i32 is_bp; /* breakpoint flag */
TCGv_i32 wdbl;
TCGv_i64 lsr;
TCGv_i32 wd_base; /* holds wbs * 2 */
TCGv_i32 wd_size; /* holds wsz * 2 */
TCGv_i32 boff; /* holds rbs * 2 */
TCGv_i32 bsize; /* holds rsz * 2 + 2 */
TCGv_i32 bcur; /* holds rcur * 2 */
TCGv_i64 pregs;
TCGv_i32 psize; /* holds psz */
TCGv_i32 pcur; /* holds pcur */
/* AAU */
TCGv_i32 aasti[16];
TCGv_i32 aasti_tags;
TCGv_i32 aaind[16];
TCGv_i32 aaind_tags;
TCGv_i32 aaincr[8];
TCGv_i32 aaincr_tags;
TCGv_i64 aad_lo[32];
TCGv_i64 aad_hi[32];
CPUE2KAauPrefStateTCG aapl, aapr;
} CPUE2KStateTCG;
extern struct CPUE2KStateTCG e2k_cs;
typedef struct UnpackedBundle {
uint32_t hs;
uint32_t ss;
uint32_t als[6];
uint32_t cs0;
uint16_t ales[6];
uint32_t cs1;
uint16_t aas[6];
uint32_t lts[4];
uint32_t pls[3];
uint32_t cds[3];
bool ss_present;
bool als_present[6];
bool cs0_present;
AlesFlag ales_present[6];
bool cs1_present;
bool aas_present[6];
bool lts_present[4];
bool pls_present[3];
bool cds_present[3];
} UnpackedBundle;
typedef enum {
AL_RESULT_NONE = 0,
AL_RESULT_SIZE_MASK = 0x3,
AL_RESULT_32 = 0x00,
AL_RESULT_64 = 0x01,
AL_RESULT_80 = 0x02,
AL_RESULT_128 = 0x03,
AL_RESULT_TYPE_MASK = 0xc,
AL_RESULT_REG = 0x04,
AL_RESULT_PREG = 0x08,
AL_RESULT_CTPR = 0x0c,
AL_RESULT_REG32 = AL_RESULT_REG | AL_RESULT_32,
AL_RESULT_REG64 = AL_RESULT_REG | AL_RESULT_64,
AL_RESULT_REG80 = AL_RESULT_REG | AL_RESULT_80,
AL_RESULT_REG128 = AL_RESULT_REG | AL_RESULT_128,
AL_RESULT_CTPR32 = AL_RESULT_CTPR | AL_RESULT_32,
AL_RESULT_CTPR64 = AL_RESULT_CTPR | AL_RESULT_64,
} AlResultType;
#define e2k_al_result_size(x) ((x) & AL_RESULT_SIZE_MASK)
#define e2k_al_result_type(x) ((x) & AL_RESULT_TYPE_MASK)
typedef struct {
AlResultType type;
/* check tag for 32-bit ops if wdbl is set */
bool check_tag;
/* poison result if tag is not zero */
bool poison;
union {
struct {
uint8_t dst; /* %rN, 1st phase */
TCGv_i32 index;
TCGv_i32 tag;
union {
TCGv_i32 v32;
TCGv_i64 v64;
};
union {
TCGv_i32 x32; /* FX ops */
TCGv_i64 x64; /* SIMD ops v5+ */
};
} reg;
struct {
int index;
union {
TCGv_i32 v32;
TCGv_i64 v64;
};
} preg, ctpr;
};
} AlResult;
typedef enum {
AAU_RESULT_NONE,
AAU_RESULT_REG32,
AAU_RESULT_REG64,
} AauResultType;
typedef struct {
AauResultType type;
uint8_t dst;
TCGv_i32 index;
union {
TCGv_i32 v32;
TCGv_i64 v64;
};
} AauResult;
typedef struct {
int reg; // -1 means do not write
TCGv_i32 value;
} PlResult;
typedef enum {
CT_NONE,
CT_IBRANCH,
CT_JUMP,
CT_CALL,
} ControlTransferType;
typedef struct {
ControlTransferType type;
union {
target_ulong target;
TCGv_i64 ctpr;
} u;
int wbs;
bool is_branch;
} ControlTransfer;
typedef struct DisasContext {
DisasContextBase base;
UnpackedBundle bundle;
target_ulong pc;
int jump_ctpr;
int mmuidx;
uint8_t mas[6];
bool loop_mode;
TCGv_i32 is_prologue;
TCGv_i32 is_epilogue;
/* optional, can be NULL */
TCGv_i32 mlock;
int version;
/* Force ILLOP for bad instruction format for cases where real CPU
do not generate it. */
bool strict;
// Temporary values.
TCGv_i32 t32[64];
TCGv_i64 t64[32];
TCGv ttl[8];
// Allocated temporary values count.
int t32_len;
int t64_len;
int ttl_len;
/* illegal tag for delayed exception */
TCGv_i32 illtag;
TCGv_i64 cond[6];
AlResult al_results[6];
TCGv_i32 al_cond[6];
AauResult aau_results[4];
int aau_am[4];
PlResult pl_results[3];
ControlTransfer ct;
} DisasContext;
/* exception generated in translation time */
void e2k_tr_gen_exception(DisasContext *dc, int which);
void e2k_tr_gen_exception_no_spill(DisasContext *ctx, int excp);
/* exception generated in runtime */
static inline void e2k_gen_exception(int excp)
{
TCGv_i32 t0 = tcg_const_i32(excp);
// TODO: check if need to save state
gen_helper_raise_exception(cpu_env, t0);
tcg_temp_free_i32(t0);
}
#define e2k_todo(ctx, fmt, ...) \
do { \
if (unlikely(qemu_loglevel_mask(LOG_UNIMP))) { \
qemu_log("%#lx: todo: ", ctx->pc); \
qemu_log(fmt, ## __VA_ARGS__); \
qemu_log("\n"); \
} \
} while (0)
#define e2k_todo_illop(ctx, fmt, ...) \
do { \
e2k_todo(ctx, fmt, ## __VA_ARGS__); \
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC); \
} while (0)
static inline void e2k_gen_mask_i64(TCGv_i64 ret, TCGv_i64 len)
{
TCGv_i64 one = tcg_const_i64(1);
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_shl_i64(t0, one, len);
tcg_gen_subi_i64(ret, t0, 1);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(one);
}
static inline void e2k_gen_maski_i64(TCGv_i64 ret, int len)
{
TCGv_i64 t0 = tcg_const_i64(len);
e2k_gen_mask_i64(ret, t0);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg1,
TCGv_i64 offset, TCGv_i64 len)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
tcg_gen_shr_i64(t0, arg1, offset);
e2k_gen_mask_i64(t1, len);
tcg_gen_and_i64(ret, t0, t1);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1,
TCGv_i64 arg2, TCGv_i64 offset, TCGv_i64 len)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
TCGv_i64 t3 = tcg_temp_new_i64();
TCGv_i64 t4 = tcg_temp_new_i64();
TCGv_i64 t5 = tcg_temp_new_i64();
e2k_gen_mask_i64(t0, len);
tcg_gen_shl_i64(t1, t0, offset);
tcg_gen_not_i64(t2, t1);
tcg_gen_and_i64(t3, arg1, t2);
tcg_gen_and_i64(t4, arg2, t0);
tcg_gen_shl_i64(t5, t4, offset);
tcg_gen_or_i64(ret, t3, t5);
tcg_temp_free_i64(t5);
tcg_temp_free_i64(t4);
tcg_temp_free_i64(t3);
tcg_temp_free_i64(t2);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
}
static inline TCGv_i32 e2k_get_temp_i32(DisasContext *dc)
{
assert(dc->t32_len < ARRAY_SIZE(dc->t32));
return dc->t32[dc->t32_len++] = tcg_temp_local_new_i32();
}
static inline TCGv_i32 e2k_get_const_i32(DisasContext *dc, uint32_t value)
{
assert(dc->t32_len < ARRAY_SIZE(dc->t32));
return dc->t32[dc->t32_len++] = tcg_const_local_i32(value);
}
static inline TCGv_i64 e2k_get_temp_i64(DisasContext *dc)
{
assert(dc->t64_len < ARRAY_SIZE(dc->t64));
return dc->t64[dc->t64_len++] = tcg_temp_local_new_i64();
}
static inline TCGv_i64 e2k_get_const_i64(DisasContext *dc, uint64_t value)
{
assert(dc->t64_len < ARRAY_SIZE(dc->t64));
return dc->t64[dc->t64_len++] = tcg_const_local_i64(value);
}
static inline TCGv e2k_get_temp(DisasContext *dc)
{
assert(dc->ttl_len < ARRAY_SIZE(dc->ttl));
return dc->ttl[dc->ttl_len++] = tcg_temp_local_new();
}
static inline void e2k_gen_save_pc(target_ulong pc)
{
tcg_gen_movi_tl(e2k_cs.pc, pc);
}
static inline void e2k_gen_save_cpu_state(DisasContext *ctx)
{
e2k_gen_save_pc(ctx->pc);
}
static inline void e2k_gen_lcnt_i64(TCGv_i64 ret)
{
tcg_gen_andi_i64(ret, e2k_cs.lsr, (1UL << 32) - 1);
}
static inline void e2k_gen_lcnt_i32(TCGv_i32 ret)
{
TCGv_i64 t0 = tcg_temp_new_i64();
e2k_gen_lcnt_i64(t0);
tcg_gen_extrl_i64_i32(ret, t0);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_lcnt_set_i32(TCGv_i32 value)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(t0, value);
tcg_gen_deposit_i64(e2k_cs.lsr, e2k_cs.lsr, t0, LSR_LCNT_OFF, LSR_LCNT_LEN);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_ecnt_i64(TCGv_i64 ret)
{
tcg_gen_extract_i64(ret, e2k_cs.lsr, LSR_ECNT_OFF, LSR_ECNT_LEN);
}
static inline void e2k_gen_ecnt_i32(TCGv_i32 ret)
{
TCGv_i64 t0 = tcg_temp_new_i64();
e2k_gen_ecnt_i64(t0);
tcg_gen_extrl_i64_i32(ret, t0);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_ecnt_set_i32(TCGv_i32 value)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(t0, value);
tcg_gen_deposit_i64(e2k_cs.lsr, e2k_cs.lsr, t0, LSR_ECNT_OFF, LSR_ECNT_LEN);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_pcnt_i32(TCGv_i32 ret)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_extract_i64(t0, e2k_cs.lsr, LSR_PCNT_OFF, LSR_PCNT_LEN);
tcg_gen_extrl_i64_i32(ret, t0);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_pcnt_set_i32(TCGv_i32 value)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(t0, value);
tcg_gen_deposit_i64(e2k_cs.lsr, e2k_cs.lsr, t0, LSR_PCNT_OFF, LSR_PCNT_LEN);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_lsr_strem_i32(TCGv_i32 ret)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_extract_i64(t0, e2k_cs.lsr, LSR_STRMD_OFF, LSR_STRMD_LEN);
tcg_gen_extrl_i64_i32(ret, t0);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_lsr_strem_set_i32(TCGv_i32 value)
{
TCGv_i64 t0 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(t0, value);
tcg_gen_deposit_i64(e2k_cs.lsr, e2k_cs.lsr, t0, LSR_STRMD_OFF,
LSR_STRMD_LEN);
tcg_temp_free_i64(t0);
}
static inline void e2k_gen_lcntex(TCGv_i32 ret)
{
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_extrl_i64_i32(t0, e2k_cs.lsr);
tcg_gen_setcondi_i32(TCG_COND_EQ, ret, t0, 0);
tcg_temp_free_i32(t0);
}
void e2k_gen_store_preg(int idx, TCGv_i64 val);
void e2k_gen_reg_tag_read_i64(TCGv_i32 ret, TCGv_i32 idx);
void e2k_gen_reg_tag_read_i32(TCGv_i32 ret, TCGv_i32 idx);
void e2k_gen_reg_tag_write_i64(TCGv_i32 value, TCGv_i32 idx);
void e2k_gen_reg_tag_write_i32(TCGv_i32 value, TCGv_i32 idx);
static inline void e2k_gen_reg_tag_writei_i64(int value, TCGv_i32 idx)
{
TCGv_i32 t0 = tcg_const_i32(value);
e2k_gen_reg_tag_write_i64(t0, idx);
tcg_temp_free_i32(t0);
}
static inline void e2k_gen_reg_tag_writei_i32(int value, TCGv_i32 idx)
{
TCGv_i32 t0 = tcg_const_i32(value);
e2k_gen_reg_tag_write_i32(t0, idx);
tcg_temp_free_i32(t0);
}
static inline void e2k_gen_reg_tag_extract_lo(TCGv_i32 ret, TCGv_i32 tags)
{
tcg_gen_andi_i32(ret, tags, GEN_MASK(0, E2K_TAG_SIZE));
}
static inline void e2k_gen_reg_tag_extract_hi(TCGv_i32 ret, TCGv_i32 tags)
{
tcg_gen_shri_i32(ret, tags, E2K_TAG_SIZE);
}
void e2k_gen_reg_tag_check_i64(TCGv_i32 ret, TCGv_i32 tag);
void e2k_gen_reg_tag_check_i32(TCGv_i32 ret, TCGv_i32 tag);
void e2k_gen_reg_index_from_wregi(TCGv_i32 ret, int idx);
void e2k_gen_reg_index_from_bregi(TCGv_i32 ret, int idx);
void e2k_gen_reg_index_from_gregi(TCGv_i32 ret, int idx);
static inline void e2k_gen_reg_index(TCGv_i32 ret, uint8_t arg)
{
if (IS_BASED(arg)) {
e2k_gen_reg_index_from_bregi(ret, GET_BASED(arg));
} else if (IS_REGULAR(arg)) {
e2k_gen_reg_index_from_wregi(ret, GET_REGULAR(arg));
} else if (IS_GLOBAL(arg)) {
e2k_gen_reg_index_from_gregi(ret, GET_GLOBAL(arg));
} else {
e2k_gen_exception(E2K_EXCP_ILLOPN);
}
}
void e2k_gen_reg_read_i64(TCGv_i64 ret, TCGv_i32 idx);
void e2k_gen_reg_read_i32(TCGv_i32 ret, TCGv_i32 idx);
void e2k_gen_reg_write_i64(TCGv_i64 value, TCGv_i32 idx);
void e2k_gen_reg_write_i32(TCGv_i32 value, TCGv_i32 idx);
void e2k_gen_xreg_read_i64(TCGv_i64 ret, TCGv_i32 idx);
void e2k_gen_xreg_read_i32(TCGv_i32 ret, TCGv_i32 idx);
void e2k_gen_xreg_read16u_i32(TCGv_i32 ret, TCGv_i32 idx);
void e2k_gen_xreg_write_i64(TCGv_i64 value, TCGv_i32 idx);
void e2k_gen_xreg_write_i32(TCGv_i32 value, TCGv_i32 idx);
void e2k_gen_xreg_write16u_i32(TCGv_i32 value, TCGv_i32 idx);
void e2k_gen_preg_i64(TCGv_i64 ret, int reg);
void e2k_gen_preg_i32(TCGv_i32 ret, int reg);
TCGv_i64 e2k_get_preg(DisasContext *dc, int reg);
void e2k_gen_cond_i32(DisasContext *ctx, TCGv_i32 ret, uint8_t psrc);
static inline void e2k_gen_cond_i64(DisasContext *ctx, TCGv_i64 ret,
uint8_t psrc)
{
TCGv_i32 t0 = tcg_temp_new_i32();
e2k_gen_cond_i32(ctx, t0, psrc);
tcg_gen_extu_i32_i64(ret, t0);
tcg_temp_free_i32(t0);
}
static inline void e2k_gen_is_last_iter(TCGv_i32 ret)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i64 t2 = tcg_temp_new_i64();
TCGv_i32 t3 = tcg_temp_new_i32();
e2k_gen_lcnt_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_LTU, t1, t0, 2);
tcg_gen_andi_i64(t2, e2k_cs.lsr, LSR_VLC_BIT);
tcg_gen_setcondi_i64(TCG_COND_NE, t2, t2, 0);
tcg_gen_extrl_i64_i32(t3, t2);
tcg_gen_and_i32(ret, t1, t3);
tcg_temp_free_i32(t3);
tcg_temp_free_i64(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
static inline void e2k_gen_is_loop_end_i32(TCGv_i32 ret)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
e2k_gen_ecnt_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_EQ, t1, t0, 0);
e2k_gen_is_last_iter(t2);
tcg_gen_and_i32(ret, t1, t2);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
void e2k_control_execute(DisasContext *ctx);
void e2k_control_window_change(DisasContext *ctx);
void e2k_stubs_commit(DisasContext *ctx);
void e2k_alc_execute(DisasContext *ctx);
void e2k_alc_commit(DisasContext *ctx);
void e2k_aau_execute(DisasContext *ctx);
void e2k_aau_commit(DisasContext *ctx);
void e2k_plu_execute(DisasContext *ctx);
void e2k_plu_commit(DisasContext *ctx);
#endif

215
target/e2k/translate/aau.c Normal file
View File

@ -0,0 +1,215 @@
#include "qemu/osdep.h"
#include "qemu.h"
#include "exec/log.h"
#include "translate.h"
typedef struct {
int chan;
union {
struct {
uint16_t am: 1;
uint16_t ind: 5;
uint16_t area: 6;
uint16_t opc: 3;
uint16_t be: 1;
};
uint16_t aas;
};
uint8_t dst;
} Instr;
static void gen_load_prefetch_program(DisasContext *ctx)
{
gen_helper_aau_load_program(cpu_env);
}
static void gen_aau_result_reg64(DisasContext *ctx, Instr *instr, TCGv_i64 dst)
{
AauResult *res = &ctx->aau_results[instr->chan];
res->type = AAU_RESULT_REG64;
res->dst = instr->dst;
res->index = e2k_get_temp_i32(ctx);
res->v64 = dst;
if (IS_REGULAR(instr->dst)) {
res->dst = instr->dst;
} else {
res->dst = 0;
e2k_gen_reg_index(res->index, instr->dst);
}
}
static void gen_aau_result_reg32(DisasContext *ctx, Instr *instr, TCGv_i32 dst)
{
AauResult *res = &ctx->aau_results[instr->chan];
res->type = AAU_RESULT_REG32;
res->dst = instr->dst;
res->index = e2k_get_temp_i32(ctx);
res->v32 = dst;
if (IS_REGULAR(instr->dst)) {
res->dst = instr->dst;
} else {
res->dst = 0;
e2k_gen_reg_index(res->index, instr->dst);
}
}
static void gen_mova_i32(DisasContext *ctx, Instr *instr, TCGv ptr)
{
MemOp memop = instr->be ? MO_BE : MO_LE;
TCGv_i32 dst = e2k_get_temp_i32(ctx);
switch(instr->opc) {
case 1: memop |= MO_8; break; /* movab */
case 2: memop |= MO_16; break; /* movah */
case 3: memop |= MO_32; break; /* movaw */
default:
g_assert_not_reached();
break;
}
tcg_gen_qemu_ld_i32(dst, ptr, 0, memop);
gen_aau_result_reg32(ctx, instr, dst);
}
static void gen_mova_i64(DisasContext *ctx, Instr *instr, TCGv ptr)
{
TCGv_i64 dst = e2k_get_temp_i64(ctx);
tcg_gen_qemu_ld_i64(dst, ptr, 0, instr->be ? MO_BEQ : MO_LEQ);
gen_aau_result_reg64(ctx, instr, dst);
}
static inline void gen_mova_ptr(TCGv ret, Instr *instr)
{
TCGv_i32 t0 = tcg_const_i32(instr->chan);
TCGv_i32 t1 = tcg_const_i32(instr->area);
TCGv t2 = tcg_temp_new();
gen_helper_mova_ptr(t2, cpu_env, t0, t1);
tcg_gen_addi_tl(ret, t2, instr->ind);
tcg_temp_free(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
static void gen_mova(DisasContext *ctx, Instr *instr)
{
TCGv t5 = tcg_temp_new();
ctx->aau_am[instr->chan] = instr->am ? instr->area : -1;
// TODO: check ind has proper alignment
// TODO: check ind is less than mrng
gen_mova_ptr(t5, instr);
switch(instr->opc) {
case 1: /* movab */
case 2: /* movah */
case 3: /* movaw */
gen_mova_i32(ctx, instr, t5);
break;
case 4: /* movad */
gen_mova_i64(ctx, instr, t5);
break;
case 5: /* movaq */
qemu_log_mask(LOG_UNIMP, "0x%lx: movaq is not implemented\n", ctx->pc);
abort();
break;
case 7: /* movaqp */
qemu_log_mask(LOG_UNIMP, "0x%lx: movaqp is not implemented\n", ctx->pc);
abort();
break;
default:
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPC);
break;
}
tcg_temp_free(t5);
}
static inline void gen_aau_am(DisasContext *ctx, int chan, int area)
{
TCGv_i32 t0 = tcg_const_i32(chan);
TCGv_i32 t1 = tcg_const_i32(area);
gen_helper_aau_am(cpu_env, t0, t1);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
void e2k_aau_execute(DisasContext *ctx)
{
const UnpackedBundle *bundle = &ctx->bundle;
unsigned int i;
for (i = 0; i < 4; i++) {
Instr instr = { 0 };
AauResult *res = &ctx->aau_results[i];
instr.chan = i;
instr.aas = bundle->aas[i + 2];
instr.dst = extract16(bundle->aas[i / 2], ((i & 1) ^ 1) * 8, 8);
if (!bundle->aas_present[i + 2] || instr.opc == 0) {
ctx->aau_am[i] = -1;
res->type = AAU_RESULT_NONE;
continue;
}
gen_mova(ctx, &instr);
}
/* bap */
if (ctx->bundle.ss & (1 << 28)) {
gen_load_prefetch_program(ctx);
}
}
void e2k_aau_commit(DisasContext *ctx)
{
unsigned int i;
for (i = 0; i < 4; i++) {
AauResult *res = &ctx->aau_results[i];
if (res->type == AAU_RESULT_REG32 || res->type == AAU_RESULT_REG64) {
if (IS_REGULAR(res->dst)) {
e2k_gen_reg_index_from_wregi(res->index, GET_REGULAR(res->dst));
}
}
}
for (i = 0; i < 4; i++) {
AauResult *res = &ctx->aau_results[i];
TCGv_i32 zero = tcg_const_i32(0);
// TODO: aau.tags
switch(res->type) {
case AAU_RESULT_REG32: {
TCGv_i64 t0 = tcg_temp_new_i64();
/* mova{b,h,w} always write to reg64 */
tcg_gen_extu_i32_i64(t0, res->v32);
e2k_gen_reg_tag_write_i32(zero, res->index);
e2k_gen_reg_write_i64(t0, res->index);
tcg_temp_free_i64(t0);
break;
}
case AAU_RESULT_REG64:
e2k_gen_reg_tag_write_i64(zero, res->index);
e2k_gen_reg_write_i64(res->v64, res->index);
break;
default:
break;
}
tcg_temp_free_i32(zero);
}
for (i = 0; i < 4; i++) {
int area = ctx->aau_am[i];
if (area == -1 || ((i == 1 || i == 3) && ctx->aau_am[i - 1] == area)) {
continue;
}
gen_aau_am(ctx, i, area);
}
}

4129
target/e2k/translate/alc.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,683 @@
#include "qemu/osdep.h"
#include "qemu.h"
#include "exec/log.h"
#include "translate.h"
static inline TCGCond cond_from_advance(int advance)
{
switch (advance) {
case 0x01: return TCG_COND_EQ;
case 0x02: return TCG_COND_NE;
case 0x03: return TCG_COND_ALWAYS;
default: return TCG_COND_NEVER;
}
}
static void gen_movcond_flag_i32(TCGv_i32 ret, int flag, TCGv_i32 cond,
TCGv_i32 v1, TCGv_i32 v2)
{
TCGv_i32 one = tcg_const_i32(1);
TCGCond c = cond_from_advance(flag);
tcg_gen_movcond_i32(c, ret, cond, one, v1, v2);
tcg_temp_free_i32(one);
}
static inline void gen_dec_wrap(TCGv_i32 ret, TCGv_i32 cur, int n,
TCGv_i32 size)
{
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_addi_i32(t0, size, n);
tcg_gen_sub_i32(t0, t0, cur);
tcg_gen_remu_i32(t0, t0, size);
tcg_gen_sub_i32(ret, size, t0);
tcg_temp_free_i32(t0);
}
static inline void gen_cur_dec(DisasContext *ctx, TCGv_i32 ret, int cond,
TCGv_i32 cur, int n, TCGv_i32 size)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_brcondi_i32(TCG_COND_EQ, size, 0, l0);
gen_dec_wrap(t0, cur, n, size);
gen_movcond_flag_i32(ret, cond, e2k_cs.ct_cond, t0, cur);
gen_set_label(l0);
tcg_temp_free_i32(t0);
}
static void gen_advance_pcnt(TCGv_i32 ret)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_local_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
e2k_gen_pcnt_i32(t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0);
tcg_gen_subi_i32(t1, t0, 1);
e2k_gen_pcnt_set_i32(t1);
gen_set_label(l0);
tcg_gen_mov_i32(ret, t0);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
static inline void gen_lcnt_overflow(TCGv_i32 lcnt)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(t0, lcnt);
tcg_gen_setcondi_i64(TCG_COND_EQ, t1, t0, 0);
tcg_gen_shli_i64(t1, t1, LSR_OVER_OFF);
tcg_gen_or_i64(e2k_cs.lsr, e2k_cs.lsr, t1);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
}
static void gen_advance_lcnt(TCGv_i32 ret)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_local_new_i32();
e2k_gen_lcnt_i32(t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0);
tcg_gen_subi_i32(t0, t0, 1);
e2k_gen_lcnt_set_i32(t0);
gen_set_label(l0);
gen_lcnt_overflow(t0);
tcg_gen_mov_i32(ret, t0);
tcg_temp_free_i32(t0);
}
static void gen_advance_ecnt(void)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_local_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
e2k_gen_ecnt_i32(t0);
tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l0);
tcg_gen_subi_i32(t1, t0, 1);
e2k_gen_ecnt_set_i32(t1);
gen_set_label(l0);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
static void gen_advance_loop_counters(void)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_local_new_i32();
TCGv_i32 t1 = tcg_temp_local_new_i32();
gen_advance_pcnt(t0);
gen_advance_lcnt(t1);
tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, l0);
tcg_gen_brcondi_i32(TCG_COND_NE, t1, 0, l0);
gen_advance_ecnt();
gen_set_label(l0);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
void e2k_stubs_commit(DisasContext *ctx)
{
uint32_t ss = ctx->bundle.ss;
int alc = extract32(ss, 16, 2);
int abp = extract32(ss, 18, 2);
int abn = extract32(ss, 21, 2);
int abg = extract32(ss, 23, 2);
int vfdi = extract32(ss, 26, 1);
if (alc) {
TCGLabel *l0 = gen_new_label();
TCGCond cond = cond_from_advance(alc);
tcg_gen_brcondi_i32(tcg_invert_cond(cond), e2k_cs.ct_cond, 1, l0);
gen_advance_loop_counters();
gen_set_label(l0);
}
if (abp) {
TCGv_i32 t0 = tcg_temp_local_new_i32();
tcg_gen_addi_i32(t0, e2k_cs.psize, 1);
gen_cur_dec(ctx, e2k_cs.pcur, abp, e2k_cs.pcur, 1, t0);
tcg_temp_free_i32(t0);
}
if (abn) {
gen_cur_dec(ctx, e2k_cs.bcur, abn, e2k_cs.bcur, 2, e2k_cs.bsize);
}
if (abg != 0) {
// TODO: impl abg
e2k_todo_illop(ctx, "abg");
}
if (vfdi != 0) {
// TODO: impl vfdi
e2k_todo_illop(ctx, "vfdi");
}
}
static void gen_cs0(DisasContext *dc)
{
typedef enum {
NOTHING,
IBRANCH,
PREF,
PUTTSD,
DONE,
HRET,
GLAUNCH,
DISP,
SDISP,
GETTSD,
LDISP,
RETURN
} cs0_type;
static cs0_type cs0_ops[4][4] = {
{IBRANCH, PREF, PUTTSD, DONE},
{DISP, NOTHING, SDISP, GETTSD},
{DISP, LDISP, SDISP, GETTSD},
{DISP, NOTHING, SDISP, RETURN}
};
const UnpackedBundle *bundle = &dc->bundle;
uint32_t cs0 = bundle->cs0;
unsigned int ctpr = (cs0 & 0xc0000000) >> 30;
unsigned int ctp_opc = (cs0 & 0x30000000) >> 28;
unsigned int param_type = (cs0 & 0x00000007);
cs0_type type = cs0_ops[ctpr][ctp_opc];
if (type == RETURN && param_type == 1) {
type = GETTSD;
} else if (type == DONE) {
if (param_type == 3) {
type = HRET;
} else if (param_type == 4) {
type = GLAUNCH;
}
}
if (type == IBRANCH || type == DONE || type == HRET || type == GLAUNCH) {
if (!bundle->ss_present || (bundle->ss & 0x00000c00)) {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
} else if ((bundle->ss & 0x1ff)
&& !(bundle->cs1_present
/* CS1.opc == CALL */
&& (bundle->cs1 & 0xf0000000) >> 28 == 5
/* CS1.param.ctopc == HCALL */
&& (bundle->cs1 & 0x380) >> 7 == 2))
{
if (type == IBRANCH && dc->ct.type == CT_NONE) {
/* C0F2 has `disp' field. In `C0F1' it's called `param'. Is this
the only difference between these two formats? Funnily enough,
DONE is also C0F2 and thus has `disp', though it obviously
makes no sense for it. */
uint32_t disp = (cs0 & 0x0fffffff);
/* Calculate a signed displacement in bytes. */
int32_t sdisp = ((int32_t) (disp << 4)) >> 1;
dc->ct.type = CT_IBRANCH;
dc->ct.u.target = dc->pc + sdisp;
} else {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
}
}
} else {
/* Note that according to Table B.4.1 it's possible to obtain
` gettsd %ctpr{1,2} with an invalid value for CS0.param.type. */
if (type == GETTSD && param_type != 1) {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
}
int ipd = bundle->ss_present ? GET_FIELD(bundle->ss, 30, 2) : 3;
if (type == DISP || type == LDISP) {
unsigned int disp = GET_FIELD(cs0, 0, 28);
/* Calculate a signed displacement in bytes. */
int sdisp = ((int) (disp << 4)) >> 1;
uint64_t reg = (dc->pc + sdisp) |
((uint64_t) CTPR_TAG_DISP << CTPR_TAG_OFF) |
((uint64_t) ipd << CTPR_IPD_OFF);
if (type == LDISP) {
reg |= (uint64_t) CTPR_OPC_LDISP << CTPR_OPC_OFF;
}
tcg_gen_movi_tl(e2k_cs.ctprs[ctpr - 1], reg);
} else if (type == SDISP) {
unsigned int disp = GET_FIELD(cs0, 0, 28) << 11;
target_ulong base = ((uint64_t) 0xe2 << 40) | disp;
uint64_t reg = (dc->pc + base) |
((uint64_t) CTPR_TAG_SDISP << CTPR_TAG_OFF) |
((uint64_t) ipd << CTPR_IPD_OFF);
tcg_gen_movi_tl(e2k_cs.ctprs[ctpr - 1], reg);
}
/* Note that RETURN is said to be COPF1. I can't understand what its
`CS0.param' is needed for: all of the bits except the three
lowermost ones are undefined, while the latter also known as "type"
field should be filled in with zeroes. */
if (type == RETURN) {
TCGv_i32 t0 = tcg_const_i32(ipd);
if (ctpr != 3) {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPN);
}
gen_helper_prep_return(e2k_cs.ctprs[2], cpu_env, t0);
tcg_temp_free_i32(t0);
}
/* GETTSD has as meaningless `CS0.param' as RETURN. The only
difference is that its `CS0.param.type' should be equal to `1'. I
wonder if I should check for that and output something like
"invalid gettsd" if this turns out not to be the case . . . */
if (type == GETTSD) {
// TODO: gettsd
e2k_todo_illop(dc, "gettsd");
}
if (type == PUTTSD) {
// unsigned int disp = (cs0 & 0x0fffffff);
// int sgnd_disp = ((int) (disp << 4)) >> 1;
/* PUTTSD obviously doesn't take %ctpr{j} parameter. TODO: beware of
an optional predicate which may control its execution which is
encoded via `SS.ctcond.psrc' and `SS.ts_opc == PUTTSDC{P,N}' in
case of `SS.type == 1' (see C.21.4). I wonder if `ct %ctpr<j>'
encoded in `SS.ctop' under the same `SS.ctcond' takes an effect in
such a case. */
// my_printf ("%s0x%llx", type == PUTTSD ? "" : ", ",
/* FIXME: this way I ensure that it'll work correctly
both on 32 and 64-bit hosts. */
// (unsigned long long) (instr_addr + sgnd_disp));
// TODO: puttsd
e2k_todo_illop(dc, "puttsd");
}
if (type == PREF) {
// unsigned int pdisp = (bundle->cs0 & 0x0ffffff0) >> 4;
// unsigned int ipd = (bundle->cs0 & 0x00000008) >> 3;
// unsigned int prefr = bundle->cs0 & 0x00000007;
// TODO: pref
e2k_todo_illop(dc, "pref");
}
}
}
static void gen_cs1(DisasContext *dc)
{
enum {
SETR0,
SETR1,
SETEI,
WAIT,
SETBR,
CALL,
MAS_OPC,
FLUSHR,
BG
};
const UnpackedBundle *bundle = &dc->bundle;
unsigned int cs1 = bundle->cs1;
unsigned int opc = (cs1 & 0xf0000000) >> 28;
if (opc == SETEI) {
bool sft = GET_BIT(cs1, 27);
if (sft) {
if (dc->version >= 2) {
// TODO: setsft
e2k_todo_illop(dc, "setsft");
} else {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
}
} else {
// uint8_t eir = GET_FIELD_LEN(cs1, 0, 8);
// TODO: setei
e2k_todo_illop(dc, "setei");
}
} else if (opc == WAIT) {
// unsigned int ma_c = (cs1 & 0x00000020) >> 5;
// unsigned int fl_c = (cs1 & 0x00000010) >> 4;
unsigned int ld_c = (cs1 & 0x00000008) >> 3;
unsigned int st_c = (cs1 & 0x00000004) >> 2;
// unsigned int all_e = (cs1 & 0x00000002) >> 1;
// unsigned int all_c = cs1 & 0x00000001;
if (dc->version >= 5) {
/* `sa{l,s}' fields are `elbrus-v5'-specific. Each of them makes sense
only in the presence of `{ld,st}_c == 1' respectively. */
if (ld_c) {
// unsigned int sal = (cs1 & 0x00000100) >> 8;
// my_printf ("sal = %d, ", sal);
}
if (st_c) {
// unsigned int sas = (cs1 & 0x00000080) >> 7;
// my_printf ("sas = %d, ", sas);
}
}
if (dc->version >= 2) {
/* `trap' field was introduced starting from `elbrus-v2'. */
// unsigned int trap = (cs1 & 0x00000040) >> 6;
// my_printf ("trap = %d, ", trap);
}
// TODO: wait
e2k_todo(dc, "wait");
// my_printf ("ma_c = %d, fl_c = %d, ld_c = %d, st_c = %d, all_e = %d, "
// "all_c = %d", ma_c, fl_c, ld_c, st_c, all_e, all_c);
} else if (opc == CALL) {
unsigned int ctop = (bundle->ss & 0x00000c00) >> 10;
if (ctop) {
dc->ct.type = CT_CALL;
dc->ct.wbs = GET_FIELD(cs1, 0, 7);
} else {
unsigned int cs1_ctopc = (cs1 & 0x380) >> 7;
/* CS1.param.ctpopc == HCALL. CS0 is required to encode HCALL. */
if (cs1_ctopc == 2 && bundle->cs0_present &&
dc->ct.type == CT_NONE)
{
unsigned int cs0 = bundle->cs0;
unsigned int cs0_opc = (cs0 & 0xf0000000) >> 28;
if (cs0_opc == 0) {
// unsigned int hdisp = (cs0 & 0x1e) >> 1;
// TODO: hcall hdisp, wbs ? cond
e2k_todo_illop(dc, "hcall");
}
} else {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
}
}
} else if (opc == MAS_OPC) {
dc->mas[0] = extract32(cs1, 21, 7);
dc->mas[2] = extract32(cs1, 14, 7);
dc->mas[3] = extract32(cs1, 7, 7);
dc->mas[5] = extract32(cs1, 0, 7);
} else if (opc == FLUSHR) {
if (cs1 & 0x00000001) {
// TODO: flushr
e2k_todo_illop(dc, "flushr");
}
if (cs1 & 0x00000002) {
// TODO: flushc
e2k_todo_illop(dc, "flushc");
}
} else if (opc == BG) {
// unsigned int chkm4 = (cs1 & 0x00010000) >> 16;
// unsigned int dmask = (cs1 & 0x0000ff00) >> 8;
// unsigned int umsk = cs1 & 0x000000ff;
// TODO: vfbg
e2k_todo_illop(dc, "vfbg");
}
}
static void gen_jmp(DisasContext *ctx)
{
int cond_type = extract32(ctx->bundle.ss, 5, 4);
int ctpr = extract32(ctx->bundle.ss, 10, 2);
if (ctpr != 0) {
ctx->ct.type = CT_JUMP;
ctx->ct.u.ctpr = e2k_cs.ctprs[ctpr - 1];
}
ctx->ct.is_branch = cond_type > 1;
if (cond_type == 1) {
tcg_gen_movi_i32(e2k_cs.ct_cond, 1);
} else if (cond_type > 1) {
uint8_t psrc = extract32(ctx->bundle.ss, 0, 5);
TCGv_i32 pcond = tcg_temp_local_new_i32();
TCGv_i32 lcond = tcg_temp_local_new_i32();
switch (cond_type) {
case 0x2:
case 0x6:
case 0xf:
/* %predN */
e2k_gen_preg_i32(pcond, psrc);
break;
case 0x3:
case 0x7:
case 0xe: {
TCGv_i32 t0 = tcg_temp_new_i32();
e2k_gen_preg_i32(t0, psrc);
tcg_gen_setcondi_i32(TCG_COND_EQ, pcond, t0, 0);
tcg_temp_free_i32(t0);
break;
}
default:
break;
}
switch (cond_type) {
case 0x4:
case 0x6:
case 0xe:
/* #LOOP_END */
e2k_gen_is_loop_end_i32(lcond);
break;
case 0x5:
case 0x7:
case 0xf: { /* #NOT_LOOP_END */
TCGv_i32 t0 = tcg_temp_new_i32();
e2k_gen_is_loop_end_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_EQ, lcond, t0, 0);
tcg_temp_free_i32(t0);
break;
}
}
switch (cond_type) {
case 0x2:
case 0x3:
/* {,~}%predN */
tcg_gen_mov_i32(e2k_cs.ct_cond, pcond);
break;
case 0x4:
case 0x5:
/* #{,NOT_}LOOP_END */
tcg_gen_mov_i32(e2k_cs.ct_cond, lcond);
break;
case 0x6:
case 0xe: {
/* {,~}%predN || #LOOP_END */
TCGv_i32 z = tcg_const_i32(0);
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_or_i32(t0, pcond, lcond);
tcg_gen_movcond_i32(TCG_COND_EQ, e2k_cs.ct_cond,
ctx->is_prologue, z, t0, lcond);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(z);
break;
}
case 0x7:
case 0xf: {
/* {,~}%predN && #NOT_LOOP_END */
TCGv_i32 z = tcg_const_i32(0);
TCGv_i32 t0 = tcg_temp_new_i32();
tcg_gen_and_i32(t0, pcond, lcond);
tcg_gen_movcond_i32(TCG_COND_EQ, e2k_cs.ct_cond,
ctx->is_prologue, z, t0, lcond);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(z);
break;
}
case 0x8:
/* %MLOCK || %dt_alM */
if (psrc & 0xf) {
// static const int conv[] = {0, 1, 3, 4};
int i;
e2k_todo(ctx, "%%MLOCK || %%dt_alM");
// %dt_al
for (i = 0; i < 4; i++) {
if (psrc & (1 << i)) {
// i
}
}
} else {
/* %MLOCK */
if (ctx->mlock) {
tcg_gen_mov_i32(e2k_cs.ct_cond, ctx->mlock);
} else {
tcg_gen_movi_i32(e2k_cs.ct_cond, 0);
}
}
break;
case 0x9: {
/* `lock_cond || pl_cond' control transfer conditions. */
unsigned int type = (psrc & 0x18) >> 3;
if (type == 0) {
// static const int cmp_num_to_alc[] = {0, 1, 3, 4};
// unsigned int cmp_num = (psrc & 0x6) >> 1;
// unsigned int neg = psrc & 0x1;
//
// my_printf ("%%MLOCK || %s%%cmp%d", neg ? "~" : "",
// cmp_num_to_alc[cmp_num]);
e2k_todo(ctx, "%%MLOCK || %%cmpN");
} else if (type == 1) {
// unsigned int cmp_jk = (psrc & 0x4) >> 2;
// unsigned int negj = (psrc & 0x2) >> 1;
// unsigned int negk = psrc & 0x1;
// my_printf ("%%MLOCK || %s%%cmp%d || %s%%cmp%d",
// negj ? "~" : "", cmp_jk == 0 ? 0 : 3,
// negk ? "~" : "", cmp_jk == 0 ? 1 : 4);
e2k_todo(ctx, "%%MLOCK || %%cmpN || %%cmpM");
} else if (type == 2) {
// unsigned int clp_num = (psrc & 0x6) >> 1;
// unsigned int neg = psrc & 0x1;
// "%%MLOCK || %s%%clp%d", neg ? "~" : "", clp_num
e2k_todo(ctx, "%%MLOCK || %%clpN");
}
break;
}
default:
e2k_todo_illop(ctx, "undefined control transfer type %#x", cond_type);
break;
}
tcg_temp_free_i32(lcond);
tcg_temp_free_i32(pcond);
}
}
void e2k_control_window_change(DisasContext *dc)
{
enum {
SETR0,
SETR1,
SETEI,
WAIT,
SETBR,
CALL,
MAS_OPC,
FLUSHR,
BG
};
const UnpackedBundle *bundle = &dc->bundle;
uint32_t cs1 = bundle->cs1;
int opc = extract32(cs1, 28, 4);
if (!dc->bundle.cs1_present) {
return;
}
if (opc == SETR0 || opc == SETR1 || opc == SETBR) {
bool setbp = (cs1 >> 27) & 1;
bool setbn = (cs1 >> 26) & 1;
if (opc == SETR1) {
if (!bundle->lts_present[0]) {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
} else {
/* Find out if VFRPSZ is always encoded together with SETWD. This
seems to be the case even if no SETWD has been explicitly
specified. */
// unsigned int rpsz = (bundle->lts[0] & 0x0001f000) >> 12;
e2k_todo(dc, "vfrpsz");
}
}
if (opc == SETR0 || opc == SETR1) {
if (!bundle->lts_present[0]) {
e2k_tr_gen_exception(dc, E2K_EXCP_ILLOPC);
} else {
TCGv_i32 lts = tcg_const_i32(bundle->lts[0]);
gen_helper_setwd(cpu_env, lts);
tcg_temp_free_i32(lts);
}
}
if (setbn) {
int rbs = GET_FIELD(cs1, BR_RBS_OFF, BR_RBS_LEN);
int rsz = GET_FIELD(cs1, BR_RSZ_OFF, BR_RSZ_LEN);
int rcur = GET_FIELD(cs1, BR_RCUR_OFF, BR_RCUR_LEN);
tcg_gen_movi_i32(e2k_cs.boff, rbs * 2);
tcg_gen_movi_i32(e2k_cs.bsize, (rsz + 1) * 2);
tcg_gen_movi_i32(e2k_cs.bcur, rcur * 2);
}
if (setbp) {
int psz = GET_FIELD(cs1, BR_PSZ_OFF, BR_PSZ_LEN);
tcg_gen_movi_i32(e2k_cs.psize, psz);
tcg_gen_movi_i32(e2k_cs.pcur, 0);
}
}
}
static void gen_prologue_epilogue(DisasContext *ctx)
{
TCGv_i32 t0 = tcg_temp_new_i32();
ctx->is_prologue = e2k_get_temp_i32(ctx);
e2k_gen_pcnt_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_NE, ctx->is_prologue, t0, 0);
ctx->is_epilogue = e2k_get_temp_i32(ctx);
e2k_gen_lcnt_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_EQ, ctx->is_epilogue, t0, 0);
tcg_temp_free_i32(t0);
}
void e2k_control_execute(DisasContext *ctx)
{
ctx->ct.type = CT_NONE;
ctx->loop_mode = (ctx->bundle.hs & (1 << 10)) != 0;
gen_prologue_epilogue(ctx);
if (ctx->bundle.ss_present) {
gen_jmp(ctx);
}
if (ctx->bundle.cs0_present) {
gen_cs0(ctx);
}
if (ctx->bundle.cs1_present) {
gen_cs1(ctx);
}
}

213
target/e2k/translate/plu.c Normal file
View File

@ -0,0 +1,213 @@
#include "qemu/osdep.h"
#include "qemu.h"
#include "exec/log.h"
#include "translate.h"
static void gen_get_lp(TCGv_i32 ret, uint16_t clp, int offset, TCGv_i32 lp[7])
{
int p = GET_FIELD(clp, offset, 3);
int neg = GET_BIT(clp, offset + 3);
tcg_gen_xori_i32(ret, lp[p], neg);
}
void e2k_gen_cond_i32(DisasContext *ctx, TCGv_i32 ret, uint8_t psrc)
{
if (psrc & 0x80) {
if (psrc == 0xc0) {
// TODO: %bgrpred
qemu_log_mask(LOG_UNIMP, "%#lx: %%bgrpred is not implemented!\n", ctx->pc);
abort();
} else if ((psrc & 0xe0) == 0xc0) {
// TODO: %rndpredN
qemu_log_mask(LOG_UNIMP, "%#lx: %%rndpred is not implemented!\n", ctx->pc);
abort();
} else {
e2k_tr_gen_exception(ctx, E2K_EXCP_ILLOPN);
}
} else {
int idx = extract8(psrc, 0, 5);
if (psrc == 0) {
// %lcntex
e2k_gen_lcntex(ret);
} else if ((psrc & 0x40) == 0) {
// TODO: %spredMASK
qemu_log_mask(LOG_UNIMP, "%#lx: %%spred is not implemented!\n", ctx->pc);
abort();
} else if ((psrc & 0x60) == 0x60) {
// %predN
e2k_gen_preg_i32(ret, idx);
} else {
// %pcntN
TCGv_i32 t0 = tcg_temp_new_i32();
e2k_gen_pcnt_i32(t0);
tcg_gen_setcondi_i32(TCG_COND_LEU, ret, t0, idx);
tcg_temp_free_i32(t0);
}
}
}
static inline void scan_needed(const UnpackedBundle *bundle, int need[7])
{
bool once_more = true;
unsigned int i;
for (i = 0; i < 3; i++) {
if (bundle->pls_present[i] && GET_BIT(bundle->pls[i], 5)) {
need[4 + i] = 1;
}
}
while (once_more) {
once_more = false;
for (i = 0; i < 3; i++) {
int p0, p1;
if (need[4 + i] != 1) {
continue;
}
p0 = GET_FIELD(bundle->pls[i], 10, 3);
p1 = GET_FIELD(bundle->pls[i], 6, 3);
if (p0 < 7 && need[p0] == 0) {
need[p0] = 1;
if (p0 >= 4) {
once_more = true;
}
}
if (p1 < 7 && need[p1] == 0) {
need[p1] = 1;
if (p1 >= 4) {
once_more = true;
}
}
need[4 + i] = 2;
}
}
}
void e2k_plu_execute(DisasContext *ctx)
{
const UnpackedBundle *bundle = &ctx->bundle;
int need[7] = { 0 };
unsigned int i;
TCGv_i32 lp[7];
scan_needed(bundle, need);
for (i = 0; i < 7; i++) {
if (need[i]) {
lp[i] = tcg_temp_new_i32();
}
}
for (i = 0; i < 3; i++) {
ctx->pl_results[i].reg = -1;
if (!bundle->pls_present[i]) {
continue;
}
if (i < 2) {
if (need[i * 2]) {
int elp = GET_FIELD(bundle->pls[i], 24, 7);
e2k_gen_cond_i32(ctx, lp[i * 2], elp);
}
if (need[i * 2 + 1]) {
int elp = GET_FIELD(bundle->pls[i], 16, 7);
e2k_gen_cond_i32(ctx, lp[i * 2 + 1], elp);
}
}
if (need[4 + i]) {
uint16_t clp = GET_FIELD(bundle->pls[i], 0, 16);
int opc = GET_FIELD(clp, 14, 2);
TCGv_i32 p0 = tcg_temp_new_i32();
TCGv_i32 p1 = tcg_temp_new_i32();
int vdst = GET_BIT(clp, 5);
int pdst = GET_FIELD(clp, 0, 5);
// TODO: check clp arg
// {C/M}LP0 0, 1 => 4
// {C/M}LP1 0, 1, 2, 3, 4 => 5
// {C/M}LP2 0, 1, 2, 3, 4, 5 => 6
// maximal cascading is 2
gen_get_lp(p0, clp, 10, lp);
gen_get_lp(p1, clp, 6, lp);
if (vdst) {
ctx->pl_results[i].reg = pdst;
ctx->pl_results[i].value = e2k_get_temp_i32(ctx);
}
switch (opc) {
case 0: /* andp */
// FIXME: what is the difference between `andp` and `landp`?
case 1: /* landp */
tcg_gen_and_i32(lp[4 + i], p0, p1);
if (vdst) {
tcg_gen_mov_i32(ctx->pl_results[i].value, lp[4 + i]);
}
break;
case 3: { /* movep */
// FIXME: clp cannot read result of movep???
tcg_gen_and_i32(lp[4 + i], p0, p1);
if (vdst) {
TCGv_i32 one = tcg_const_i32(1);
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i32 t1 = tcg_temp_new_i32();
e2k_gen_preg_i64(t0, pdst);
tcg_gen_extrl_i64_i32(t1, t0);
tcg_gen_movcond_i32(TCG_COND_EQ, ctx->pl_results[i].value,
p0, one, p1, t1);
tcg_temp_free_i32(t1);
tcg_temp_free_i64(t0);
tcg_temp_free_i32(one);
}
break;
}
default:
abort();
break;
}
}
}
for (i = 0; i < 7; i++) {
if (need[i]) {
tcg_temp_free_i32(lp[i]);
}
}
}
void e2k_plu_commit(DisasContext *ctx)
{
unsigned int i;
for (i = 0; i < 3; i++) {
TCGv_i64 t0;
if (ctx->pl_results[i].reg < 0) {
continue;
}
t0 = tcg_temp_new_i64();
tcg_gen_extu_i32_i64(t0, ctx->pl_results[i].value);
e2k_gen_store_preg(ctx->pl_results[i].reg, t0);
tcg_temp_free_i64(t0);
}
}

View File

@ -0,0 +1,302 @@
#include "qemu/osdep.h"
#include "qemu.h"
#include "exec/log.h"
#include "translate.h"
static inline void gen_ptr_from_index(TCGv_ptr ret, TCGv_ptr ptr, TCGv_i32 idx,
int size)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_ptr t1 = tcg_temp_new_ptr();
tcg_gen_muli_i32(t0, idx, size);
tcg_gen_ext_i32_ptr(t1, t0);
tcg_gen_add_ptr(ret, ptr, t1);
tcg_temp_free_ptr(t1);
tcg_temp_free_i32(t0);
}
static inline void gen_preg_index(TCGv_i32 ret, int idx)
{
TCGv_i32 i = tcg_const_i32(idx);
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
TCGv_i32 t3 = tcg_temp_new_i32();
assert(idx < 32);
tcg_gen_addi_i32(t0, e2k_cs.psize, 1);
tcg_gen_addi_i32(t1, e2k_cs.pcur, idx);
tcg_gen_remu_i32(t2, t1, t0);
tcg_gen_movi_i32(t3, idx);
tcg_gen_movcond_i32(TCG_COND_LEU, ret, i, e2k_cs.psize, t2, t3);
tcg_temp_free_i32(t3);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(i);
}
static void gen_preg_offset(TCGv_i64 ret, int idx)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
gen_preg_index(t0, idx);
tcg_gen_muli_i32(t1, t0, 2);
tcg_gen_extu_i32_i64(ret, t1);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t0);
}
static void gen_preg_clear(TCGv_i64 ret, TCGv_i64 offset)
{
TCGv_i64 t0 = tcg_const_i64(3);
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
tcg_gen_shl_i64(t1, t0, offset);
tcg_gen_not_i64(t2, t1);
tcg_gen_and_i64(ret, t2, e2k_cs.pregs);
tcg_temp_free_i64(t2);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
}
void e2k_gen_preg_i64(TCGv_i64 ret, int reg)
{
TCGv_i64 one = tcg_const_i64(1);
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
gen_preg_offset(t0, reg);
tcg_gen_shl_i64(t1, one, t0);
tcg_gen_and_i64(t2, e2k_cs.pregs, t1);
tcg_gen_setcondi_i64(TCG_COND_NE, ret, t2, 0);
tcg_temp_free_i64(t2);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(one);
}
void e2k_gen_preg_i32(TCGv_i32 ret, int reg)
{
TCGv_i64 t0 = tcg_temp_new_i64();
e2k_gen_preg_i64(t0, reg);
tcg_gen_extrl_i64_i32(ret, t0);
tcg_temp_free_i64(t0);
}
TCGv_i64 e2k_get_preg(DisasContext *dc, int reg)
{
TCGv_i64 ret = e2k_get_temp_i64(dc);
e2k_gen_preg_i64(ret, reg);
return ret;
}
void e2k_gen_store_preg(int idx, TCGv_i64 val)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
TCGv_i64 t2 = tcg_temp_new_i64();
TCGv_i64 t3 = tcg_temp_new_i64();
gen_preg_offset(t0, idx);
gen_preg_clear(t1, t0);
tcg_gen_andi_i64(t2, val, 3);
tcg_gen_shl_i64(t3, val, t0);
tcg_gen_or_i64(e2k_cs.pregs, t1, t3);
tcg_temp_free_i64(t3);
tcg_temp_free_i64(t2);
tcg_temp_free_i64(t1);
tcg_temp_free_i64(t0);
}
static inline void gen_reg_tag_ptr(TCGv_ptr ret, TCGv_i32 idx)
{
TCGv_ptr t0 = tcg_temp_new_ptr();
TCGv_ptr t1 = tcg_temp_new_ptr();
tcg_gen_ext_i32_ptr(t0, idx);
tcg_gen_addi_ptr(t1, cpu_env, offsetof(CPUE2KState, tags));
tcg_gen_add_ptr(ret, t1, t0);
tcg_temp_free_ptr(t1);
tcg_temp_free_ptr(t0);
}
void e2k_gen_reg_tag_read_i64(TCGv_i32 ret, TCGv_i32 idx)
{
TCGv_ptr t0 = tcg_temp_new_ptr();
gen_reg_tag_ptr(t0, idx);
tcg_gen_ld8u_i32(ret, t0, 0);
tcg_temp_free_ptr(t0);
}
void e2k_gen_reg_tag_read_i32(TCGv_i32 ret, TCGv_i32 idx)
{
TCGv_ptr t0 = tcg_temp_new_ptr();
TCGv_i32 t1 = tcg_temp_new_i32();
gen_reg_tag_ptr(t0, idx);
tcg_gen_ld8u_i32(t1, t0, 0);
tcg_gen_andi_i32(ret, t1, GEN_MASK(0, E2K_TAG_SIZE));
tcg_temp_free_ptr(t0);
}
static inline void gen_tag_check(TCGv_i32 ret, TCGv_i32 tag)
{
// FIXME: what CPU does if tag is greater than 1?
tcg_gen_setcondi_i32(TCG_COND_NE, ret, tag, 0);
}
void e2k_gen_reg_tag_check_i64(TCGv_i32 ret, TCGv_i32 tag)
{
gen_tag_check(ret, tag);
}
void e2k_gen_reg_tag_check_i32(TCGv_i32 ret, TCGv_i32 tag)
{
TCGv_i32 t0 = tcg_temp_new_i32();
e2k_gen_reg_tag_extract_lo(t0, tag);
gen_tag_check(ret, t0);
tcg_temp_free_i32(t0);
}
void e2k_gen_reg_tag_write_i64(TCGv_i32 value, TCGv_i32 idx)
{
TCGv_ptr t0 = tcg_temp_new_ptr();
gen_reg_tag_ptr(t0, idx);
tcg_gen_st8_i32(value, t0, 0);
tcg_temp_free_ptr(t0);
}
void e2k_gen_reg_tag_write_i32(TCGv_i32 value, TCGv_i32 idx)
{
TCGv_ptr t0 = tcg_temp_new_ptr();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
gen_reg_tag_ptr(t0, idx);
tcg_gen_ld8u_i32(t1, t0, 0);
tcg_gen_deposit_i32(t2, t1, value, 0, E2K_TAG_SIZE);
tcg_gen_st8_i32(t2, t0, 0);
tcg_temp_free_i32(t2);
tcg_temp_free_i32(t1);
tcg_temp_free_ptr(t0);
}
static inline void gen_reg_index_from_wreg(TCGv_i32 ret, TCGv_i32 idx)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_local_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2;
tcg_gen_mov_i32(t0, idx);
tcg_gen_brcond_i32(TCG_COND_LTU, t0, e2k_cs.wd_size, l0);
e2k_gen_exception(E2K_EXCP_MAPERR);
gen_set_label(l0);
tcg_gen_add_i32(t1, e2k_cs.wd_base, t0);
tcg_temp_free_i32(t0);
t2 = tcg_const_i32(E2K_NR_COUNT);
tcg_gen_remu_i32(ret, t1, t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t2);
}
void e2k_gen_reg_index_from_wregi(TCGv_i32 ret, int idx)
{
TCGv_i32 t0 = tcg_const_i32(idx);
gen_reg_index_from_wreg(ret, t0);
tcg_temp_free_i32(t0);
}
void e2k_gen_reg_index_from_bregi(TCGv_i32 ret, int idx)
{
TCGLabel *l0 = gen_new_label();
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32();
TCGv_i32 t2 = tcg_temp_new_i32();
tcg_gen_brcondi_i32(tcg_invert_cond(TCG_COND_LTU), e2k_cs.bsize, idx, l0);
e2k_gen_exception(E2K_EXCP_MAPERR);
gen_set_label(l0);
tcg_gen_addi_i32(t0, e2k_cs.bcur, idx);
tcg_gen_remu_i32(t1, t0, e2k_cs.bsize);
tcg_temp_free_i32(t0);
tcg_gen_add_i32(t2, e2k_cs.boff, t1);
tcg_temp_free_i32(t1);
gen_reg_index_from_wreg(ret, t2);
tcg_temp_free_i32(t2);
}
void e2k_gen_reg_index_from_gregi(TCGv_i32 ret, int idx)
{
// TODO: based global registers index
tcg_gen_movi_i32(ret, E2K_NR_COUNT + idx);
}
static inline void gen_reg_ptr(TCGv_ptr ret, TCGv_i32 idx)
{
TCGv_ptr t0 = tcg_temp_new_ptr();
tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, regs));
gen_ptr_from_index(ret, t0, idx, 8);
tcg_temp_free_ptr(t0);
}
static inline void gen_xreg_ptr(TCGv_ptr ret, TCGv_i32 idx)
{
TCGv_ptr t0 = tcg_temp_new_ptr();
tcg_gen_addi_ptr(t0, cpu_env, offsetof(CPUE2KState, xregs));
gen_ptr_from_index(ret, t0, idx, 8);
tcg_temp_free_ptr(t0);
}
#define GEN_REG_READ(name, ty, ptr_func, ld_func) \
void name(ty ret, TCGv_i32 idx) \
{ \
TCGv_ptr t0 = tcg_temp_new_ptr(); \
ptr_func(t0, idx); \
ld_func(ret, t0, 0); \
tcg_temp_free_ptr(t0); \
}
#define GEN_REG_WRITE(name, ty, ptr_func, st_func) \
void name(ty value, TCGv_i32 idx) \
{ \
TCGv_ptr t0 = tcg_temp_new_ptr(); \
ptr_func(t0, idx); \
st_func(value, t0, 0); \
tcg_temp_free_ptr(t0); \
}
GEN_REG_READ(e2k_gen_reg_read_i64, TCGv_i64, gen_reg_ptr, tcg_gen_ld_i64)
GEN_REG_READ(e2k_gen_reg_read_i32, TCGv_i32, gen_reg_ptr, tcg_gen_ld_i32)
GEN_REG_WRITE(e2k_gen_reg_write_i64, TCGv_i64, gen_reg_ptr, tcg_gen_st_i64)
GEN_REG_WRITE(e2k_gen_reg_write_i32, TCGv_i32, gen_reg_ptr, tcg_gen_st_i32)
GEN_REG_READ(e2k_gen_xreg_read_i64, TCGv_i64, gen_xreg_ptr, tcg_gen_ld_i64)
GEN_REG_READ(e2k_gen_xreg_read_i32, TCGv_i32, gen_xreg_ptr, tcg_gen_ld_i32)
GEN_REG_READ(e2k_gen_xreg_read16u_i32, TCGv_i32, gen_xreg_ptr, tcg_gen_ld16u_i32)
GEN_REG_WRITE(e2k_gen_xreg_write_i64, TCGv_i64, gen_xreg_ptr, tcg_gen_st_i64)
GEN_REG_WRITE(e2k_gen_xreg_write_i32, TCGv_i32, gen_xreg_ptr, tcg_gen_st_i32)
GEN_REG_WRITE(e2k_gen_xreg_write16u_i32, TCGv_i32, gen_xreg_ptr, tcg_gen_st16_i32)

View File

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

View File

@ -1957,7 +1957,12 @@ static int32_t x86_guest_base_offset;
# if defined(__x86_64__) && defined(__linux__)
# include <asm/prctl.h>
# include <sys/prctl.h>
int arch_prctl(int code, unsigned long addr);
# include <linux/unistd.h>
static int arch_prctl(int code, unsigned long addr)
{
return syscall(__NR_arch_prctl, code, addr);
}
static inline int setup_guest_base_seg(void)
{
if (arch_prctl(ARCH_SET_GS, guest_base) == 0) {

View File

@ -4628,7 +4628,8 @@ static void tcg_register_jit_int(void *buf_ptr, size_t buf_size,
/* Enable this block to be able to debug the ELF image file creation.
One can use readelf, objdump, or other inspection utilities. */
{
FILE *f = fopen("/tmp/qemu.jit", "w+b");
FILE *f = fopen("@TERMUX_PREFIX@/tmp/qemu.jit", "w+b");
if (f) {
if (fwrite(img, img_size, 1, f) != img_size) {
/* Avoid stupid unused return value warning for fwrite. */

View File

@ -285,5 +285,4 @@ if not get_option('tcg').disabled()
endif
subdir('qapi-schema')
subdir('qtest')
subdir('migration')

View File

@ -69,6 +69,7 @@ fi
: ${cross_cc_cflags_sparc64="-m64 -mcpu=ultrasparc"}
: ${cross_cc_x86_64="x86_64-pc-linux-gnu-gcc"}
: ${cross_cc_cflags_x86_64="-m64"}
: ${cross_cc_e2k="e2k-linux-cc"}
for target in $target_list; do
arch=${target%%-*}
@ -94,7 +95,7 @@ for target in $target_list; do
xtensa|xtensaeb)
arches=xtensa
;;
alpha|cris|hppa|i386|lm32|microblaze|microblazeel|m68k|openrisc|riscv64|s390x|sh4|sparc64)
alpha|cris|hppa|i386|lm32|microblaze|microblazeel|m68k|openrisc|riscv64|s390x|sh4|sparc64|e2k)
arches=$target
;;
*)

View File

@ -0,0 +1,15 @@
# -*- Mode: makefile -*-
#
# Elbrus 2000 tests
E2K_SRC=$(SRC_PATH)/tests/tcg/e2k
VPATH+=$(E2K_SRC)
E2K_TESTS=hello-e2k
TESTS+=$(E2K_TESTS)
#
# hello-e2k is a barebones app
#
hello-e2k: CFLAGS+=-ffreestanding
hello-e2k: LDFLAGS+=-nostdlib

View File

@ -0,0 +1,9 @@
#include <asm/e2k_api.h>
#include <asm/unistd.h>
#define MSG "Hello, world!\n"
void _start(void) {
__E2K_SYSCALL_3(LINUX_SYSCALL64_TRAPNUM, __NR_write, 1, MSG, sizeof(MSG));
__E2K_SYSCALL_1(LINUX_SYSCALL64_TRAPNUM, __NR_exit, 0);
}

View File

@ -29,6 +29,8 @@
#define _FILE_OFFSET_BITS 64
#include <linux/mman.h>
#include "qemu/osdep.h"
#include "qemu/atomic.h"
#include "qemu/ctype.h"

View File

@ -17,7 +17,6 @@
#include "qemu/osdep.h"
#include "qemu/drm.h"
#include <glob.h>
#include <dirent.h>
int qemu_drm_rendernode_open(const char *rendernode)

View File

@ -32,6 +32,7 @@
#include "qemu/host-utils.h"
#if defined CONFIG_LINUX && !defined CONFIG_MEMFD
#include <linux/mman.h>
#include <sys/syscall.h>
#include <asm/unistd.h>

View File

@ -10,7 +10,7 @@
* later. See the COPYING file in the top-level directory.
*/
#ifdef CONFIG_LINUX
#ifdef __linux__
#include <linux/mman.h>
#else /* !CONFIG_LINUX */
#define MAP_SYNC 0x0

View File

@ -246,7 +246,7 @@ bool module_load_one(const char *prefix, const char *lib_name, bool mayfail)
version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION),
G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~",
'_');
dirs[n_dirs++] = g_strdup_printf("/var/run/qemu/%s", version_dir);
dirs[n_dirs++] = g_strdup_printf("@TERMUX_PREFIX@/var/run/qemu/%s", version_dir);
#endif
assert(n_dirs <= ARRAY_SIZE(dirs));

View File

@ -41,6 +41,7 @@
#include "qemu/cutils.h"
#ifdef CONFIG_LINUX
#include <linux/mman.h>
#include <sys/syscall.h>
#endif

View File

@ -900,7 +900,7 @@ static int unix_listen_saddr(UnixSocketAddress *saddr,
path = saddr->path;
} else {
const char *tmpdir = getenv("TMPDIR");
tmpdir = tmpdir ? tmpdir : "/tmp";
tmpdir = tmpdir ? tmpdir : "@TERMUX_PREFIX@/tmp";
path = pathbuf = g_strdup_printf("%s/qemu-socket-XXXXXX", tmpdir);
}

View File

@ -13,6 +13,7 @@
#include "qemu/osdep.h"
#include <sys/ioctl.h>
#include <linux/vfio.h>
#include <linux/mman.h>
#include "qapi/error.h"
#include "exec/ramlist.h"
#include "exec/cpu-common.h"