Commit 33417e7025afa5ea1c38c3c2b2ea53d975b5648b
1 parent
4021dab0
soft mmu support - Memory I/O API - synthetize string instructions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@354 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
10 changed files
with
351 additions
and
234 deletions
cpu-all.h
... | ... | @@ -140,6 +140,7 @@ static inline void stfl(void *ptr, float v) |
140 | 140 | stl(ptr, u.i); |
141 | 141 | } |
142 | 142 | |
143 | + | |
143 | 144 | #if defined(__arm__) && !defined(WORDS_BIGENDIAN) |
144 | 145 | |
145 | 146 | /* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ |
... | ... | @@ -317,6 +318,17 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc); |
317 | 318 | int cpu_breakpoint_remove(CPUState *env, uint32_t pc); |
318 | 319 | void cpu_single_step(CPUState *env, int enabled); |
319 | 320 | |
321 | +/* memory API */ | |
322 | + | |
323 | +typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value); | |
324 | +typedef uint32_t CPUReadMemoryFunc(uint32_t addr); | |
325 | + | |
326 | +void cpu_register_physical_memory(unsigned long start_addr, unsigned long size, | |
327 | + long phys_offset); | |
328 | +int cpu_register_io_memory(int io_index, | |
329 | + CPUReadMemoryFunc **mem_read, | |
330 | + CPUWriteMemoryFunc **mem_write); | |
331 | + | |
320 | 332 | /* gdb stub API */ |
321 | 333 | extern int gdbstub_fd; |
322 | 334 | CPUState *cpu_gdbstub_get_env(void *opaque); | ... | ... |
cpu-arm.h
... | ... | @@ -20,12 +20,10 @@ |
20 | 20 | #ifndef CPU_ARM_H |
21 | 21 | #define CPU_ARM_H |
22 | 22 | |
23 | -#include "config.h" | |
24 | -#include <setjmp.h> | |
23 | +#include "cpu-defs.h" | |
25 | 24 | |
26 | 25 | #define EXCP_UDEF 1 /* undefined instruction */ |
27 | 26 | #define EXCP_SWI 2 /* software interrupt */ |
28 | -#define EXCP_INTERRUPT 256 /* async interruption */ | |
29 | 27 | |
30 | 28 | typedef struct CPUARMState { |
31 | 29 | uint32_t regs[16]; | ... | ... |
cpu-i386.h
... | ... | @@ -20,8 +20,7 @@ |
20 | 20 | #ifndef CPU_I386_H |
21 | 21 | #define CPU_I386_H |
22 | 22 | |
23 | -#include "config.h" | |
24 | -#include <setjmp.h> | |
23 | +#include "cpu-defs.h" | |
25 | 24 | |
26 | 25 | #define R_EAX 0 |
27 | 26 | #define R_ECX 1 |
... | ... | @@ -153,12 +152,6 @@ |
153 | 152 | #define EXCP11_ALGN 17 |
154 | 153 | #define EXCP12_MCHK 18 |
155 | 154 | |
156 | -#define EXCP_INTERRUPT 256 /* async interruption */ | |
157 | -#define EXCP_HLT 257 /* hlt instruction reached */ | |
158 | -#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */ | |
159 | - | |
160 | -#define MAX_BREAKPOINTS 32 | |
161 | - | |
162 | 155 | enum { |
163 | 156 | CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ |
164 | 157 | CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */ |
... | ... | @@ -257,7 +250,8 @@ typedef struct CPUX86State { |
257 | 250 | SegmentCache gdt; /* only base and limit are used */ |
258 | 251 | SegmentCache idt; /* only base and limit are used */ |
259 | 252 | int cpl; /* current cpl */ |
260 | - | |
253 | + int soft_mmu; /* TRUE if soft mmu is being used */ | |
254 | + | |
261 | 255 | /* sysenter registers */ |
262 | 256 | uint32_t sysenter_cs; |
263 | 257 | uint32_t sysenter_esp; |
... | ... | @@ -275,10 +269,16 @@ typedef struct CPUX86State { |
275 | 269 | int interrupt_request; |
276 | 270 | int user_mode_only; /* user mode only simulation */ |
277 | 271 | |
272 | + /* soft mmu support */ | |
273 | + /* 0 = kernel, 1 = user */ | |
274 | + CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; | |
275 | + CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; | |
276 | + | |
277 | + /* ice debug support */ | |
278 | 278 | uint32_t breakpoints[MAX_BREAKPOINTS]; |
279 | 279 | int nb_breakpoints; |
280 | 280 | int singlestep_enabled; |
281 | - | |
281 | + | |
282 | 282 | /* user data */ |
283 | 283 | void *opaque; |
284 | 284 | } CPUX86State; | ... | ... |
exec-i386.h
... | ... | @@ -138,6 +138,7 @@ void cpu_x86_update_cr0(CPUX86State *env); |
138 | 138 | void cpu_x86_update_cr3(CPUX86State *env); |
139 | 139 | void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); |
140 | 140 | int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write); |
141 | +void tlb_fill(unsigned long addr, int is_write, void *retaddr); | |
141 | 142 | void __hidden cpu_lock(void); |
142 | 143 | void __hidden cpu_unlock(void); |
143 | 144 | void do_interrupt(int intno, int is_int, int error_code, |
... | ... | @@ -364,3 +365,52 @@ static inline void load_eflags(int eflags, int update_mask) |
364 | 365 | env->eflags = (env->eflags & ~update_mask) | |
365 | 366 | (eflags & update_mask); |
366 | 367 | } |
368 | + | |
369 | +/* memory access macros */ | |
370 | + | |
371 | +#define ldul ldl | |
372 | +#define lduq ldq | |
373 | +#define ldul_user ldl_user | |
374 | +#define ldul_kernel ldl_kernel | |
375 | + | |
376 | +#define ldub_raw ldub | |
377 | +#define ldsb_raw ldsb | |
378 | +#define lduw_raw lduw | |
379 | +#define ldsw_raw ldsw | |
380 | +#define ldl_raw ldl | |
381 | +#define ldq_raw ldq | |
382 | + | |
383 | +#define stb_raw stb | |
384 | +#define stw_raw stw | |
385 | +#define stl_raw stl | |
386 | +#define stq_raw stq | |
387 | + | |
388 | +#define MEMUSER 0 | |
389 | +#define DATA_SIZE 1 | |
390 | +#include "softmmu_header.h" | |
391 | + | |
392 | +#define DATA_SIZE 2 | |
393 | +#include "softmmu_header.h" | |
394 | + | |
395 | +#define DATA_SIZE 4 | |
396 | +#include "softmmu_header.h" | |
397 | + | |
398 | +#define DATA_SIZE 8 | |
399 | +#include "softmmu_header.h" | |
400 | + | |
401 | +#undef MEMUSER | |
402 | +#define MEMUSER 1 | |
403 | +#define DATA_SIZE 1 | |
404 | +#include "softmmu_header.h" | |
405 | + | |
406 | +#define DATA_SIZE 2 | |
407 | +#include "softmmu_header.h" | |
408 | + | |
409 | +#define DATA_SIZE 4 | |
410 | +#include "softmmu_header.h" | |
411 | + | |
412 | +#define DATA_SIZE 8 | |
413 | +#include "softmmu_header.h" | |
414 | + | |
415 | +#undef MEMUSER | |
416 | + | ... | ... |
exec.c
... | ... | @@ -68,6 +68,7 @@ typedef struct PageDesc { |
68 | 68 | #define L2_SIZE (1 << L2_BITS) |
69 | 69 | |
70 | 70 | static void tb_invalidate_page(unsigned long address); |
71 | +static void io_mem_init(void); | |
71 | 72 | |
72 | 73 | unsigned long real_host_page_size; |
73 | 74 | unsigned long host_page_bits; |
... | ... | @@ -76,6 +77,12 @@ unsigned long host_page_mask; |
76 | 77 | |
77 | 78 | static PageDesc *l1_map[L1_SIZE]; |
78 | 79 | |
80 | +/* io memory support */ | |
81 | +static unsigned long *l1_physmap[L1_SIZE]; | |
82 | +CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; | |
83 | +CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; | |
84 | +static int io_mem_nb; | |
85 | + | |
79 | 86 | static void page_init(void) |
80 | 87 | { |
81 | 88 | /* NOTE: we can always suppose that host_page_size >= |
... | ... | @@ -201,6 +208,7 @@ void cpu_exec_init(void) |
201 | 208 | if (!code_gen_ptr) { |
202 | 209 | code_gen_ptr = code_gen_buffer; |
203 | 210 | page_init(); |
211 | + io_mem_init(); | |
204 | 212 | } |
205 | 213 | } |
206 | 214 | |
... | ... | @@ -744,3 +752,133 @@ void page_unmap(void) |
744 | 752 | tb_flush(); |
745 | 753 | } |
746 | 754 | #endif |
755 | + | |
756 | +void tlb_flush(CPUState *env) | |
757 | +{ | |
758 | +#if defined(TARGET_I386) | |
759 | + int i; | |
760 | + for(i = 0; i < CPU_TLB_SIZE; i++) { | |
761 | + env->tlb_read[0][i].address = -1; | |
762 | + env->tlb_write[0][i].address = -1; | |
763 | + env->tlb_read[1][i].address = -1; | |
764 | + env->tlb_write[1][i].address = -1; | |
765 | + } | |
766 | +#endif | |
767 | +} | |
768 | + | |
769 | +void tlb_flush_page(CPUState *env, uint32_t addr) | |
770 | +{ | |
771 | +#if defined(TARGET_I386) | |
772 | + int i; | |
773 | + | |
774 | + i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); | |
775 | + env->tlb_read[0][i].address = -1; | |
776 | + env->tlb_write[0][i].address = -1; | |
777 | + env->tlb_read[1][i].address = -1; | |
778 | + env->tlb_write[1][i].address = -1; | |
779 | +#endif | |
780 | +} | |
781 | + | |
782 | +static inline unsigned long *physpage_find_alloc(unsigned int page) | |
783 | +{ | |
784 | + unsigned long **lp, *p; | |
785 | + unsigned int index, i; | |
786 | + | |
787 | + index = page >> TARGET_PAGE_BITS; | |
788 | + lp = &l1_physmap[index >> L2_BITS]; | |
789 | + p = *lp; | |
790 | + if (!p) { | |
791 | + /* allocate if not found */ | |
792 | + p = malloc(sizeof(unsigned long) * L2_SIZE); | |
793 | + for(i = 0; i < L2_SIZE; i++) | |
794 | + p[i] = IO_MEM_UNASSIGNED; | |
795 | + *lp = p; | |
796 | + } | |
797 | + return p + (index & (L2_SIZE - 1)); | |
798 | +} | |
799 | + | |
800 | +/* return NULL if no page defined (unused memory) */ | |
801 | +unsigned long physpage_find(unsigned long page) | |
802 | +{ | |
803 | + unsigned long *p; | |
804 | + unsigned int index; | |
805 | + index = page >> TARGET_PAGE_BITS; | |
806 | + p = l1_physmap[index >> L2_BITS]; | |
807 | + if (!p) | |
808 | + return IO_MEM_UNASSIGNED; | |
809 | + return p[index & (L2_SIZE - 1)]; | |
810 | +} | |
811 | + | |
812 | +/* register physical memory. 'size' must be a multiple of the target | |
813 | + page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an | |
814 | + io memory page */ | |
815 | +void cpu_register_physical_memory(unsigned long start_addr, unsigned long size, | |
816 | + long phys_offset) | |
817 | +{ | |
818 | + unsigned long addr, end_addr; | |
819 | + unsigned long *p; | |
820 | + | |
821 | + end_addr = start_addr + size; | |
822 | + for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) { | |
823 | + p = physpage_find_alloc(addr); | |
824 | + *p = phys_offset; | |
825 | + if ((phys_offset & ~TARGET_PAGE_MASK) == 0) | |
826 | + phys_offset += TARGET_PAGE_SIZE; | |
827 | + } | |
828 | +} | |
829 | + | |
830 | +static uint32_t unassigned_mem_readb(uint32_t addr) | |
831 | +{ | |
832 | + return 0; | |
833 | +} | |
834 | + | |
835 | +static void unassigned_mem_writeb(uint32_t addr, uint32_t val) | |
836 | +{ | |
837 | +} | |
838 | + | |
839 | +static CPUReadMemoryFunc *unassigned_mem_read[3] = { | |
840 | + unassigned_mem_readb, | |
841 | + unassigned_mem_readb, | |
842 | + unassigned_mem_readb, | |
843 | +}; | |
844 | + | |
845 | +static CPUWriteMemoryFunc *unassigned_mem_write[3] = { | |
846 | + unassigned_mem_writeb, | |
847 | + unassigned_mem_writeb, | |
848 | + unassigned_mem_writeb, | |
849 | +}; | |
850 | + | |
851 | + | |
852 | +static void io_mem_init(void) | |
853 | +{ | |
854 | + io_mem_nb = 1; | |
855 | + cpu_register_io_memory(0, unassigned_mem_read, unassigned_mem_write); | |
856 | +} | |
857 | + | |
858 | +/* mem_read and mem_write are arrays of functions containing the | |
859 | + function to access byte (index 0), word (index 1) and dword (index | |
860 | + 2). All functions must be supplied. If io_index is non zero, the | |
861 | + corresponding io zone is modified. If it is zero, a new io zone is | |
862 | + allocated. The return value can be used with | |
863 | + cpu_register_physical_memory(). (-1) is returned if error. */ | |
864 | +int cpu_register_io_memory(int io_index, | |
865 | + CPUReadMemoryFunc **mem_read, | |
866 | + CPUWriteMemoryFunc **mem_write) | |
867 | +{ | |
868 | + int i; | |
869 | + | |
870 | + if (io_index <= 0) { | |
871 | + if (io_index >= IO_MEM_NB_ENTRIES) | |
872 | + return -1; | |
873 | + io_index = io_mem_nb++; | |
874 | + } else { | |
875 | + if (io_index >= IO_MEM_NB_ENTRIES) | |
876 | + return -1; | |
877 | + } | |
878 | + | |
879 | + for(i = 0;i < 3; i++) { | |
880 | + io_mem_read[io_index][i] = mem_read[i]; | |
881 | + io_mem_write[io_index][i] = mem_write[i]; | |
882 | + } | |
883 | + return io_index << IO_MEM_SHIFT; | |
884 | +} | ... | ... |
exec.h
... | ... | @@ -21,6 +21,17 @@ |
21 | 21 | /* allow to see translation results - the slowdown should be negligible, so we leave it */ |
22 | 22 | #define DEBUG_DISAS |
23 | 23 | |
24 | +#ifndef glue | |
25 | +#define xglue(x, y) x ## y | |
26 | +#define glue(x, y) xglue(x, y) | |
27 | +#define stringify(s) tostring(s) | |
28 | +#define tostring(s) #s | |
29 | +#endif | |
30 | + | |
31 | +#if GCC_MAJOR < 3 | |
32 | +#define __builtin_expect(x, n) (x) | |
33 | +#endif | |
34 | + | |
24 | 35 | /* is_jmp field values */ |
25 | 36 | #define DISAS_NEXT 0 /* next instruction can be analyzed */ |
26 | 37 | #define DISAS_JUMP 1 /* only pc was modified dynamically */ |
... | ... | @@ -44,14 +55,17 @@ extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; |
44 | 55 | |
45 | 56 | #if defined(TARGET_I386) |
46 | 57 | |
47 | -#define GEN_FLAG_CODE32_SHIFT 0 | |
48 | -#define GEN_FLAG_ADDSEG_SHIFT 1 | |
49 | -#define GEN_FLAG_SS32_SHIFT 2 | |
50 | -#define GEN_FLAG_VM_SHIFT 3 | |
51 | -#define GEN_FLAG_ST_SHIFT 4 | |
52 | -#define GEN_FLAG_TF_SHIFT 8 /* same position as eflags */ | |
53 | -#define GEN_FLAG_CPL_SHIFT 9 | |
54 | -#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */ | |
58 | +#define GEN_FLAG_CODE32_SHIFT 0 | |
59 | +#define GEN_FLAG_ADDSEG_SHIFT 1 | |
60 | +#define GEN_FLAG_SS32_SHIFT 2 | |
61 | +#define GEN_FLAG_VM_SHIFT 3 | |
62 | +#define GEN_FLAG_ST_SHIFT 4 | |
63 | +#define GEN_FLAG_TF_SHIFT 8 /* same position as eflags */ | |
64 | +#define GEN_FLAG_CPL_SHIFT 9 | |
65 | +#define GEN_FLAG_SOFT_MMU_SHIFT 11 | |
66 | +#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */ | |
67 | + | |
68 | +void optimize_flags_init(void); | |
55 | 69 | |
56 | 70 | #endif |
57 | 71 | |
... | ... | @@ -68,6 +82,8 @@ int cpu_restore_state(struct TranslationBlock *tb, |
68 | 82 | void cpu_exec_init(void); |
69 | 83 | int page_unprotect(unsigned long address); |
70 | 84 | void page_unmap(void); |
85 | +void tlb_flush_page(CPUState *env, uint32_t addr); | |
86 | +void tlb_flush(CPUState *env); | |
71 | 87 | |
72 | 88 | #define CODE_GEN_MAX_SIZE 65536 |
73 | 89 | #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ |
... | ... | @@ -230,6 +246,17 @@ dummy_label ## n:\ |
230 | 246 | |
231 | 247 | #endif |
232 | 248 | |
249 | +/* physical memory access */ | |
250 | +#define IO_MEM_NB_ENTRIES 256 | |
251 | +#define TLB_INVALID_MASK (1 << 3) | |
252 | +#define IO_MEM_SHIFT 4 | |
253 | +#define IO_MEM_UNASSIGNED (1 << IO_MEM_SHIFT) | |
254 | + | |
255 | +unsigned long physpage_find(unsigned long page); | |
256 | + | |
257 | +extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; | |
258 | +extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; | |
259 | + | |
233 | 260 | #ifdef __powerpc__ |
234 | 261 | static inline int testandset (int *p) |
235 | 262 | { | ... | ... |
helper-i386.c
... | ... | @@ -781,7 +781,7 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) |
781 | 781 | int new_cs, new_eip; |
782 | 782 | uint32_t esp, esp_mask; |
783 | 783 | uint8_t *ssp; |
784 | - | |
784 | + | |
785 | 785 | new_cs = T0; |
786 | 786 | new_eip = T1; |
787 | 787 | esp = env->regs[R_ESP]; |
... | ... | @@ -1741,3 +1741,34 @@ void helper_frstor(uint8_t *ptr, int data32) |
1741 | 1741 | } |
1742 | 1742 | } |
1743 | 1743 | |
1744 | +#define SHIFT 0 | |
1745 | +#include "softmmu_template.h" | |
1746 | + | |
1747 | +#define SHIFT 1 | |
1748 | +#include "softmmu_template.h" | |
1749 | + | |
1750 | +#define SHIFT 2 | |
1751 | +#include "softmmu_template.h" | |
1752 | + | |
1753 | +#define SHIFT 3 | |
1754 | +#include "softmmu_template.h" | |
1755 | + | |
1756 | +/* try to fill the TLB and return an exception if error */ | |
1757 | +void tlb_fill(unsigned long addr, int is_write, void *retaddr) | |
1758 | +{ | |
1759 | + TranslationBlock *tb; | |
1760 | + int ret; | |
1761 | + unsigned long pc; | |
1762 | + ret = cpu_x86_handle_mmu_fault(env, addr, is_write); | |
1763 | + if (ret) { | |
1764 | + /* now we have a real cpu fault */ | |
1765 | + pc = (unsigned long)retaddr; | |
1766 | + tb = tb_find_pc(pc); | |
1767 | + if (tb) { | |
1768 | + /* the PC is inside the translated code. It means that we have | |
1769 | + a virtual CPU fault */ | |
1770 | + cpu_restore_state(tb, env, pc); | |
1771 | + } | |
1772 | + raise_exception_err(EXCP0E_PAGE, env->error_code); | |
1773 | + } | |
1774 | +} | ... | ... |
op-i386.c
... | ... | @@ -376,70 +376,14 @@ void OPPROTO op_andl_A0_ffff(void) |
376 | 376 | |
377 | 377 | /* memory access */ |
378 | 378 | |
379 | -void OPPROTO op_ldub_T0_A0(void) | |
380 | -{ | |
381 | - T0 = ldub((uint8_t *)A0); | |
382 | -} | |
383 | - | |
384 | -void OPPROTO op_ldsb_T0_A0(void) | |
385 | -{ | |
386 | - T0 = ldsb((int8_t *)A0); | |
387 | -} | |
388 | - | |
389 | -void OPPROTO op_lduw_T0_A0(void) | |
390 | -{ | |
391 | - T0 = lduw((uint8_t *)A0); | |
392 | -} | |
393 | - | |
394 | -void OPPROTO op_ldsw_T0_A0(void) | |
395 | -{ | |
396 | - T0 = ldsw((int8_t *)A0); | |
397 | -} | |
398 | - | |
399 | -void OPPROTO op_ldl_T0_A0(void) | |
400 | -{ | |
401 | - T0 = ldl((uint8_t *)A0); | |
402 | -} | |
379 | +#define MEMSUFFIX | |
380 | +#include "ops_mem.h" | |
403 | 381 | |
404 | -void OPPROTO op_ldub_T1_A0(void) | |
405 | -{ | |
406 | - T1 = ldub((uint8_t *)A0); | |
407 | -} | |
408 | - | |
409 | -void OPPROTO op_ldsb_T1_A0(void) | |
410 | -{ | |
411 | - T1 = ldsb((int8_t *)A0); | |
412 | -} | |
413 | - | |
414 | -void OPPROTO op_lduw_T1_A0(void) | |
415 | -{ | |
416 | - T1 = lduw((uint8_t *)A0); | |
417 | -} | |
382 | +#define MEMSUFFIX _user | |
383 | +#include "ops_mem.h" | |
418 | 384 | |
419 | -void OPPROTO op_ldsw_T1_A0(void) | |
420 | -{ | |
421 | - T1 = ldsw((int8_t *)A0); | |
422 | -} | |
423 | - | |
424 | -void OPPROTO op_ldl_T1_A0(void) | |
425 | -{ | |
426 | - T1 = ldl((uint8_t *)A0); | |
427 | -} | |
428 | - | |
429 | -void OPPROTO op_stb_T0_A0(void) | |
430 | -{ | |
431 | - stb((uint8_t *)A0, T0); | |
432 | -} | |
433 | - | |
434 | -void OPPROTO op_stw_T0_A0(void) | |
435 | -{ | |
436 | - stw((uint8_t *)A0, T0); | |
437 | -} | |
438 | - | |
439 | -void OPPROTO op_stl_T0_A0(void) | |
440 | -{ | |
441 | - stl((uint8_t *)A0, T0); | |
442 | -} | |
385 | +#define MEMSUFFIX _kernel | |
386 | +#include "ops_mem.h" | |
443 | 387 | |
444 | 388 | /* used for bit operations */ |
445 | 389 | |
... | ... | @@ -635,6 +579,38 @@ void OPPROTO op_movswl_DX_AX(void) |
635 | 579 | EDX = (EDX & 0xffff0000) | (((int16_t)EAX >> 15) & 0xffff); |
636 | 580 | } |
637 | 581 | |
582 | +/* string ops helpers */ | |
583 | + | |
584 | +void OPPROTO op_addl_ESI_T0(void) | |
585 | +{ | |
586 | + ESI += T0; | |
587 | +} | |
588 | + | |
589 | +void OPPROTO op_addw_ESI_T0(void) | |
590 | +{ | |
591 | + ESI = (ESI & ~0xffff) | ((ESI + T0) & 0xffff); | |
592 | +} | |
593 | + | |
594 | +void OPPROTO op_addl_EDI_T0(void) | |
595 | +{ | |
596 | + EDI += T0; | |
597 | +} | |
598 | + | |
599 | +void OPPROTO op_addw_EDI_T0(void) | |
600 | +{ | |
601 | + EDI = (EDI & ~0xffff) | ((EDI + T0) & 0xffff); | |
602 | +} | |
603 | + | |
604 | +void OPPROTO op_decl_ECX(void) | |
605 | +{ | |
606 | + ECX--; | |
607 | +} | |
608 | + | |
609 | +void OPPROTO op_decw_ECX(void) | |
610 | +{ | |
611 | + ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff); | |
612 | +} | |
613 | + | |
638 | 614 | /* push/pop */ |
639 | 615 | |
640 | 616 | void op_pushl_T0(void) | ... | ... |
op_string.h
1 | 1 | |
2 | -void OPPROTO glue(glue(op_movs, SUFFIX), STRING_SUFFIX)(void) | |
3 | -{ | |
4 | - int v, inc; | |
5 | - v = glue(ldu, SUFFIX)(SI_ADDR); | |
6 | - glue(st, SUFFIX)(DI_ADDR, v); | |
7 | - inc = (DF << SHIFT); | |
8 | - INC_SI(); | |
9 | - INC_DI(); | |
10 | -} | |
11 | - | |
12 | -void OPPROTO glue(glue(op_rep_movs, SUFFIX), STRING_SUFFIX)(void) | |
13 | -{ | |
14 | - int v, inc; | |
15 | - inc = (DF << SHIFT); | |
16 | - while (CX != 0) { | |
17 | - v = glue(ldu, SUFFIX)(SI_ADDR); | |
18 | - glue(st, SUFFIX)(DI_ADDR, v); | |
19 | - INC_SI(); | |
20 | - INC_DI(); | |
21 | - DEC_CX(); | |
22 | - } | |
23 | - FORCE_RET(); | |
24 | -} | |
25 | - | |
26 | -void OPPROTO glue(glue(op_stos, SUFFIX), STRING_SUFFIX)(void) | |
27 | -{ | |
28 | - int inc; | |
29 | - glue(st, SUFFIX)(DI_ADDR, EAX); | |
30 | - inc = (DF << SHIFT); | |
31 | - INC_DI(); | |
32 | -} | |
33 | - | |
34 | -void OPPROTO glue(glue(op_rep_stos, SUFFIX), STRING_SUFFIX)(void) | |
35 | -{ | |
36 | - int inc; | |
37 | - inc = (DF << SHIFT); | |
38 | - while (CX != 0) { | |
39 | - glue(st, SUFFIX)(DI_ADDR, EAX); | |
40 | - INC_DI(); | |
41 | - DEC_CX(); | |
42 | - } | |
43 | - FORCE_RET(); | |
44 | -} | |
45 | - | |
46 | -void OPPROTO glue(glue(op_lods, SUFFIX), STRING_SUFFIX)(void) | |
47 | -{ | |
48 | - int v, inc; | |
49 | - v = glue(ldu, SUFFIX)(SI_ADDR); | |
50 | -#if SHIFT == 0 | |
51 | - EAX = (EAX & ~0xff) | v; | |
52 | -#elif SHIFT == 1 | |
53 | - EAX = (EAX & ~0xffff) | v; | |
54 | -#else | |
55 | - EAX = v; | |
56 | -#endif | |
57 | - inc = (DF << SHIFT); | |
58 | - INC_SI(); | |
59 | -} | |
60 | - | |
61 | -/* don't know if it is used */ | |
62 | -void OPPROTO glue(glue(op_rep_lods, SUFFIX), STRING_SUFFIX)(void) | |
63 | -{ | |
64 | - int v, inc; | |
65 | - inc = (DF << SHIFT); | |
66 | - while (CX != 0) { | |
67 | - v = glue(ldu, SUFFIX)(SI_ADDR); | |
68 | -#if SHIFT == 0 | |
69 | - EAX = (EAX & ~0xff) | v; | |
70 | -#elif SHIFT == 1 | |
71 | - EAX = (EAX & ~0xffff) | v; | |
72 | -#else | |
73 | - EAX = v; | |
74 | -#endif | |
75 | - INC_SI(); | |
76 | - DEC_CX(); | |
77 | - } | |
78 | - FORCE_RET(); | |
79 | -} | |
80 | - | |
81 | -void OPPROTO glue(glue(op_scas, SUFFIX), STRING_SUFFIX)(void) | |
82 | -{ | |
83 | - int v, inc; | |
84 | - | |
85 | - v = glue(ldu, SUFFIX)(DI_ADDR); | |
86 | - inc = (DF << SHIFT); | |
87 | - INC_DI(); | |
88 | - CC_SRC = v; | |
89 | - CC_DST = EAX - v; | |
90 | -} | |
91 | - | |
92 | 2 | void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void) |
93 | 3 | { |
94 | 4 | int v1, v2, inc; |
... | ... | @@ -133,18 +43,6 @@ void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void) |
133 | 43 | FORCE_RET(); |
134 | 44 | } |
135 | 45 | |
136 | -void OPPROTO glue(glue(op_cmps, SUFFIX), STRING_SUFFIX)(void) | |
137 | -{ | |
138 | - int v1, v2, inc; | |
139 | - v1 = glue(ldu, SUFFIX)(SI_ADDR); | |
140 | - v2 = glue(ldu, SUFFIX)(DI_ADDR); | |
141 | - inc = (DF << SHIFT); | |
142 | - INC_SI(); | |
143 | - INC_DI(); | |
144 | - CC_SRC = v2; | |
145 | - CC_DST = v1 - v2; | |
146 | -} | |
147 | - | |
148 | 46 | void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void) |
149 | 47 | { |
150 | 48 | int v1, v2, inc; |
... | ... | @@ -187,54 +85,6 @@ void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void) |
187 | 85 | FORCE_RET(); |
188 | 86 | } |
189 | 87 | |
190 | -void OPPROTO glue(glue(op_outs, SUFFIX), STRING_SUFFIX)(void) | |
191 | -{ | |
192 | - int v, dx, inc; | |
193 | - dx = EDX & 0xffff; | |
194 | - v = glue(ldu, SUFFIX)(SI_ADDR); | |
195 | - glue(cpu_x86_out, SUFFIX)(env, dx, v); | |
196 | - inc = (DF << SHIFT); | |
197 | - INC_SI(); | |
198 | -} | |
199 | - | |
200 | -void OPPROTO glue(glue(op_rep_outs, SUFFIX), STRING_SUFFIX)(void) | |
201 | -{ | |
202 | - int v, dx, inc; | |
203 | - inc = (DF << SHIFT); | |
204 | - dx = EDX & 0xffff; | |
205 | - while (CX != 0) { | |
206 | - v = glue(ldu, SUFFIX)(SI_ADDR); | |
207 | - glue(cpu_x86_out, SUFFIX)(env, dx, v); | |
208 | - INC_SI(); | |
209 | - DEC_CX(); | |
210 | - } | |
211 | - FORCE_RET(); | |
212 | -} | |
213 | - | |
214 | -void OPPROTO glue(glue(op_ins, SUFFIX), STRING_SUFFIX)(void) | |
215 | -{ | |
216 | - int v, dx, inc; | |
217 | - dx = EDX & 0xffff; | |
218 | - v = glue(cpu_x86_in, SUFFIX)(env, dx); | |
219 | - glue(st, SUFFIX)(DI_ADDR, v); | |
220 | - inc = (DF << SHIFT); | |
221 | - INC_DI(); | |
222 | -} | |
223 | - | |
224 | -void OPPROTO glue(glue(op_rep_ins, SUFFIX), STRING_SUFFIX)(void) | |
225 | -{ | |
226 | - int v, dx, inc; | |
227 | - inc = (DF << SHIFT); | |
228 | - dx = EDX & 0xffff; | |
229 | - while (CX != 0) { | |
230 | - v = glue(cpu_x86_in, SUFFIX)(env, dx); | |
231 | - glue(st, SUFFIX)(DI_ADDR, v); | |
232 | - INC_DI(); | |
233 | - DEC_CX(); | |
234 | - } | |
235 | - FORCE_RET(); | |
236 | -} | |
237 | - | |
238 | 88 | #undef STRING_SUFFIX |
239 | 89 | #undef SI_ADDR |
240 | 90 | #undef DI_ADDR | ... | ... |
ops_template.h
... | ... | @@ -547,6 +547,31 @@ void OPPROTO op_update_bt_cc(void) |
547 | 547 | #define DEC_CX() ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff) |
548 | 548 | #include "op_string.h" |
549 | 549 | |
550 | +void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void) | |
551 | +{ | |
552 | + T0 = DF << SHIFT; | |
553 | +} | |
554 | + | |
555 | +void OPPROTO glue(op_string_jz_sub, SUFFIX)(void) | |
556 | +{ | |
557 | + if ((DATA_TYPE)CC_DST == 0) | |
558 | + JUMP_TB(PARAM1, 1, PARAM2); | |
559 | +} | |
560 | + | |
561 | +void OPPROTO glue(op_string_jnz_sub, SUFFIX)(void) | |
562 | +{ | |
563 | + if ((DATA_TYPE)CC_DST != 0) | |
564 | + JUMP_TB(PARAM1, 1, PARAM2); | |
565 | +} | |
566 | + | |
567 | +#if DATA_BITS >= 16 | |
568 | +void OPPROTO glue(op_jz_ecx, SUFFIX)(void) | |
569 | +{ | |
570 | + if ((DATA_TYPE)ECX == 0) | |
571 | + JUMP_TB(PARAM1, 1, PARAM2); | |
572 | +} | |
573 | +#endif | |
574 | + | |
550 | 575 | /* port I/O */ |
551 | 576 | |
552 | 577 | void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) |
... | ... | @@ -559,6 +584,16 @@ void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void) |
559 | 584 | T1 = glue(cpu_x86_in, SUFFIX)(env, T0 & 0xffff); |
560 | 585 | } |
561 | 586 | |
587 | +void OPPROTO glue(glue(op_in, SUFFIX), _DX_T0)(void) | |
588 | +{ | |
589 | + T0 = glue(cpu_x86_in, SUFFIX)(env, EDX & 0xffff); | |
590 | +} | |
591 | + | |
592 | +void OPPROTO glue(glue(op_out, SUFFIX), _DX_T0)(void) | |
593 | +{ | |
594 | + glue(cpu_x86_out, SUFFIX)(env, EDX & 0xffff, T0); | |
595 | +} | |
596 | + | |
562 | 597 | #undef DATA_BITS |
563 | 598 | #undef SHIFT_MASK |
564 | 599 | #undef SIGN_MASK | ... | ... |