diff options
-rw-r--r-- | MAINTAINERS | 6 | ||||
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | hw/elf_ops.h | 11 | ||||
-rw-r--r-- | hw/lan9118.c | 2 | ||||
-rw-r--r-- | hw/mcf5206.c | 12 | ||||
-rw-r--r-- | hw/musicpal.c | 4 | ||||
-rw-r--r-- | hw/pl110.c | 30 | ||||
-rw-r--r-- | hw/pl110_template.h | 22 | ||||
-rw-r--r-- | hw/wm8750.c | 4 | ||||
-rwxr-xr-x | scripts/checkpatch.pl | 68 | ||||
-rw-r--r-- | target-arm/helper.c | 4 | ||||
-rw-r--r-- | target-cris/translate.c | 2 | ||||
-rw-r--r-- | target-mips/cpu.h | 49 | ||||
-rw-r--r-- | target-mips/op_helper.c | 49 | ||||
-rw-r--r-- | target-mips/translate.c | 16 | ||||
-rw-r--r-- | target-s390x/Makefile.objs | 5 | ||||
-rw-r--r-- | target-s390x/cc_helper.c | 550 | ||||
-rw-r--r-- | target-s390x/cpu.h | 9 | ||||
-rw-r--r-- | target-s390x/fpu_helper.c | 843 | ||||
-rw-r--r-- | target-s390x/helper.c | 102 | ||||
-rw-r--r-- | target-s390x/helper.h | 250 | ||||
-rw-r--r-- | target-s390x/int_helper.c | 201 | ||||
-rw-r--r-- | target-s390x/mem_helper.c | 1203 | ||||
-rw-r--r-- | target-s390x/misc_helper.c | 430 | ||||
-rw-r--r-- | target-s390x/op_helper.c | 3019 | ||||
-rw-r--r-- | target-s390x/translate.c | 233 | ||||
-rw-r--r-- | target-sparc/fop_helper.c | 67 | ||||
-rw-r--r-- | target-xtensa/xtensa-semi.c | 112 | ||||
-rw-r--r-- | tcg/s390/tcg-target.c | 14 |
29 files changed, 3822 insertions, 3497 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 6d864c1..61f8b45 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -398,6 +398,12 @@ M: Blue Swirl <blauwirbel@gmail.com> S: Maintained F: hw/sun4u.c +Leon3 +M: Fabien Chouteau <chouteau@adacore.com> +S: Maintained +F: hw/leon3.c +F: hw/grlib* + S390 Machines ------------- S390 Virtio @@ -3829,7 +3829,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile" case "$target_arch2" in - alpha | i386 | or32 | sparc* | x86_64 | xtensa* | ppc*) + alpha | i386 | or32 | s390x | sparc* | x86_64 | xtensa* | ppc*) echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak ;; esac diff --git a/hw/elf_ops.h b/hw/elf_ops.h index fa65ce2..731a983 100644 --- a/hw/elf_ops.h +++ b/hw/elf_ops.h @@ -269,6 +269,17 @@ static int glue(load_elf, SZ)(const char *name, int fd, addr = ph->p_paddr; } + /* the entry pointer in the ELF header is a virtual + * address, if the text segments paddr and vaddr differ + * we need to adjust the entry */ + if (pentry && !translate_fn && + ph->p_vaddr != ph->p_paddr && + ehdr.e_entry >= ph->p_vaddr && + ehdr.e_entry < ph->p_vaddr + ph->p_filesz && + ph->p_flags & PF_X) { + *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr; + } + snprintf(label, sizeof(label), "phdr #%d: %s", i, name); rom_add_blob_fixed(label, data, mem_size, addr); diff --git a/hw/lan9118.c b/hw/lan9118.c index ff0a50b..ceaf96f 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -500,7 +500,7 @@ static int lan9118_filter(lan9118_state *s, const uint8_t *addr) } } else { /* Hash matching */ - hash = (crc32(~0, addr, 6) >> 26); + hash = compute_mcast_idx(addr); if (hash & 0x20) { return (s->mac_hashh >> (hash & 0x1f)) & 1; } else { diff --git a/hw/mcf5206.c b/hw/mcf5206.c index 539b391..27753e2 100644 --- a/hw/mcf5206.c +++ b/hw/mcf5206.c @@ -378,7 +378,7 @@ static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset) { m5206_mbar_state *s = (m5206_mbar_state *)opaque; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR read offset 0x%x", (int)offset); } if (m5206_mbar_width[offset >> 2] > 1) { @@ -397,7 +397,7 @@ static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset) m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR read offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; @@ -421,7 +421,7 @@ static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset) m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR read offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; @@ -445,7 +445,7 @@ static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset, m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR write offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; @@ -469,7 +469,7 @@ static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset, m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR write offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; @@ -497,7 +497,7 @@ static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset, m5206_mbar_state *s = (m5206_mbar_state *)opaque; int width; offset &= 0x3ff; - if (offset > 0x200) { + if (offset >= 0x200) { hw_error("Bad MBAR write offset 0x%x", (int)offset); } width = m5206_mbar_width[offset >> 2]; diff --git a/hw/musicpal.c b/hw/musicpal.c index ad725b5..f305e21 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -1583,7 +1583,7 @@ static void musicpal_init(ram_addr_t ram_size, * image is smaller than 32 MB. */ #ifdef TARGET_WORDS_BIGENDIAN - pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL, + pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, "musicpal.flash", flash_size, dinfo->bdrv, 0x10000, (flash_size + 0xffff) >> 16, @@ -1591,7 +1591,7 @@ static void musicpal_init(ram_addr_t ram_size, 2, 0x00BF, 0x236D, 0x0000, 0x0000, 0x5555, 0x2AAA, 1); #else - pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL, + pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, "musicpal.flash", flash_size, dinfo->bdrv, 0x10000, (flash_size + 0xffff) >> 16, @@ -55,8 +55,8 @@ typedef struct { enum pl110_bppmode bpp; int invalidate; uint32_t mux_ctrl; - uint32_t pallette[256]; - uint32_t raw_pallette[128]; + uint32_t palette[256]; + uint32_t raw_palette[128]; qemu_irq irq; } pl110_state; @@ -79,8 +79,8 @@ static const VMStateDescription vmstate_pl110 = { VMSTATE_INT32(rows, pl110_state), VMSTATE_UINT32(bpp, pl110_state), VMSTATE_INT32(invalidate, pl110_state), - VMSTATE_UINT32_ARRAY(pallette, pl110_state, 256), - VMSTATE_UINT32_ARRAY(raw_pallette, pl110_state, 128), + VMSTATE_UINT32_ARRAY(palette, pl110_state, 256), + VMSTATE_UINT32_ARRAY(raw_palette, pl110_state, 128), VMSTATE_UINT32_V(mux_ctrl, pl110_state, 2), VMSTATE_END_OF_LIST() } @@ -236,7 +236,7 @@ static void pl110_update_display(void *opaque) s->upbase, s->cols, s->rows, src_width, dest_width, 0, s->invalidate, - fn, s->pallette, + fn, s->palette, &first, &last); if (first >= 0) { dpy_update(s->ds, 0, first, s->cols, last - first + 1); @@ -253,13 +253,13 @@ static void pl110_invalidate_display(void * opaque) } } -static void pl110_update_pallette(pl110_state *s, int n) +static void pl110_update_palette(pl110_state *s, int n) { int i; uint32_t raw; unsigned int r, g, b; - raw = s->raw_pallette[n]; + raw = s->raw_palette[n]; n <<= 1; for (i = 0; i < 2; i++) { r = (raw & 0x1f) << 3; @@ -271,17 +271,17 @@ static void pl110_update_pallette(pl110_state *s, int n) raw >>= 6; switch (ds_get_bits_per_pixel(s->ds)) { case 8: - s->pallette[n] = rgb_to_pixel8(r, g, b); + s->palette[n] = rgb_to_pixel8(r, g, b); break; case 15: - s->pallette[n] = rgb_to_pixel15(r, g, b); + s->palette[n] = rgb_to_pixel15(r, g, b); break; case 16: - s->pallette[n] = rgb_to_pixel16(r, g, b); + s->palette[n] = rgb_to_pixel16(r, g, b); break; case 24: case 32: - s->pallette[n] = rgb_to_pixel32(r, g, b); + s->palette[n] = rgb_to_pixel32(r, g, b); break; } n++; @@ -314,7 +314,7 @@ static uint64_t pl110_read(void *opaque, target_phys_addr_t offset, return idregs[s->version][(offset - 0xfe0) >> 2]; } if (offset >= 0x200 && offset < 0x400) { - return s->raw_pallette[(offset - 0x200) >> 2]; + return s->raw_palette[(offset - 0x200) >> 2]; } switch (offset >> 2) { case 0: /* LCDTiming0 */ @@ -364,10 +364,10 @@ static void pl110_write(void *opaque, target_phys_addr_t offset, is written to. */ s->invalidate = 1; if (offset >= 0x200 && offset < 0x400) { - /* Pallette. */ + /* Palette. */ n = (offset - 0x200) >> 2; - s->raw_pallette[(offset - 0x200) >> 2] = val; - pl110_update_pallette(s, n); + s->raw_palette[(offset - 0x200) >> 2] = val; + pl110_update_palette(s, n); return; } switch (offset >> 2) { diff --git a/hw/pl110_template.h b/hw/pl110_template.h index 1dce32a..e738e4a 100644 --- a/hw/pl110_template.h +++ b/hw/pl110_template.h @@ -129,14 +129,14 @@ static drawfn glue(pl110_draw_fn_,BITS)[48] = static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { - uint32_t *pallette = opaque; + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; #ifdef SWAP_PIXELS -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 7 - (x))) & 1]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 7 - (x))) & 1]); #else -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x) + y)) & 1]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x) + y)) & 1]); #endif #ifdef SWAP_WORDS FN_8(24) @@ -157,14 +157,14 @@ static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { - uint32_t *pallette = opaque; + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; #ifdef SWAP_PIXELS -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 6 - (x)*2)) & 3]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 6 - (x)*2)) & 3]); #else -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*2 + y)) & 3]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x)*2 + y)) & 3]); #endif #ifdef SWAP_WORDS FN_4(0, 24) @@ -185,14 +185,14 @@ static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { - uint32_t *pallette = opaque; + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; #ifdef SWAP_PIXELS -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 4 - (x)*4)) & 0xf]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 4 - (x)*4)) & 0xf]); #else -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*4 + y)) & 0xf]); +#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x)*4 + y)) & 0xf]); #endif #ifdef SWAP_WORDS FN_2(0, 24) @@ -213,11 +213,11 @@ static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t static void glue(pl110_draw_line8_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep) { - uint32_t *pallette = opaque; + uint32_t *palette = opaque; uint32_t data; while (width > 0) { data = *(uint32_t *)src; -#define FN(x) COPY_PIXEL(d, pallette[(data >> (x)) & 0xff]); +#define FN(x) COPY_PIXEL(d, palette[(data >> (x)) & 0xff]); #ifdef SWAP_WORDS FN(24) FN(16) diff --git a/hw/wm8750.c b/hw/wm8750.c index 11bcec3..44f138f 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -361,10 +361,10 @@ static int wm8750_tx(I2CSlave *i2c, uint8_t data) uint16_t value; if (s->i2c_len >= 2) { - printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len); #ifdef VERBOSE - return 1; + printf("%s: long message (%i bytes)\n", __func__, s->i2c_len); #endif + return 1; } s->i2c_data[s->i2c_len ++] = data; if (s->i2c_len != 2) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index b98dc6c..ec0aa4c 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -97,6 +97,9 @@ my $dbg_values = 0; my $dbg_possible = 0; my $dbg_type = 0; my $dbg_attr = 0; +my $dbg_adv_dcs = 0; +my $dbg_adv_checking = 0; +my $dbg_adv_apw = 0; for my $key (keys %debug) { ## no critic eval "\${dbg_$key} = '$debug{$key}';"; @@ -2486,8 +2489,11 @@ sub process { if ($line =~ /(^.*)\bif\b/ && $line !~ /\#\s*if/) { my ($level, $endln, @chunks) = ctx_statement_full($linenr, $realcnt, 1); - #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; - #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n"; + if ($dbg_adv_apw) { + print "APW: chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; + print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n" + if $#chunks >= 1; + } if ($#chunks >= 0 && $level == 0) { my $allowed = 0; my $seen = 0; @@ -2512,18 +2518,22 @@ sub process { $seen++ if ($block =~ /^\s*{/); - #print "cond<$cond> block<$block> allowed<$allowed>\n"; + print "APW: cond<$cond> block<$block> allowed<$allowed>\n" + if $dbg_adv_apw; if (statement_lines($cond) > 1) { - #print "APW: ALLOWED: cond<$cond>\n"; - $allowed = 1; + print "APW: ALLOWED: cond<$cond>\n" + if $dbg_adv_apw; + $allowed = 1; } if ($block =~/\b(?:if|for|while)\b/) { - #print "APW: ALLOWED: block<$block>\n"; - $allowed = 1; + print "APW: ALLOWED: block<$block>\n" + if $dbg_adv_apw; + $allowed = 1; } if (statement_block_size($block) > 1) { - #print "APW: ALLOWED: lines block<$block>\n"; - $allowed = 1; + print "APW: ALLOWED: lines block<$block>\n" + if $dbg_adv_apw; + $allowed = 1; } } if ($seen != ($#chunks + 1)) { @@ -2537,32 +2547,41 @@ sub process { $line !~ /\#\s*else/) { my $allowed = 0; - # Check the pre-context. - if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) { - #print "APW: ALLOWED: pre<$1>\n"; - $allowed = 1; - } + # Check the pre-context. + if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) { + my $pre = $1; + + if ($line !~ /else/) { + print "APW: ALLOWED: pre<$pre> line<$line>\n" + if $dbg_adv_apw; + $allowed = 1; + } + } my ($level, $endln, @chunks) = ctx_statement_full($linenr, $realcnt, $-[0]); # Check the condition. my ($cond, $block) = @{$chunks[0]}; - #print "CHECKING<$linenr> cond<$cond> block<$block>\n"; + print "CHECKING<$linenr> cond<$cond> block<$block>\n" + if $dbg_adv_checking; if (defined $cond) { substr($block, 0, length($cond), ''); } if (statement_lines($cond) > 1) { - #print "APW: ALLOWED: cond<$cond>\n"; - $allowed = 1; + print "APW: ALLOWED: cond<$cond>\n" + if $dbg_adv_apw; + $allowed = 1; } if ($block =~/\b(?:if|for|while)\b/) { - #print "APW: ALLOWED: block<$block>\n"; - $allowed = 1; + print "APW: ALLOWED: block<$block>\n" + if $dbg_adv_apw; + $allowed = 1; } if (statement_block_size($block) > 1) { - #print "APW: ALLOWED: lines block<$block>\n"; - $allowed = 1; + print "APW: ALLOWED: lines block<$block>\n" + if $dbg_adv_apw; + $allowed = 1; } # Check the post-context. if (defined $chunks[1]) { @@ -2571,10 +2590,13 @@ sub process { substr($block, 0, length($cond), ''); } if ($block =~ /^\s*\{/) { - #print "APW: ALLOWED: chunk-1 block<$block>\n"; - $allowed = 1; + print "APW: ALLOWED: chunk-1 block<$block>\n" + if $dbg_adv_apw; + $allowed = 1; } } + print "DCS: level=$level block<$block> allowed=$allowed\n" + if $dbg_adv_dcs; if ($level == 0 && $block !~ /^\s*\{/ && !$allowed) { my $herectx = $here . "\n";; my $cnt = statement_rawlines($block); diff --git a/target-arm/helper.c b/target-arm/helper.c index dceaa95..e27df96 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -645,7 +645,7 @@ static int pmsav5_insn_ap_read(CPUARMState *env, const ARMCPRegInfo *ri, static int arm946_prbs_read(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value) { - if (ri->crm > 8) { + if (ri->crm >= 8) { return EXCP_UDEF; } *value = env->cp15.c6_region[ri->crm]; @@ -655,7 +655,7 @@ static int arm946_prbs_read(CPUARMState *env, const ARMCPRegInfo *ri, static int arm946_prbs_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { - if (ri->crm > 8) { + if (ri->crm >= 8) { return EXCP_UDEF; } env->cp15.c6_region[ri->crm] = value; diff --git a/target-cris/translate.c b/target-cris/translate.c index 1ad9ec7..ad31877 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3458,7 +3458,7 @@ void cpu_dump_state (CPUCRISState *env, FILE *f, fprintf_function cpu_fprintf, } srs = env->pregs[PR_SRS]; cpu_fprintf(f, "\nsupport function regs bank %x:\n", srs); - if (srs < 256) { + if (srs < ARRAY_SIZE(env->sregs)) { for (i = 0; i < 16; i++) { cpu_fprintf(f, "s%2.2d=%8.8x ", i, env->sregs[srs][i]); diff --git a/target-mips/cpu.h b/target-mips/cpu.h index ce3467f..88d92f1 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -742,4 +742,53 @@ static inline void cpu_pc_from_tb(CPUMIPSState *env, TranslationBlock *tb) env->hflags |= tb->flags & MIPS_HFLAG_BMASK; } +static inline void compute_hflags(CPUMIPSState *env) +{ + env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | + MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | + MIPS_HFLAG_UX); + if (!(env->CP0_Status & (1 << CP0St_EXL)) && + !(env->CP0_Status & (1 << CP0St_ERL)) && + !(env->hflags & MIPS_HFLAG_DM)) { + env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; + } +#if defined(TARGET_MIPS64) + if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || + (env->CP0_Status & (1 << CP0St_PX)) || + (env->CP0_Status & (1 << CP0St_UX))) { + env->hflags |= MIPS_HFLAG_64; + } + if (env->CP0_Status & (1 << CP0St_UX)) { + env->hflags |= MIPS_HFLAG_UX; + } +#endif + if ((env->CP0_Status & (1 << CP0St_CU0)) || + !(env->hflags & MIPS_HFLAG_KSU)) { + env->hflags |= MIPS_HFLAG_CP0; + } + if (env->CP0_Status & (1 << CP0St_CU1)) { + env->hflags |= MIPS_HFLAG_FPU; + } + if (env->CP0_Status & (1 << CP0St_FR)) { + env->hflags |= MIPS_HFLAG_F64; + } + if (env->insn_flags & ISA_MIPS32R2) { + if (env->active_fpu.fcr0 & (1 << FCR0_F64)) { + env->hflags |= MIPS_HFLAG_COP1X; + } + } else if (env->insn_flags & ISA_MIPS32) { + if (env->hflags & MIPS_HFLAG_64) { + env->hflags |= MIPS_HFLAG_COP1X; + } + } else if (env->insn_flags & ISA_MIPS4) { + /* All supported MIPS IV CPUs use the XX (CU3) to enable + and disable the MIPS IV extensions to the MIPS III ISA. + Some other MIPS IV CPUs ignore the bit, so the check here + would be too restrictive for them. */ + if (env->CP0_Status & (1 << CP0St_CU3)) { + env->hflags |= MIPS_HFLAG_COP1X; + } + } +} + #endif /* !defined (__MIPS_CPU_H__) */ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index e5bc93e..3d242aa 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -32,55 +32,6 @@ static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global); #endif -static inline void compute_hflags(CPUMIPSState *env) -{ - env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | - MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | - MIPS_HFLAG_UX); - if (!(env->CP0_Status & (1 << CP0St_EXL)) && - !(env->CP0_Status & (1 << CP0St_ERL)) && - !(env->hflags & MIPS_HFLAG_DM)) { - env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; - } -#if defined(TARGET_MIPS64) - if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || - (env->CP0_Status & (1 << CP0St_PX)) || - (env->CP0_Status & (1 << CP0St_UX))) { - env->hflags |= MIPS_HFLAG_64; - } - if (env->CP0_Status & (1 << CP0St_UX)) { - env->hflags |= MIPS_HFLAG_UX; - } -#endif - if ((env->CP0_Status & (1 << CP0St_CU0)) || - !(env->hflags & MIPS_HFLAG_KSU)) { - env->hflags |= MIPS_HFLAG_CP0; - } - if (env->CP0_Status & (1 << CP0St_CU1)) { - env->hflags |= MIPS_HFLAG_FPU; - } - if (env->CP0_Status & (1 << CP0St_FR)) { - env->hflags |= MIPS_HFLAG_F64; - } - if (env->insn_flags & ISA_MIPS32R2) { - if (env->active_fpu.fcr0 & (1 << FCR0_F64)) { - env->hflags |= MIPS_HFLAG_COP1X; - } - } else if (env->insn_flags & ISA_MIPS32) { - if (env->hflags & MIPS_HFLAG_64) { - env->hflags |= MIPS_HFLAG_COP1X; - } - } else if (env->insn_flags & ISA_MIPS4) { - /* All supported MIPS IV CPUs use the XX (CU3) to enable - and disable the MIPS IV extensions to the MIPS III ISA. - Some other MIPS IV CPUs ignore the bit, so the check here - would be too restrictive for them. */ - if (env->CP0_Status & (1 << CP0St_CU3)) { - env->hflags |= MIPS_HFLAG_COP1X; - } - } -} - /*****************************************************************************/ /* Exceptions processing helpers */ diff --git a/target-mips/translate.c b/target-mips/translate.c index b293419..a884f75 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -12787,18 +12787,13 @@ void cpu_state_reset(CPUMIPSState *env) env->insn_flags = env->cpu_model->insn_flags; #if defined(CONFIG_USER_ONLY) - env->hflags = MIPS_HFLAG_UM; + env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU); /* Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR hardware registers. */ env->CP0_HWREna |= 0x0000000F; if (env->CP0_Config1 & (1 << CP0C1_FP)) { - env->hflags |= MIPS_HFLAG_FPU; + env->CP0_Status |= (1 << CP0St_CU1); } -#ifdef TARGET_MIPS64 - if (env->active_fpu.fcr0 & (1 << FCR0_F64)) { - env->hflags |= MIPS_HFLAG_F64; - } -#endif #else if (env->hflags & MIPS_HFLAG_BMASK) { /* If the exception was raised from a delay slot, @@ -12828,7 +12823,6 @@ void cpu_state_reset(CPUMIPSState *env) } /* Count register increments in debug mode, EJTAG version 1 */ env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); - env->hflags = MIPS_HFLAG_CP0; if (env->CP0_Config3 & (1 << CP0C3_MT)) { int i; @@ -12856,11 +12850,7 @@ void cpu_state_reset(CPUMIPSState *env) } } #endif -#if defined(TARGET_MIPS64) - if (env->cpu_model->insn_flags & ISA_MIPS3) { - env->hflags |= MIPS_HFLAG_64; - } -#endif + compute_hflags(env); env->exception_index = EXCP_NONE; } diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs index 80be3bb..e728abf 100644 --- a/target-s390x/Makefile.objs +++ b/target-s390x/Makefile.objs @@ -1,5 +1,4 @@ -obj-y += translate.o op_helper.o helper.o cpu.o interrupt.o +obj-y += translate.o helper.o cpu.o interrupt.o +obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o obj-$(CONFIG_SOFTMMU) += machine.o obj-$(CONFIG_KVM) += kvm.o - -$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c new file mode 100644 index 0000000..19ef145 --- /dev/null +++ b/target-s390x/cc_helper.c @@ -0,0 +1,550 @@ +/* + * S/390 condition code helper routines + * + * Copyright (c) 2009 Ulrich Hecht + * Copyright (c) 2009 Alexander Graf + * + * 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 "cpu.h" +#include "helper.h" + +/* #define DEBUG_HELPER */ +#ifdef DEBUG_HELPER +#define HELPER_LOG(x...) qemu_log(x) +#else +#define HELPER_LOG(x...) +#endif + +static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src, + int32_t dst) +{ + if (src == dst) { + return 0; + } else if (src < dst) { + return 1; + } else { + return 2; + } +} + +static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst) +{ + return cc_calc_ltgt_32(env, dst, 0); +} + +static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src, + int64_t dst) +{ + if (src == dst) { + return 0; + } else if (src < dst) { + return 1; + } else { + return 2; + } +} + +static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst) +{ + return cc_calc_ltgt_64(env, dst, 0); +} + +static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src, + uint32_t dst) +{ + if (src == dst) { + return 0; + } else if (src < dst) { + return 1; + } else { + return 2; + } +} + +static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, + uint64_t dst) +{ + if (src == dst) { + return 0; + } else if (src < dst) { + return 1; + } else { + return 2; + } +} + +static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, + uint32_t mask) +{ + uint16_t r = val & mask; + + HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask); + if (r == 0 || mask == 0) { + return 0; + } else if (r == mask) { + return 3; + } else { + return 1; + } +} + +/* set condition code for test under mask */ +static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, + uint32_t mask) +{ + uint16_t r = val & mask; + + HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r); + if (r == 0 || mask == 0) { + return 0; + } else if (r == mask) { + return 3; + } else { + while (!(mask & 0x8000)) { + mask <<= 1; + val <<= 1; + } + if (val & 0x8000) { + return 2; + } else { + return 1; + } + } +} + +static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst) +{ + return !!dst; +} + +static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, + int64_t a2, int64_t ar) +{ + if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { + return 3; /* overflow */ + } else { + if (ar < 0) { + return 1; + } else if (ar > 0) { + return 2; + } else { + return 0; + } + } +} + +static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, + uint64_t a2, uint64_t ar) +{ + if (ar == 0) { + if (a1) { + return 2; + } else { + return 0; + } + } else { + if (ar < a1 || ar < a2) { + return 3; + } else { + return 1; + } + } +} + +static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, + int64_t a2, int64_t ar) +{ + if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { + return 3; /* overflow */ + } else { + if (ar < 0) { + return 1; + } else if (ar > 0) { + return 2; + } else { + return 0; + } + } +} + +static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, + uint64_t a2, uint64_t ar) +{ + if (ar == 0) { + return 2; + } else { + if (a2 > a1) { + return 1; + } else { + return 3; + } + } +} + +static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) +{ + if ((uint64_t)dst == 0x8000000000000000ULL) { + return 3; + } else if (dst) { + return 1; + } else { + return 0; + } +} + +static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst) +{ + return !!dst; +} + +static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst) +{ + if ((uint64_t)dst == 0x8000000000000000ULL) { + return 3; + } else if (dst < 0) { + return 1; + } else if (dst > 0) { + return 2; + } else { + return 0; + } +} + + +static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, + int32_t a2, int32_t ar) +{ + if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { + return 3; /* overflow */ + } else { + if (ar < 0) { + return 1; + } else if (ar > 0) { + return 2; + } else { + return 0; + } + } +} + +static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, + uint32_t a2, uint32_t ar) +{ + if (ar == 0) { + if (a1) { + return 2; + } else { + return 0; + } + } else { + if (ar < a1 || ar < a2) { + return 3; + } else { + return 1; + } + } +} + +static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, + int32_t a2, int32_t ar) +{ + if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { + return 3; /* overflow */ + } else { + if (ar < 0) { + return 1; + } else if (ar > 0) { + return 2; + } else { + return 0; + } + } +} + +static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, + uint32_t a2, uint32_t ar) +{ + if (ar == 0) { + return 2; + } else { + if (a2 > a1) { + return 1; + } else { + return 3; + } + } +} + +static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) +{ + if ((uint32_t)dst == 0x80000000UL) { + return 3; + } else if (dst) { + return 1; + } else { + return 0; + } +} + +static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst) +{ + return !!dst; +} + +static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst) +{ + if ((uint32_t)dst == 0x80000000UL) { + return 3; + } else if (dst < 0) { + return 1; + } else if (dst > 0) { + return 2; + } else { + return 0; + } +} + +/* calculate condition code for insert character under mask insn */ +static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, + uint32_t val) +{ + uint32_t cc; + + HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val); + if (mask == 0xf) { + if (!val) { + return 0; + } else if (val & 0x80000000) { + return 1; + } else { + return 2; + } + } + + if (!val || !mask) { + cc = 0; + } else { + while (mask != 1) { + mask >>= 1; + val >>= 8; + } + if (val & 0x80) { + cc = 1; + } else { + cc = 2; + } + } + return cc; +} + +static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, + uint64_t shift) +{ + uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); + uint64_t match, r; + + /* check if the sign bit stays the same */ + if (src & (1ULL << 63)) { + match = mask; + } else { + match = 0; + } + + if ((src & mask) != match) { + /* overflow */ + return 3; + } + + r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63)); + + if ((int64_t)r == 0) { + return 0; + } else if ((int64_t)r < 0) { + return 1; + } + + return 2; +} + + +static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, + uint64_t src, uint64_t dst, uint64_t vr) +{ + uint32_t r = 0; + + switch (cc_op) { + case CC_OP_CONST0: + case CC_OP_CONST1: + case CC_OP_CONST2: + case CC_OP_CONST3: + /* cc_op value _is_ cc */ + r = cc_op; + break; + case CC_OP_LTGT0_32: + r = cc_calc_ltgt0_32(env, dst); + break; + case CC_OP_LTGT0_64: + r = cc_calc_ltgt0_64(env, dst); + break; + case CC_OP_LTGT_32: + r = cc_calc_ltgt_32(env, src, dst); + break; + case CC_OP_LTGT_64: + r = cc_calc_ltgt_64(env, src, dst); + break; + case CC_OP_LTUGTU_32: + r = cc_calc_ltugtu_32(env, src, dst); + break; + case CC_OP_LTUGTU_64: + r = cc_calc_ltugtu_64(env, src, dst); + break; + case CC_OP_TM_32: + r = cc_calc_tm_32(env, src, dst); + break; + case CC_OP_TM_64: + r = cc_calc_tm_64(env, src, dst); + break; + case CC_OP_NZ: + r = cc_calc_nz(env, dst); + break; + case CC_OP_ADD_64: + r = cc_calc_add_64(env, src, dst, vr); + break; + case CC_OP_ADDU_64: + r = cc_calc_addu_64(env, src, dst, vr); + break; + case CC_OP_SUB_64: + r = cc_calc_sub_64(env, src, dst, vr); + break; + case CC_OP_SUBU_64: + r = cc_calc_subu_64(env, src, dst, vr); + break; + case CC_OP_ABS_64: + r = cc_calc_abs_64(env, dst); + break; + case CC_OP_NABS_64: + r = cc_calc_nabs_64(env, dst); + break; + case CC_OP_COMP_64: + r = cc_calc_comp_64(env, dst); + break; + + case CC_OP_ADD_32: + r = cc_calc_add_32(env, src, dst, vr); + break; + case CC_OP_ADDU_32: + r = cc_calc_addu_32(env, src, dst, vr); + break; + case CC_OP_SUB_32: + r = cc_calc_sub_32(env, src, dst, vr); + break; + case CC_OP_SUBU_32: + r = cc_calc_subu_32(env, src, dst, vr); + break; + case CC_OP_ABS_32: + r = cc_calc_abs_64(env, dst); + break; + case CC_OP_NABS_32: + r = cc_calc_nabs_64(env, dst); + break; + case CC_OP_COMP_32: + r = cc_calc_comp_32(env, dst); + break; + + case CC_OP_ICM: + r = cc_calc_icm_32(env, src, dst); + break; + case CC_OP_SLAG: + r = cc_calc_slag(env, src, dst); + break; + + case CC_OP_LTGT_F32: + r = set_cc_f32(env, src, dst); + break; + case CC_OP_LTGT_F64: + r = set_cc_f64(env, src, dst); + break; + case CC_OP_NZ_F32: + r = set_cc_nz_f32(dst); + break; + case CC_OP_NZ_F64: + r = set_cc_nz_f64(dst); + break; + + default: + cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op)); + } + + HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__, + cc_name(cc_op), src, dst, vr, r); + return r; +} + +uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, + uint64_t vr) +{ + return do_calc_cc(env, cc_op, src, dst, vr); +} + +uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src, + uint64_t dst, uint64_t vr) +{ + return do_calc_cc(env, cc_op, src, dst, vr); +} + +/* insert psw mask and condition code into r1 */ +void HELPER(ipm)(CPUS390XState *env, uint32_t cc, uint32_t r1) +{ + uint64_t r = env->regs[r1]; + + r &= 0xffffffff00ffffffULL; + r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf); + env->regs[r1] = r; + HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__, + cc, env->psw.mask, r); +} + +#ifndef CONFIG_USER_ONLY +void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr) +{ + load_psw(env, mask, addr); + cpu_loop_exit(env); +} + +void HELPER(sacf)(CPUS390XState *env, uint64_t a1) +{ + HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1); + + switch (a1 & 0xf00) { + case 0x000: + env->psw.mask &= ~PSW_MASK_ASC; + env->psw.mask |= PSW_ASC_PRIMARY; + break; + case 0x100: + env->psw.mask &= ~PSW_MASK_ASC; + env->psw.mask |= PSW_ASC_SECONDARY; + break; + case 0x300: + env->psw.mask &= ~PSW_MASK_ASC; + env->psw.mask |= PSW_ASC_HOME; + break; + default: + qemu_log("unknown sacf mode: %" PRIx64 "\n", a1); + program_interrupt(env, PGM_SPECIFICATION, 2); + break; + } +} +#endif diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 18ac6e3..ed81af3 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -999,4 +999,13 @@ static inline void cpu_pc_from_tb(CPUS390XState *env, TranslationBlock* tb) env->psw.addr = tb->pc; } +/* fpu_helper.c */ +uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2); +uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2); +uint32_t set_cc_nz_f32(float32 v); +uint32_t set_cc_nz_f64(float64 v); + +/* misc_helper.c */ +void program_interrupt(CPUS390XState *env, uint32_t code, int ilc); + #endif diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c new file mode 100644 index 0000000..ee9420d --- /dev/null +++ b/target-s390x/fpu_helper.c @@ -0,0 +1,843 @@ +/* + * S/390 FPU helper routines + * + * Copyright (c) 2009 Ulrich Hecht + * Copyright (c) 2009 Alexander Graf + * + * 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 "cpu.h" +#include "helper.h" + +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#endif + +/* #define DEBUG_HELPER */ +#ifdef DEBUG_HELPER +#define HELPER_LOG(x...) qemu_log(x) +#else +#define HELPER_LOG(x...) +#endif + +static inline int float_comp_to_cc(CPUS390XState *env, int float_compare) +{ + switch (float_compare) { + case float_relation_equal: + return 0; + case float_relation_less: + return 1; + case float_relation_greater: + return 2; + case float_relation_unordered: + return 3; + default: + cpu_abort(env, "unknown return value for float compare\n"); + } +} + +/* condition codes for binary FP ops */ +uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2) +{ + return float_comp_to_cc(env, float32_compare_quiet(v1, v2, + &env->fpu_status)); +} + +uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2) +{ + return float_comp_to_cc(env, float64_compare_quiet(v1, v2, + &env->fpu_status)); +} + +/* condition codes for unary FP ops */ +uint32_t set_cc_nz_f32(float32 v) +{ + if (float32_is_any_nan(v)) { + return 3; + } else if (float32_is_zero(v)) { + return 0; + } else if (float32_is_neg(v)) { + return 1; + } else { + return 2; + } +} + +uint32_t set_cc_nz_f64(float64 v) +{ + if (float64_is_any_nan(v)) { + return 3; + } else if (float64_is_zero(v)) { + return 0; + } else if (float64_is_neg(v)) { + return 1; + } else { + return 2; + } +} + +static uint32_t set_cc_nz_f128(float128 v) +{ + if (float128_is_any_nan(v)) { + return 3; + } else if (float128_is_zero(v)) { + return 0; + } else if (float128_is_neg(v)) { + return 1; + } else { + return 2; + } +} + +/* convert 32-bit int to 64-bit float */ +void HELPER(cdfbr)(CPUS390XState *env, uint32_t f1, int32_t v2) +{ + HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1); + env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); +} + +/* convert 32-bit int to 128-bit float */ +void HELPER(cxfbr)(CPUS390XState *env, uint32_t f1, int32_t v2) +{ + CPU_QuadU v1; + + v1.q = int32_to_float128(v2, &env->fpu_status); + env->fregs[f1].ll = v1.ll.upper; + env->fregs[f1 + 2].ll = v1.ll.lower; +} + +/* convert 64-bit int to 32-bit float */ +void HELPER(cegbr)(CPUS390XState *env, uint32_t f1, int64_t v2) +{ + HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); + env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status); +} + +/* convert 64-bit int to 64-bit float */ +void HELPER(cdgbr)(CPUS390XState *env, uint32_t f1, int64_t v2) +{ + HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); + env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); +} + +/* convert 64-bit int to 128-bit float */ +void HELPER(cxgbr)(CPUS390XState *env, uint32_t f1, int64_t v2) +{ + CPU_QuadU x1; + + x1.q = int64_to_float128(v2, &env->fpu_status); + HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __func__, v2, + x1.ll.upper, x1.ll.lower); + env->fregs[f1].ll = x1.ll.upper; + env->fregs[f1 + 2].ll = x1.ll.lower; +} + +/* convert 32-bit int to 32-bit float */ +void HELPER(cefbr)(CPUS390XState *env, uint32_t f1, int32_t v2) +{ + env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); + HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2, + env->fregs[f1].l.upper, f1); +} + +/* 32-bit FP addition RR */ +uint32_t HELPER(aebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, + env->fregs[f2].l.upper, + &env->fpu_status); + HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, + env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); + + return set_cc_nz_f32(env->fregs[f1].l.upper); +} + +/* 64-bit FP addition RR */ +uint32_t HELPER(adbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, + &env->fpu_status); + HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __func__, + env->fregs[f2].d, env->fregs[f1].d, f1); + + return set_cc_nz_f64(env->fregs[f1].d); +} + +/* 32-bit FP subtraction RR */ +uint32_t HELPER(sebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper, + env->fregs[f2].l.upper, + &env->fpu_status); + HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, + env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); + + return set_cc_nz_f32(env->fregs[f1].l.upper); +} + +/* 64-bit FP subtraction RR */ +uint32_t HELPER(sdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, + &env->fpu_status); + HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", + __func__, env->fregs[f2].d, env->fregs[f1].d, f1); + + return set_cc_nz_f64(env->fregs[f1].d); +} + +/* 32-bit FP division RR */ +void HELPER(debr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper, + env->fregs[f2].l.upper, + &env->fpu_status); +} + +/* 128-bit FP division RR */ +void HELPER(dxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + CPU_QuadU v1; + CPU_QuadU v2; + CPU_QuadU res; + + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + res.q = float128_div(v1.q, v2.q, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; +} + +/* 64-bit FP multiplication RR */ +void HELPER(mdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, + &env->fpu_status); +} + +/* 128-bit FP multiplication RR */ +void HELPER(mxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + CPU_QuadU v1; + CPU_QuadU v2; + CPU_QuadU res; + + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + res.q = float128_mul(v1.q, v2.q, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; +} + +/* convert 32-bit float to 64-bit float */ +void HELPER(ldebr)(CPUS390XState *env, uint32_t r1, uint32_t r2) +{ + env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper, + &env->fpu_status); +} + +/* convert 128-bit float to 64-bit float */ +void HELPER(ldxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + CPU_QuadU x2; + + x2.ll.upper = env->fregs[f2].ll; + x2.ll.lower = env->fregs[f2 + 2].ll; + env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status); + HELPER_LOG("%s: to 0x%ld\n", __func__, env->fregs[f1].d); +} + +/* convert 64-bit float to 128-bit float */ +void HELPER(lxdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + CPU_QuadU res; + + res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; +} + +/* convert 64-bit float to 32-bit float */ +void HELPER(ledbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + float64 d2 = env->fregs[f2].d; + + env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status); +} + +/* convert 128-bit float to 32-bit float */ +void HELPER(lexbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + CPU_QuadU x2; + + x2.ll.upper = env->fregs[f2].ll; + x2.ll.lower = env->fregs[f2 + 2].ll; + env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status); + HELPER_LOG("%s: to 0x%d\n", __func__, env->fregs[f1].l.upper); +} + +/* absolute value of 32-bit float */ +uint32_t HELPER(lpebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + float32 v1; + float32 v2 = env->fregs[f2].d; + + v1 = float32_abs(v2); + env->fregs[f1].d = v1; + return set_cc_nz_f32(v1); +} + +/* absolute value of 64-bit float */ +uint32_t HELPER(lpdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + float64 v1; + float64 v2 = env->fregs[f2].d; + + v1 = float64_abs(v2); + env->fregs[f1].d = v1; + return set_cc_nz_f64(v1); +} + +/* absolute value of 128-bit float */ +uint32_t HELPER(lpxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + CPU_QuadU v1; + CPU_QuadU v2; + + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + v1.q = float128_abs(v2.q); + env->fregs[f1].ll = v1.ll.upper; + env->fregs[f1 + 2].ll = v1.ll.lower; + return set_cc_nz_f128(v1.q); +} + +/* load and test 64-bit float */ +uint32_t HELPER(ltdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = env->fregs[f2].d; + return set_cc_nz_f64(env->fregs[f1].d); +} + +/* load and test 32-bit float */ +uint32_t HELPER(ltebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + env->fregs[f1].l.upper = env->fregs[f2].l.upper; + return set_cc_nz_f32(env->fregs[f1].l.upper); +} + +/* load and test 128-bit float */ +uint32_t HELPER(ltxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + CPU_QuadU x; + + x.ll.upper = env->fregs[f2].ll; + x.ll.lower = env->fregs[f2 + 2].ll; + env->fregs[f1].ll = x.ll.upper; + env->fregs[f1 + 2].ll = x.ll.lower; + return set_cc_nz_f128(x.q); +} + +/* load complement of 32-bit float */ +uint32_t HELPER(lcebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper); + + return set_cc_nz_f32(env->fregs[f1].l.upper); +} + +/* load complement of 64-bit float */ +uint32_t HELPER(lcdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_chs(env->fregs[f2].d); + + return set_cc_nz_f64(env->fregs[f1].d); +} + +/* load complement of 128-bit float */ +uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + CPU_QuadU x1, x2; + + x2.ll.upper = env->fregs[f2].ll; + x2.ll.lower = env->fregs[f2 + 2].ll; + x1.q = float128_chs(x2.q); + env->fregs[f1].ll = x1.ll.upper; + env->fregs[f1 + 2].ll = x1.ll.lower; + return set_cc_nz_f128(x1.q); +} + +/* 32-bit FP addition RM */ +void HELPER(aeb)(CPUS390XState *env, uint32_t f1, uint32_t val) +{ + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; + + v2.l = val; + HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __func__, + v1, f1, v2.f); + env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status); +} + +/* 32-bit FP division RM */ +void HELPER(deb)(CPUS390XState *env, uint32_t f1, uint32_t val) +{ + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; + + v2.l = val; + HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __func__, + v1, f1, v2.f); + env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status); +} + +/* 32-bit FP multiplication RM */ +void HELPER(meeb)(CPUS390XState *env, uint32_t f1, uint32_t val) +{ + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; + + v2.l = val; + HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __func__, + v1, f1, v2.f); + env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); +} + +/* 32-bit FP compare RR */ +uint32_t HELPER(cebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + float32 v1 = env->fregs[f1].l.upper; + float32 v2 = env->fregs[f2].l.upper; + + HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__, + v1, f1, v2); + return set_cc_f32(env, v1, v2); +} + +/* 64-bit FP compare RR */ +uint32_t HELPER(cdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + float64 v1 = env->fregs[f1].d; + float64 v2 = env->fregs[f2].d; + + HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__, + v1, f1, v2); + return set_cc_f64(env, v1, v2); +} + +/* 128-bit FP compare RR */ +uint32_t HELPER(cxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + CPU_QuadU v1; + CPU_QuadU v2; + + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + + return float_comp_to_cc(env, float128_compare_quiet(v1.q, v2.q, + &env->fpu_status)); +} + +/* 64-bit FP compare RM */ +uint32_t HELPER(cdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + + v2.ll = cpu_ldq_data(env, a2); + HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1, + f1, v2.d); + return set_cc_f64(env, v1, v2.d); +} + +/* 64-bit FP addition RM */ +uint32_t HELPER(adb)(CPUS390XState *env, uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + + v2.ll = cpu_ldq_data(env, a2); + HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__, + v1, f1, v2.d); + env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); + return set_cc_nz_f64(v1); +} + +/* 32-bit FP subtraction RM */ +void HELPER(seb)(CPUS390XState *env, uint32_t f1, uint32_t val) +{ + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; + + v2.l = val; + env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status); +} + +/* 64-bit FP subtraction RM */ +uint32_t HELPER(sdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + + v2.ll = cpu_ldq_data(env, a2); + env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); + return set_cc_nz_f64(v1); +} + +/* 64-bit FP multiplication RM */ +void HELPER(mdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + + v2.ll = cpu_ldq_data(env, a2); + HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__, + v1, f1, v2.d); + env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); +} + +/* 64-bit FP division RM */ +void HELPER(ddb)(CPUS390XState *env, uint32_t f1, uint64_t a2) +{ + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + + v2.ll = cpu_ldq_data(env, a2); + HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __func__, + v1, f1, v2.d); + env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); +} + +static void set_round_mode(CPUS390XState *env, int m3) +{ + switch (m3) { + case 0: + /* current mode */ + break; + case 1: + /* biased round no nearest */ + case 4: + /* round to nearest */ + set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); + break; + case 5: + /* round to zero */ + set_float_rounding_mode(float_round_to_zero, &env->fpu_status); + break; + case 6: + /* round to +inf */ + set_float_rounding_mode(float_round_up, &env->fpu_status); + break; + case 7: + /* round to -inf */ + set_float_rounding_mode(float_round_down, &env->fpu_status); + break; + } +} + +/* convert 32-bit float to 64-bit int */ +uint32_t HELPER(cgebr)(CPUS390XState *env, uint32_t r1, uint32_t f2, + uint32_t m3) +{ + float32 v2 = env->fregs[f2].l.upper; + + set_round_mode(env, m3); + env->regs[r1] = float32_to_int64(v2, &env->fpu_status); + return set_cc_nz_f32(v2); +} + +/* convert 64-bit float to 64-bit int */ +uint32_t HELPER(cgdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, + uint32_t m3) +{ + float64 v2 = env->fregs[f2].d; + + set_round_mode(env, m3); + env->regs[r1] = float64_to_int64(v2, &env->fpu_status); + return set_cc_nz_f64(v2); +} + +/* convert 128-bit float to 64-bit int */ +uint32_t HELPER(cgxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, + uint32_t m3) +{ + CPU_QuadU v2; + + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + set_round_mode(env, m3); + env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status); + if (float128_is_any_nan(v2.q)) { + return 3; + } else if (float128_is_zero(v2.q)) { + return 0; + } else if (float128_is_neg(v2.q)) { + return 1; + } else { + return 2; + } +} + +/* convert 32-bit float to 32-bit int */ +uint32_t HELPER(cfebr)(CPUS390XState *env, uint32_t r1, uint32_t f2, + uint32_t m3) +{ + float32 v2 = env->fregs[f2].l.upper; + + set_round_mode(env, m3); + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | + float32_to_int32(v2, &env->fpu_status); + return set_cc_nz_f32(v2); +} + +/* convert 64-bit float to 32-bit int */ +uint32_t HELPER(cfdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, + uint32_t m3) +{ + float64 v2 = env->fregs[f2].d; + + set_round_mode(env, m3); + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | + float64_to_int32(v2, &env->fpu_status); + return set_cc_nz_f64(v2); +} + +/* convert 128-bit float to 32-bit int */ +uint32_t HELPER(cfxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, + uint32_t m3) +{ + CPU_QuadU v2; + + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | + float128_to_int32(v2.q, &env->fpu_status); + return set_cc_nz_f128(v2.q); +} + +/* load 32-bit FP zero */ +void HELPER(lzer)(CPUS390XState *env, uint32_t f1) +{ + env->fregs[f1].l.upper = float32_zero; +} + +/* load 64-bit FP zero */ +void HELPER(lzdr)(CPUS390XState *env, uint32_t f1) +{ + env->fregs[f1].d = float64_zero; +} + +/* load 128-bit FP zero */ +void HELPER(lzxr)(CPUS390XState *env, uint32_t f1) +{ + CPU_QuadU x; + + x.q = float64_to_float128(float64_zero, &env->fpu_status); + env->fregs[f1].ll = x.ll.upper; + env->fregs[f1 + 1].ll = x.ll.lower; +} + +/* 128-bit FP subtraction RR */ +uint32_t HELPER(sxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + CPU_QuadU v1; + CPU_QuadU v2; + CPU_QuadU res; + + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + res.q = float128_sub(v1.q, v2.q, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; + return set_cc_nz_f128(res.q); +} + +/* 128-bit FP addition RR */ +uint32_t HELPER(axbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + CPU_QuadU v1; + CPU_QuadU v2; + CPU_QuadU res; + + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + res.q = float128_add(v1.q, v2.q, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; + return set_cc_nz_f128(res.q); +} + +/* 32-bit FP multiplication RR */ +void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper, + env->fregs[f2].l.upper, + &env->fpu_status); +} + +/* 64-bit FP division RR */ +void HELPER(ddbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, + &env->fpu_status); +} + +/* 64-bit FP multiply and add RM */ +void HELPER(madb)(CPUS390XState *env, uint32_t f1, uint64_t a2, uint32_t f3) +{ + CPU_DoubleU v2; + + HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3); + v2.ll = cpu_ldq_data(env, a2); + env->fregs[f1].d = float64_add(env->fregs[f1].d, + float64_mul(v2.d, env->fregs[f3].d, + &env->fpu_status), + &env->fpu_status); +} + +/* 64-bit FP multiply and add RR */ +void HELPER(madbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) +{ + HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); + env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, + env->fregs[f3].d, + &env->fpu_status), + env->fregs[f1].d, &env->fpu_status); +} + +/* 64-bit FP multiply and subtract RR */ +void HELPER(msdbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) +{ + HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); + env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, + env->fregs[f3].d, + &env->fpu_status), + env->fregs[f1].d, &env->fpu_status); +} + +/* 32-bit FP multiply and add RR */ +void HELPER(maebr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) +{ + env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, + float32_mul(env->fregs[f2].l.upper, + env->fregs[f3].l.upper, + &env->fpu_status), + &env->fpu_status); +} + +/* convert 32-bit float to 64-bit float */ +void HELPER(ldeb)(CPUS390XState *env, uint32_t f1, uint64_t a2) +{ + uint32_t v2; + + v2 = cpu_ldl_data(env, a2); + env->fregs[f1].d = float32_to_float64(v2, + &env->fpu_status); +} + +/* convert 64-bit float to 128-bit float */ +void HELPER(lxdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) +{ + CPU_DoubleU v2; + CPU_QuadU v1; + + v2.ll = cpu_ldq_data(env, a2); + v1.q = float64_to_float128(v2.d, &env->fpu_status); + env->fregs[f1].ll = v1.ll.upper; + env->fregs[f1 + 2].ll = v1.ll.lower; +} + +/* test data class 32-bit */ +uint32_t HELPER(tceb)(CPUS390XState *env, uint32_t f1, uint64_t m2) +{ + float32 v1 = env->fregs[f1].l.upper; + int neg = float32_is_neg(v1); + uint32_t cc = 0; + + HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, (long)v1, m2, neg); + if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) || + (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) || + (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || + (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { + cc = 1; + } else if (m2 & (1 << (9-neg))) { + /* assume normalized number */ + cc = 1; + } + + /* FIXME: denormalized? */ + return cc; +} + +/* test data class 64-bit */ +uint32_t HELPER(tcdb)(CPUS390XState *env, uint32_t f1, uint64_t m2) +{ + float64 v1 = env->fregs[f1].d; + int neg = float64_is_neg(v1); + uint32_t cc = 0; + + HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, v1, m2, neg); + if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) || + (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) || + (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || + (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { + cc = 1; + } else if (m2 & (1 << (9-neg))) { + /* assume normalized number */ + cc = 1; + } + /* FIXME: denormalized? */ + return cc; +} + +/* test data class 128-bit */ +uint32_t HELPER(tcxb)(CPUS390XState *env, uint32_t f1, uint64_t m2) +{ + CPU_QuadU v1; + uint32_t cc = 0; + int neg; + + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; + + neg = float128_is_neg(v1.q); + if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) || + (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) || + (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) || + (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) { + cc = 1; + } else if (m2 & (1 << (9-neg))) { + /* assume normalized number */ + cc = 1; + } + /* FIXME: denormalized? */ + return cc; +} + +/* square root 64-bit RR */ +void HELPER(sqdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) +{ + env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); +} diff --git a/target-s390x/helper.c b/target-s390x/helper.c index d0a1180..a5741ec 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -74,7 +74,7 @@ S390CPU *cpu_s390x_init(const char *cpu_model) { S390CPU *cpu; CPUS390XState *env; - static int inited = 0; + static int inited; cpu = S390_CPU(object_new(TYPE_S390_CPU)); env = &cpu->env; @@ -91,25 +91,27 @@ S390CPU *cpu_s390x_init(const char *cpu_model) #if defined(CONFIG_USER_ONLY) -void do_interrupt (CPUS390XState *env) +void do_interrupt(CPUS390XState *env) { env->exception_index = -1; } -int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw, - int mmu_idx) +int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address, + int rw, int mmu_idx) { - /* fprintf(stderr,"%s: address 0x%lx rw %d mmu_idx %d\n", - __FUNCTION__, address, rw, mmu_idx); */ + /* fprintf(stderr, "%s: address 0x%lx rw %d mmu_idx %d\n", + __func__, address, rw, mmu_idx); */ env->exception_index = EXCP_ADDR; - env->__excp_addr = address; /* FIXME: find out how this works on a real machine */ + /* FIXME: find out how this works on a real machine */ + env->__excp_addr = address; return 1; } #else /* !CONFIG_USER_ONLY */ /* Ensure to exit the TB after this call! */ -static void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilc) +static void trigger_pgm_exception(CPUS390XState *env, uint32_t code, + uint32_t ilc) { env->exception_index = EXCP_PGM; env->int_pgm_code = code; @@ -138,19 +140,20 @@ static int trans_bits(CPUS390XState *env, uint64_t mode) return bits; } -static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr, uint64_t mode) +static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr, + uint64_t mode) { int ilc = ILC_LATER_INC_2; int bits = trans_bits(env, mode) | 4; - DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __FUNCTION__, vaddr, bits); + DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits); trigger_pgm_exception(env, PGM_PROTECTION, ilc); } -static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, uint32_t type, - uint64_t asc, int rw) +static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, + uint32_t type, uint64_t asc, int rw) { int ilc = ILC_LATER; int bits = trans_bits(env, asc); @@ -160,26 +163,26 @@ static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, uint32_t ilc = 2; } - DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __FUNCTION__, vaddr, bits); + DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits); trigger_pgm_exception(env, type, ilc); } -static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t asc, - uint64_t asce, int level, target_ulong *raddr, - int *flags, int rw) +static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, + uint64_t asc, uint64_t asce, int level, + target_ulong *raddr, int *flags, int rw) { uint64_t offs = 0; uint64_t origin; uint64_t new_asce; - PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __FUNCTION__, asce); + PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __func__, asce); if (((level != _ASCE_TYPE_SEGMENT) && (asce & _REGION_ENTRY_INV)) || ((level == _ASCE_TYPE_SEGMENT) && (asce & _SEGMENT_ENTRY_INV))) { /* XXX different regions have different faults */ - DPRINTF("%s: invalid region\n", __FUNCTION__); + DPRINTF("%s: invalid region\n", __func__); trigger_page_fault(env, vaddr, PGM_SEGMENT_TRANS, asc, rw); return -1; } @@ -222,7 +225,7 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t a new_asce = ldq_phys(origin + offs); PTE_DPRINTF("%s: 0x%" PRIx64 " + 0x%" PRIx64 " => 0x%016" PRIx64 "\n", - __FUNCTION__, origin, offs, new_asce); + __func__, origin, offs, new_asce); if (level != _ASCE_TYPE_SEGMENT) { /* yet another region */ @@ -232,7 +235,7 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t a /* PTE */ if (new_asce & _PAGE_INVALID) { - DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __FUNCTION__, new_asce); + DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __func__, new_asce); trigger_page_fault(env, vaddr, PGM_PAGE_TRANS, asc, rw); return -1; } @@ -243,13 +246,14 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t a *raddr = new_asce & _ASCE_ORIGIN; - PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __FUNCTION__, new_asce); + PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __func__, new_asce); return 0; } -static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t asc, - target_ulong *raddr, int *flags, int rw) +static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, + uint64_t asc, target_ulong *raddr, int *flags, + int rw) { uint64_t asce = 0; int level, new_level; @@ -257,15 +261,15 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as switch (asc) { case PSW_ASC_PRIMARY: - PTE_DPRINTF("%s: asc=primary\n", __FUNCTION__); + PTE_DPRINTF("%s: asc=primary\n", __func__); asce = env->cregs[1]; break; case PSW_ASC_SECONDARY: - PTE_DPRINTF("%s: asc=secondary\n", __FUNCTION__); + PTE_DPRINTF("%s: asc=secondary\n", __func__); asce = env->cregs[7]; break; case PSW_ASC_HOME: - PTE_DPRINTF("%s: asc=home\n", __FUNCTION__); + PTE_DPRINTF("%s: asc=home\n", __func__); asce = env->cregs[13]; break; } @@ -276,8 +280,7 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as case _ASCE_TYPE_REGION2: if (vaddr & 0xffe0000000000000ULL) { DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64 - " 0xffe0000000000000ULL\n", __FUNCTION__, - vaddr); + " 0xffe0000000000000ULL\n", __func__, vaddr); trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw); return -1; } @@ -285,8 +288,7 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as case _ASCE_TYPE_REGION3: if (vaddr & 0xfffffc0000000000ULL) { DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64 - " 0xfffffc0000000000ULL\n", __FUNCTION__, - vaddr); + " 0xfffffc0000000000ULL\n", __func__, vaddr); trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw); return -1; } @@ -294,8 +296,7 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as case _ASCE_TYPE_SEGMENT: if (vaddr & 0xffffffff80000000ULL) { DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64 - " 0xffffffff80000000ULL\n", __FUNCTION__, - vaddr); + " 0xffffffff80000000ULL\n", __func__, vaddr); trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw); return -1; } @@ -358,7 +359,7 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, break; } -out: + out: /* Convert real address -> absolute address */ if (*raddr < 0x2000) { *raddr = *raddr + env->psa; @@ -378,18 +379,18 @@ out: return r; } -int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong _vaddr, int rw, - int mmu_idx) +int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong orig_vaddr, + int rw, int mmu_idx) { uint64_t asc = env->psw.mask & PSW_MASK_ASC; target_ulong vaddr, raddr; int prot; DPRINTF("%s: address 0x%" PRIx64 " rw %d mmu_idx %d\n", - __FUNCTION__, _vaddr, rw, mmu_idx); + __func__, _vaddr, rw, mmu_idx); - _vaddr &= TARGET_PAGE_MASK; - vaddr = _vaddr; + orig_vaddr &= TARGET_PAGE_MASK; + vaddr = orig_vaddr; /* 31-Bit mode */ if (!(env->psw.mask & PSW_MASK_64)) { @@ -403,22 +404,23 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong _vaddr, int rw, /* check out of RAM access */ if (raddr > (ram_size + virtio_size)) { - DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __FUNCTION__, + DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, (uint64_t)aaddr, (uint64_t)ram_size); trigger_pgm_exception(env, PGM_ADDRESSING, ILC_LATER); return 1; } - DPRINTF("%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", __FUNCTION__, + DPRINTF("%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", __func__, (uint64_t)vaddr, (uint64_t)raddr, prot); - tlb_set_page(env, _vaddr, raddr, prot, + tlb_set_page(env, orig_vaddr, raddr, prot, mmu_idx, TARGET_PAGE_SIZE); return 0; } -target_phys_addr_t cpu_get_phys_page_debug(CPUS390XState *env, target_ulong vaddr) +target_phys_addr_t cpu_get_phys_page_debug(CPUS390XState *env, + target_ulong vaddr) { target_ulong raddr; int prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; @@ -497,19 +499,19 @@ static void do_program_interrupt(CPUS390XState *env) switch (ilc) { case ILC_LATER: - ilc = get_ilc(ldub_code(env->psw.addr)); + ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); break; case ILC_LATER_INC: - ilc = get_ilc(ldub_code(env->psw.addr)); + ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); env->psw.addr += ilc * 2; break; case ILC_LATER_INC_2: - ilc = get_ilc(ldub_code(env->psw.addr)) * 2; + ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)) * 2; env->psw.addr += ilc; break; } - qemu_log("%s: code=0x%x ilc=%d\n", __FUNCTION__, env->int_pgm_code, ilc); + qemu_log("%s: code=0x%x ilc=%d\n", __func__, env->int_pgm_code, ilc); lowcore = cpu_physical_memory_map(env->psa, &len, 1); @@ -522,7 +524,7 @@ static void do_program_interrupt(CPUS390XState *env) cpu_physical_memory_unmap(lowcore, len, 1, len); - DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __FUNCTION__, + DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__, env->int_pgm_code, ilc, env->psw.mask, env->psw.addr); @@ -565,15 +567,15 @@ static void do_ext_interrupt(CPUS390XState *env) env->pending_int &= ~INTERRUPT_EXT; } - DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __FUNCTION__, + DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, env->psw.mask, env->psw.addr); load_psw(env, mask, addr); } -void do_interrupt (CPUS390XState *env) +void do_interrupt(CPUS390XState *env) { - qemu_log("%s: %d at pc=%" PRIx64 "\n", __FUNCTION__, env->exception_index, + qemu_log("%s: %d at pc=%" PRIx64 "\n", __func__, env->exception_index, env->psw.addr); s390_add_running_cpu(env); diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 01c8d0e..5419f37 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -1,19 +1,19 @@ #include "def-helper.h" -DEF_HELPER_1(exception, void, i32) -DEF_HELPER_3(nc, i32, i32, i64, i64) -DEF_HELPER_3(oc, i32, i32, i64, i64) -DEF_HELPER_3(xc, i32, i32, i64, i64) -DEF_HELPER_3(mvc, void, i32, i64, i64) -DEF_HELPER_3(clc, i32, i32, i64, i64) -DEF_HELPER_2(mvcl, i32, i32, i32) +DEF_HELPER_2(exception, void, env, i32) +DEF_HELPER_4(nc, i32, env, i32, i64, i64) +DEF_HELPER_4(oc, i32, env, i32, i64, i64) +DEF_HELPER_4(xc, i32, env, i32, i64, i64) +DEF_HELPER_4(mvc, void, env, i32, i64, i64) +DEF_HELPER_4(clc, i32, env, i32, i64, i64) +DEF_HELPER_3(mvcl, i32, env, i32, i32) DEF_HELPER_FLAGS_1(set_cc_comp_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32) DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64) DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) -DEF_HELPER_3(clm, i32, i32, i32, i64) -DEF_HELPER_3(stcm, void, i32, i32, i64) -DEF_HELPER_2(mlg, void, i32, i64) -DEF_HELPER_2(dlg, void, i32, i64) +DEF_HELPER_4(clm, i32, env, i32, i32, i64) +DEF_HELPER_4(stcm, void, env, i32, i32, i64) +DEF_HELPER_3(mlg, void, env, i32, i64) +DEF_HELPER_3(dlg, void, env, i32, i64) DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64) DEF_HELPER_FLAGS_3(set_cc_addu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) DEF_HELPER_FLAGS_3(set_cc_add32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32) @@ -22,131 +22,131 @@ DEF_HELPER_FLAGS_3(set_cc_sub64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s6 DEF_HELPER_FLAGS_3(set_cc_subu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) DEF_HELPER_FLAGS_3(set_cc_sub32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32) DEF_HELPER_FLAGS_3(set_cc_subu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) -DEF_HELPER_3(srst, i32, i32, i32, i32) -DEF_HELPER_3(clst, i32, i32, i32, i32) -DEF_HELPER_3(mvpg, void, i64, i64, i64) -DEF_HELPER_3(mvst, void, i32, i32, i32) -DEF_HELPER_3(csg, i32, i32, i64, i32) -DEF_HELPER_3(cdsg, i32, i32, i64, i32) -DEF_HELPER_3(cs, i32, i32, i64, i32) -DEF_HELPER_4(ex, i32, i32, i64, i64, i64) +DEF_HELPER_4(srst, i32, env, i32, i32, i32) +DEF_HELPER_4(clst, i32, env, i32, i32, i32) +DEF_HELPER_4(mvpg, void, env, i64, i64, i64) +DEF_HELPER_4(mvst, void, env, i32, i32, i32) +DEF_HELPER_4(csg, i32, env, i32, i64, i32) +DEF_HELPER_4(cdsg, i32, env, i32, i64, i32) +DEF_HELPER_4(cs, i32, env, i32, i64, i32) +DEF_HELPER_5(ex, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32) DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_PURE|TCG_CALL_CONST, s32, s32) DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_PURE|TCG_CALL_CONST, i64, s64) DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_PURE|TCG_CALL_CONST, s64, s64) -DEF_HELPER_3(stcmh, void, i32, i64, i32) -DEF_HELPER_3(icmh, i32, i32, i64, i32) -DEF_HELPER_2(ipm, void, i32, i32) +DEF_HELPER_4(stcmh, void, env, i32, i64, i32) +DEF_HELPER_4(icmh, i32, env, i32, i64, i32) +DEF_HELPER_3(ipm, void, env, i32, i32) DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) -DEF_HELPER_3(stam, void, i32, i64, i32) -DEF_HELPER_3(lam, void, i32, i64, i32) -DEF_HELPER_3(mvcle, i32, i32, i64, i32) -DEF_HELPER_3(clcle, i32, i32, i64, i32) -DEF_HELPER_3(slb, i32, i32, i32, i32) -DEF_HELPER_4(slbg, i32, i32, i32, i64, i64) -DEF_HELPER_2(cefbr, void, i32, s32) -DEF_HELPER_2(cdfbr, void, i32, s32) -DEF_HELPER_2(cxfbr, void, i32, s32) -DEF_HELPER_2(cegbr, void, i32, s64) -DEF_HELPER_2(cdgbr, void, i32, s64) -DEF_HELPER_2(cxgbr, void, i32, s64) -DEF_HELPER_2(adbr, i32, i32, i32) -DEF_HELPER_2(aebr, i32, i32, i32) -DEF_HELPER_2(sebr, i32, i32, i32) -DEF_HELPER_2(sdbr, i32, i32, i32) -DEF_HELPER_2(debr, void, i32, i32) -DEF_HELPER_2(dxbr, void, i32, i32) -DEF_HELPER_2(mdbr, void, i32, i32) -DEF_HELPER_2(mxbr, void, i32, i32) -DEF_HELPER_2(ldebr, void, i32, i32) -DEF_HELPER_2(ldxbr, void, i32, i32) -DEF_HELPER_2(lxdbr, void, i32, i32) -DEF_HELPER_2(ledbr, void, i32, i32) -DEF_HELPER_2(lexbr, void, i32, i32) -DEF_HELPER_2(lpebr, i32, i32, i32) -DEF_HELPER_2(lpdbr, i32, i32, i32) -DEF_HELPER_2(lpxbr, i32, i32, i32) -DEF_HELPER_2(ltebr, i32, i32, i32) -DEF_HELPER_2(ltdbr, i32, i32, i32) -DEF_HELPER_2(ltxbr, i32, i32, i32) -DEF_HELPER_2(lcebr, i32, i32, i32) -DEF_HELPER_2(lcdbr, i32, i32, i32) -DEF_HELPER_2(lcxbr, i32, i32, i32) -DEF_HELPER_2(aeb, void, i32, i32) -DEF_HELPER_2(deb, void, i32, i32) -DEF_HELPER_2(meeb, void, i32, i32) -DEF_HELPER_2(cdb, i32, i32, i64) -DEF_HELPER_2(adb, i32, i32, i64) -DEF_HELPER_2(seb, void, i32, i32) -DEF_HELPER_2(sdb, i32, i32, i64) -DEF_HELPER_2(mdb, void, i32, i64) -DEF_HELPER_2(ddb, void, i32, i64) -DEF_HELPER_FLAGS_2(cebr, TCG_CALL_PURE, i32, i32, i32) -DEF_HELPER_FLAGS_2(cdbr, TCG_CALL_PURE, i32, i32, i32) -DEF_HELPER_FLAGS_2(cxbr, TCG_CALL_PURE, i32, i32, i32) -DEF_HELPER_3(cgebr, i32, i32, i32, i32) -DEF_HELPER_3(cgdbr, i32, i32, i32, i32) -DEF_HELPER_3(cgxbr, i32, i32, i32, i32) -DEF_HELPER_1(lzer, void, i32) -DEF_HELPER_1(lzdr, void, i32) -DEF_HELPER_1(lzxr, void, i32) -DEF_HELPER_3(cfebr, i32, i32, i32, i32) -DEF_HELPER_3(cfdbr, i32, i32, i32, i32) -DEF_HELPER_3(cfxbr, i32, i32, i32, i32) -DEF_HELPER_2(axbr, i32, i32, i32) -DEF_HELPER_2(sxbr, i32, i32, i32) -DEF_HELPER_2(meebr, void, i32, i32) -DEF_HELPER_2(ddbr, void, i32, i32) -DEF_HELPER_3(madb, void, i32, i64, i32) -DEF_HELPER_3(maebr, void, i32, i32, i32) -DEF_HELPER_3(madbr, void, i32, i32, i32) -DEF_HELPER_3(msdbr, void, i32, i32, i32) -DEF_HELPER_2(ldeb, void, i32, i64) -DEF_HELPER_2(lxdb, void, i32, i64) -DEF_HELPER_FLAGS_2(tceb, TCG_CALL_PURE, i32, i32, i64) -DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_PURE, i32, i32, i64) -DEF_HELPER_FLAGS_2(tcxb, TCG_CALL_PURE, i32, i32, i64) -DEF_HELPER_2(flogr, i32, i32, i64) -DEF_HELPER_2(sqdbr, void, i32, i32) +DEF_HELPER_4(stam, void, env, i32, i64, i32) +DEF_HELPER_4(lam, void, env, i32, i64, i32) +DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) +DEF_HELPER_4(clcle, i32, env, i32, i64, i32) +DEF_HELPER_4(slb, i32, env, i32, i32, i32) +DEF_HELPER_5(slbg, i32, env, i32, i32, i64, i64) +DEF_HELPER_3(cefbr, void, env, i32, s32) +DEF_HELPER_3(cdfbr, void, env, i32, s32) +DEF_HELPER_3(cxfbr, void, env, i32, s32) +DEF_HELPER_3(cegbr, void, env, i32, s64) +DEF_HELPER_3(cdgbr, void, env, i32, s64) +DEF_HELPER_3(cxgbr, void, env, i32, s64) +DEF_HELPER_3(adbr, i32, env, i32, i32) +DEF_HELPER_3(aebr, i32, env, i32, i32) +DEF_HELPER_3(sebr, i32, env, i32, i32) +DEF_HELPER_3(sdbr, i32, env, i32, i32) +DEF_HELPER_3(debr, void, env, i32, i32) +DEF_HELPER_3(dxbr, void, env, i32, i32) +DEF_HELPER_3(mdbr, void, env, i32, i32) +DEF_HELPER_3(mxbr, void, env, i32, i32) +DEF_HELPER_3(ldebr, void, env, i32, i32) +DEF_HELPER_3(ldxbr, void, env, i32, i32) +DEF_HELPER_3(lxdbr, void, env, i32, i32) +DEF_HELPER_3(ledbr, void, env, i32, i32) +DEF_HELPER_3(lexbr, void, env, i32, i32) +DEF_HELPER_3(lpebr, i32, env, i32, i32) +DEF_HELPER_3(lpdbr, i32, env, i32, i32) +DEF_HELPER_3(lpxbr, i32, env, i32, i32) +DEF_HELPER_3(ltebr, i32, env, i32, i32) +DEF_HELPER_3(ltdbr, i32, env, i32, i32) +DEF_HELPER_3(ltxbr, i32, env, i32, i32) +DEF_HELPER_3(lcebr, i32, env, i32, i32) +DEF_HELPER_3(lcdbr, i32, env, i32, i32) +DEF_HELPER_3(lcxbr, i32, env, i32, i32) +DEF_HELPER_3(aeb, void, env, i32, i32) +DEF_HELPER_3(deb, void, env, i32, i32) +DEF_HELPER_3(meeb, void, env, i32, i32) +DEF_HELPER_3(cdb, i32, env, i32, i64) +DEF_HELPER_3(adb, i32, env, i32, i64) +DEF_HELPER_3(seb, void, env, i32, i32) +DEF_HELPER_3(sdb, i32, env, i32, i64) +DEF_HELPER_3(mdb, void, env, i32, i64) +DEF_HELPER_3(ddb, void, env, i32, i64) +DEF_HELPER_FLAGS_3(cebr, TCG_CALL_PURE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(cdbr, TCG_CALL_PURE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(cxbr, TCG_CALL_PURE, i32, env, i32, i32) +DEF_HELPER_4(cgebr, i32, env, i32, i32, i32) +DEF_HELPER_4(cgdbr, i32, env, i32, i32, i32) +DEF_HELPER_4(cgxbr, i32, env, i32, i32, i32) +DEF_HELPER_2(lzer, void, env, i32) +DEF_HELPER_2(lzdr, void, env, i32) +DEF_HELPER_2(lzxr, void, env, i32) +DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) +DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) +DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) +DEF_HELPER_3(axbr, i32, env, i32, i32) +DEF_HELPER_3(sxbr, i32, env, i32, i32) +DEF_HELPER_3(meebr, void, env, i32, i32) +DEF_HELPER_3(ddbr, void, env, i32, i32) +DEF_HELPER_4(madb, void, env, i32, i64, i32) +DEF_HELPER_4(maebr, void, env, i32, i32, i32) +DEF_HELPER_4(madbr, void, env, i32, i32, i32) +DEF_HELPER_4(msdbr, void, env, i32, i32, i32) +DEF_HELPER_3(ldeb, void, env, i32, i64) +DEF_HELPER_3(lxdb, void, env, i32, i64) +DEF_HELPER_FLAGS_3(tceb, TCG_CALL_PURE, i32, env, i32, i64) +DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_PURE, i32, env, i32, i64) +DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_PURE, i32, env, i32, i64) +DEF_HELPER_3(flogr, i32, env, i32, i64) +DEF_HELPER_3(sqdbr, void, env, i32, i32) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_PURE|TCG_CALL_CONST, i64, s32) -DEF_HELPER_3(unpk, void, i32, i64, i64) -DEF_HELPER_3(tr, void, i32, i64, i64) +DEF_HELPER_4(unpk, void, env, i32, i64, i64) +DEF_HELPER_4(tr, void, env, i32, i64, i64) -DEF_HELPER_2(servc, i32, i32, i64) -DEF_HELPER_3(diag, i64, i32, i64, i64) -DEF_HELPER_2(load_psw, void, i64, i64) +DEF_HELPER_3(servc, i32, env, i32, i64) +DEF_HELPER_4(diag, i64, env, i32, i64, i64) +DEF_HELPER_3(load_psw, void, env, i64, i64) DEF_HELPER_1(program_interrupt, void, i32) -DEF_HELPER_FLAGS_1(stidp, TCG_CALL_CONST, void, i64) -DEF_HELPER_FLAGS_1(spx, TCG_CALL_CONST, void, i64) +DEF_HELPER_FLAGS_2(stidp, TCG_CALL_CONST, void, env, i64) +DEF_HELPER_FLAGS_2(spx, TCG_CALL_CONST, void, env, i64) DEF_HELPER_FLAGS_1(sck, TCG_CALL_CONST, i32, i64) -DEF_HELPER_1(stck, i32, i64) -DEF_HELPER_1(stcke, i32, i64) -DEF_HELPER_FLAGS_1(sckc, TCG_CALL_CONST, void, i64) -DEF_HELPER_FLAGS_1(stckc, TCG_CALL_CONST, void, i64) -DEF_HELPER_FLAGS_1(spt, TCG_CALL_CONST, void, i64) -DEF_HELPER_FLAGS_1(stpt, TCG_CALL_CONST, void, i64) -DEF_HELPER_3(stsi, i32, i64, i32, i32) -DEF_HELPER_3(lctl, void, i32, i64, i32) -DEF_HELPER_3(lctlg, void, i32, i64, i32) -DEF_HELPER_3(stctl, void, i32, i64, i32) -DEF_HELPER_3(stctg, void, i32, i64, i32) +DEF_HELPER_2(stck, i32, env, i64) +DEF_HELPER_2(stcke, i32, env, i64) +DEF_HELPER_FLAGS_2(sckc, TCG_CALL_CONST, void, env, i64) +DEF_HELPER_FLAGS_2(stckc, TCG_CALL_CONST, void, env, i64) +DEF_HELPER_FLAGS_2(spt, TCG_CALL_CONST, void, env, i64) +DEF_HELPER_FLAGS_2(stpt, TCG_CALL_CONST, void, env, i64) +DEF_HELPER_4(stsi, i32, env, i64, i32, i32) +DEF_HELPER_4(lctl, void, env, i32, i64, i32) +DEF_HELPER_4(lctlg, void, env, i32, i64, i32) +DEF_HELPER_4(stctl, void, env, i32, i64, i32) +DEF_HELPER_4(stctg, void, env, i32, i64, i32) DEF_HELPER_FLAGS_2(tprot, TCG_CALL_CONST, i32, i64, i64) -DEF_HELPER_FLAGS_1(iske, TCG_CALL_PURE|TCG_CALL_CONST, i64, i64) -DEF_HELPER_FLAGS_2(sske, TCG_CALL_CONST, void, i32, i64) -DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_CONST, i32, i32, i64) -DEF_HELPER_2(csp, i32, i32, i32) -DEF_HELPER_3(mvcs, i32, i64, i64, i64) -DEF_HELPER_3(mvcp, i32, i64, i64, i64) -DEF_HELPER_3(sigp, i32, i64, i32, i64) -DEF_HELPER_1(sacf, void, i64) -DEF_HELPER_FLAGS_2(ipte, TCG_CALL_CONST, void, i64, i64) -DEF_HELPER_FLAGS_0(ptlb, TCG_CALL_CONST, void) -DEF_HELPER_2(lra, i32, i64, i32) -DEF_HELPER_2(stura, void, i64, i32) -DEF_HELPER_2(cksm, void, i32, i32) +DEF_HELPER_FLAGS_2(iske, TCG_CALL_PURE|TCG_CALL_CONST, i64, env, i64) +DEF_HELPER_FLAGS_3(sske, TCG_CALL_CONST, void, env, i32, i64) +DEF_HELPER_FLAGS_3(rrbe, TCG_CALL_CONST, i32, env, i32, i64) +DEF_HELPER_3(csp, i32, env, i32, i32) +DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) +DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) +DEF_HELPER_4(sigp, i32, env, i64, i32, i64) +DEF_HELPER_2(sacf, void, env, i64) +DEF_HELPER_FLAGS_3(ipte, TCG_CALL_CONST, void, env, i64, i64) +DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_CONST, void, env) +DEF_HELPER_3(lra, i32, env, i64, i32) +DEF_HELPER_3(stura, void, env, i64, i32) +DEF_HELPER_3(cksm, void, env, i32, i32) -DEF_HELPER_FLAGS_4(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST, - i32, i32, i64, i64, i64) +DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST, + i32, env, i32, i64, i64, i64) #include "def-helper.h" diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c new file mode 100644 index 0000000..f202a7e --- /dev/null +++ b/target-s390x/int_helper.c @@ -0,0 +1,201 @@ +/* + * S/390 integer helper routines + * + * Copyright (c) 2009 Ulrich Hecht + * Copyright (c) 2009 Alexander Graf + * + * 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 "cpu.h" +#include "host-utils.h" +#include "helper.h" + +/* #define DEBUG_HELPER */ +#ifdef DEBUG_HELPER +#define HELPER_LOG(x...) qemu_log(x) +#else +#define HELPER_LOG(x...) +#endif + +/* 64/64 -> 128 unsigned multiplication */ +void HELPER(mlg)(CPUS390XState *env, uint32_t r1, uint64_t v2) +{ +#if HOST_LONG_BITS == 64 && defined(__GNUC__) + /* assuming 64-bit hosts have __uint128_t */ + __uint128_t res = (__uint128_t)env->regs[r1 + 1]; + + res *= (__uint128_t)v2; + env->regs[r1] = (uint64_t)(res >> 64); + env->regs[r1 + 1] = (uint64_t)res; +#else + mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2); +#endif +} + +/* 128 -> 64/64 unsigned division */ +void HELPER(dlg)(CPUS390XState *env, uint32_t r1, uint64_t v2) +{ + uint64_t divisor = v2; + + if (!env->regs[r1]) { + /* 64 -> 64/64 case */ + env->regs[r1] = env->regs[r1 + 1] % divisor; + env->regs[r1 + 1] = env->regs[r1 + 1] / divisor; + return; + } else { +#if HOST_LONG_BITS == 64 && defined(__GNUC__) + /* assuming 64-bit hosts have __uint128_t */ + __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | + (env->regs[r1 + 1]); + __uint128_t quotient = dividend / divisor; + __uint128_t remainder = dividend % divisor; + + env->regs[r1 + 1] = quotient; + env->regs[r1] = remainder; +#else + /* 32-bit hosts would need special wrapper functionality - just abort if + we encounter such a case; it's very unlikely anyways. */ + cpu_abort(env, "128 -> 64/64 division not implemented\n"); +#endif + } +} + +/* absolute value 32-bit */ +uint32_t HELPER(abs_i32)(int32_t val) +{ + if (val < 0) { + return -val; + } else { + return val; + } +} + +/* negative absolute value 32-bit */ +int32_t HELPER(nabs_i32)(int32_t val) +{ + if (val < 0) { + return val; + } else { + return -val; + } +} + +/* absolute value 64-bit */ +uint64_t HELPER(abs_i64)(int64_t val) +{ + HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val); + + if (val < 0) { + return -val; + } else { + return val; + } +} + +/* negative absolute value 64-bit */ +int64_t HELPER(nabs_i64)(int64_t val) +{ + if (val < 0) { + return val; + } else { + return -val; + } +} + +/* add with carry 32-bit unsigned */ +uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2) +{ + uint32_t res; + + res = v1 + v2; + if (cc & 2) { + res++; + } + + return res; +} + +/* subtract unsigned v2 from v1 with borrow */ +uint32_t HELPER(slb)(CPUS390XState *env, uint32_t cc, uint32_t r1, uint32_t v2) +{ + uint32_t v1 = env->regs[r1]; + uint32_t res = v1 + (~v2) + (cc >> 1); + + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; + if (cc & 2) { + /* borrow */ + return v1 ? 1 : 0; + } else { + return v1 ? 3 : 2; + } +} + +/* subtract unsigned v2 from v1 with borrow */ +uint32_t HELPER(slbg)(CPUS390XState *env, uint32_t cc, uint32_t r1, + uint64_t v1, uint64_t v2) +{ + uint64_t res = v1 + (~v2) + (cc >> 1); + + env->regs[r1] = res; + if (cc & 2) { + /* borrow */ + return v1 ? 1 : 0; + } else { + return v1 ? 3 : 2; + } +} + +/* find leftmost one */ +uint32_t HELPER(flogr)(CPUS390XState *env, uint32_t r1, uint64_t v2) +{ + uint64_t res = 0; + uint64_t ov2 = v2; + + while (!(v2 & 0x8000000000000000ULL) && v2) { + v2 <<= 1; + res++; + } + + if (!v2) { + env->regs[r1] = 64; + env->regs[r1 + 1] = 0; + return 0; + } else { + env->regs[r1] = res; + env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res); + return 2; + } +} + +uint64_t HELPER(cvd)(int32_t bin) +{ + /* positive 0 */ + uint64_t dec = 0x0c; + int shift = 4; + + if (bin < 0) { + bin = -bin; + dec = 0x0d; + } + + for (shift = 4; (shift < 64) && bin; shift += 4) { + int current_number = bin % 10; + + dec |= (current_number) << shift; + bin /= 10; + } + + return dec; +} diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c new file mode 100644 index 0000000..b21b37c --- /dev/null +++ b/target-s390x/mem_helper.c @@ -0,0 +1,1203 @@ +/* + * S/390 memory access helper routines + * + * Copyright (c) 2009 Ulrich Hecht + * Copyright (c) 2009 Alexander Graf + * + * 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 "cpu.h" +#include "helper.h" + +/*****************************************************************************/ +/* Softmmu support */ +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" + +#define MMUSUFFIX _mmu + +#define SHIFT 0 +#include "softmmu_template.h" + +#define SHIFT 1 +#include "softmmu_template.h" + +#define SHIFT 2 +#include "softmmu_template.h" + +#define SHIFT 3 +#include "softmmu_template.h" + +/* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +/* XXX: fix it to restore all registers */ +void tlb_fill(CPUS390XState *env, target_ulong addr, int is_write, int mmu_idx, + uintptr_t retaddr) +{ + TranslationBlock *tb; + int ret; + + ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx); + if (unlikely(ret != 0)) { + if (likely(retaddr)) { + /* now we have a real cpu fault */ + tb = tb_find_pc(retaddr); + if (likely(tb)) { + /* the PC is inside the translated code. It means that we have + a virtual CPU fault */ + cpu_restore_state(tb, env, retaddr); + } + } + cpu_loop_exit(env); + } +} + +#endif + +/* #define DEBUG_HELPER */ +#ifdef DEBUG_HELPER +#define HELPER_LOG(x...) qemu_log(x) +#else +#define HELPER_LOG(x...) +#endif + +#ifndef CONFIG_USER_ONLY +static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest, + uint8_t byte) +{ + target_phys_addr_t dest_phys; + target_phys_addr_t len = l; + void *dest_p; + uint64_t asc = env->psw.mask & PSW_MASK_ASC; + int flags; + + if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { + cpu_stb_data(env, dest, byte); + cpu_abort(env, "should never reach here"); + } + dest_phys |= dest & ~TARGET_PAGE_MASK; + + dest_p = cpu_physical_memory_map(dest_phys, &len, 1); + + memset(dest_p, byte, len); + + cpu_physical_memory_unmap(dest_p, 1, len, len); +} + +static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src) +{ + target_phys_addr_t dest_phys; + target_phys_addr_t src_phys; + target_phys_addr_t len = l; + void *dest_p; + void *src_p; + uint64_t asc = env->psw.mask & PSW_MASK_ASC; + int flags; + + if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { + cpu_stb_data(env, dest, 0); + cpu_abort(env, "should never reach here"); + } + dest_phys |= dest & ~TARGET_PAGE_MASK; + + if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) { + cpu_ldub_data(env, src); + cpu_abort(env, "should never reach here"); + } + src_phys |= src & ~TARGET_PAGE_MASK; + + dest_p = cpu_physical_memory_map(dest_phys, &len, 1); + src_p = cpu_physical_memory_map(src_phys, &len, 0); + + memmove(dest_p, src_p, len); + + cpu_physical_memory_unmap(dest_p, 1, len, len); + cpu_physical_memory_unmap(src_p, 0, len, len); +} +#endif + +/* and on array */ +uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src) +{ + int i; + unsigned char x; + uint32_t cc = 0; + + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", + __func__, l, dest, src); + for (i = 0; i <= l; i++) { + x = cpu_ldub_data(env, dest + i) & cpu_ldub_data(env, src + i); + if (x) { + cc = 1; + } + cpu_stb_data(env, dest + i, x); + } + return cc; +} + +/* xor on array */ +uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src) +{ + int i; + unsigned char x; + uint32_t cc = 0; + + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", + __func__, l, dest, src); + +#ifndef CONFIG_USER_ONLY + /* xor with itself is the same as memset(0) */ + if ((l > 32) && (src == dest) && + (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) { + mvc_fast_memset(env, l + 1, dest, 0); + return 0; + } +#else + if (src == dest) { + memset(g2h(dest), 0, l + 1); + return 0; + } +#endif + + for (i = 0; i <= l; i++) { + x = cpu_ldub_data(env, dest + i) ^ cpu_ldub_data(env, src + i); + if (x) { + cc = 1; + } + cpu_stb_data(env, dest + i, x); + } + return cc; +} + +/* or on array */ +uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src) +{ + int i; + unsigned char x; + uint32_t cc = 0; + + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", + __func__, l, dest, src); + for (i = 0; i <= l; i++) { + x = cpu_ldub_data(env, dest + i) | cpu_ldub_data(env, src + i); + if (x) { + cc = 1; + } + cpu_stb_data(env, dest + i, x); + } + return cc; +} + +/* memmove */ +void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) +{ + int i = 0; + int x = 0; + uint32_t l_64 = (l + 1) / 8; + + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", + __func__, l, dest, src); + +#ifndef CONFIG_USER_ONLY + if ((l > 32) && + (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) && + (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) { + if (dest == (src + 1)) { + mvc_fast_memset(env, l + 1, dest, cpu_ldub_data(env, src)); + return; + } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) { + mvc_fast_memmove(env, l + 1, dest, src); + return; + } + } +#else + if (dest == (src + 1)) { + memset(g2h(dest), cpu_ldub_data(env, src), l + 1); + return; + } else { + memmove(g2h(dest), g2h(src), l + 1); + return; + } +#endif + + /* handle the parts that fit into 8-byte loads/stores */ + if (dest != (src + 1)) { + for (i = 0; i < l_64; i++) { + cpu_stq_data(env, dest + x, cpu_ldq_data(env, src + x)); + x += 8; + } + } + + /* slow version crossing pages with byte accesses */ + for (i = x; i <= l; i++) { + cpu_stb_data(env, dest + i, cpu_ldub_data(env, src + i)); + } +} + +/* compare unsigned byte arrays */ +uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2) +{ + int i; + unsigned char x, y; + uint32_t cc; + + HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n", + __func__, l, s1, s2); + for (i = 0; i <= l; i++) { + x = cpu_ldub_data(env, s1 + i); + y = cpu_ldub_data(env, s2 + i); + HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y); + if (x < y) { + cc = 1; + goto done; + } else if (x > y) { + cc = 2; + goto done; + } + } + cc = 0; + done: + HELPER_LOG("\n"); + return cc; +} + +/* compare logical under mask */ +uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask, + uint64_t addr) +{ + uint8_t r, d; + uint32_t cc; + + HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1, + mask, addr); + cc = 0; + while (mask) { + if (mask & 8) { + d = cpu_ldub_data(env, addr); + r = (r1 & 0xff000000UL) >> 24; + HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d, + addr); + if (r < d) { + cc = 1; + break; + } else if (r > d) { + cc = 2; + break; + } + addr++; + } + mask = (mask << 1) & 0xf; + r1 <<= 8; + } + HELPER_LOG("\n"); + return cc; +} + +/* store character under mask */ +void HELPER(stcm)(CPUS390XState *env, uint32_t r1, uint32_t mask, + uint64_t addr) +{ + uint8_t r; + + HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask, + addr); + while (mask) { + if (mask & 8) { + r = (r1 & 0xff000000UL) >> 24; + cpu_stb_data(env, addr, r); + HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr); + addr++; + } + mask = (mask << 1) & 0xf; + r1 <<= 8; + } + HELPER_LOG("\n"); +} + +static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2) +{ + uint64_t r = d2; + + if (x2) { + r += env->regs[x2]; + } + + if (b2) { + r += env->regs[b2]; + } + + /* 31-Bit mode */ + if (!(env->psw.mask & PSW_MASK_64)) { + r &= 0x7fffffff; + } + + return r; +} + +static inline uint64_t get_address_31fix(CPUS390XState *env, int reg) +{ + uint64_t r = env->regs[reg]; + + /* 31-Bit mode */ + if (!(env->psw.mask & PSW_MASK_64)) { + r &= 0x7fffffff; + } + + return r; +} + +/* search string (c is byte to search, r2 is string, r1 end of string) */ +uint32_t HELPER(srst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) +{ + uint64_t i; + uint32_t cc = 2; + uint64_t str = get_address_31fix(env, r2); + uint64_t end = get_address_31fix(env, r1); + + HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__, + c, env->regs[r1], env->regs[r2]); + + for (i = str; i != end; i++) { + if (cpu_ldub_data(env, i) == c) { + env->regs[r1] = i; + cc = 1; + break; + } + } + + return cc; +} + +/* unsigned string compare (c is string terminator) */ +uint32_t HELPER(clst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) +{ + uint64_t s1 = get_address_31fix(env, r1); + uint64_t s2 = get_address_31fix(env, r2); + uint8_t v1, v2; + uint32_t cc; + + c = c & 0xff; +#ifdef CONFIG_USER_ONLY + if (!c) { + HELPER_LOG("%s: comparing '%s' and '%s'\n", + __func__, (char *)g2h(s1), (char *)g2h(s2)); + } +#endif + for (;;) { + v1 = cpu_ldub_data(env, s1); + v2 = cpu_ldub_data(env, s2); + if ((v1 == c || v2 == c) || (v1 != v2)) { + break; + } + s1++; + s2++; + } + + if (v1 == v2) { + cc = 0; + } else { + cc = (v1 < v2) ? 1 : 2; + /* FIXME: 31-bit mode! */ + env->regs[r1] = s1; + env->regs[r2] = s2; + } + return cc; +} + +/* move page */ +void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2) +{ + /* XXX missing r0 handling */ +#ifdef CONFIG_USER_ONLY + int i; + + for (i = 0; i < TARGET_PAGE_SIZE; i++) { + cpu_stb_data(env, r1 + i, cpu_ldub_data(env, r2 + i)); + } +#else + mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2); +#endif +} + +/* string copy (c is string terminator) */ +void HELPER(mvst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) +{ + uint64_t dest = get_address_31fix(env, r1); + uint64_t src = get_address_31fix(env, r2); + uint8_t v; + + c = c & 0xff; +#ifdef CONFIG_USER_ONLY + if (!c) { + HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src), + dest); + } +#endif + for (;;) { + v = cpu_ldub_data(env, src); + cpu_stb_data(env, dest, v); + if (v == c) { + break; + } + src++; + dest++; + } + env->regs[r1] = dest; /* FIXME: 31-bit mode! */ +} + +/* compare and swap 64-bit */ +uint32_t HELPER(csg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) +{ + /* FIXME: locking? */ + uint32_t cc; + uint64_t v2 = cpu_ldq_data(env, a2); + + if (env->regs[r1] == v2) { + cc = 0; + cpu_stq_data(env, a2, env->regs[r3]); + } else { + cc = 1; + env->regs[r1] = v2; + } + return cc; +} + +/* compare double and swap 64-bit */ +uint32_t HELPER(cdsg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) +{ + /* FIXME: locking? */ + uint32_t cc; + uint64_t v2_hi = cpu_ldq_data(env, a2); + uint64_t v2_lo = cpu_ldq_data(env, a2 + 8); + uint64_t v1_hi = env->regs[r1]; + uint64_t v1_lo = env->regs[r1 + 1]; + + if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) { + cc = 0; + cpu_stq_data(env, a2, env->regs[r3]); + cpu_stq_data(env, a2 + 8, env->regs[r3 + 1]); + } else { + cc = 1; + env->regs[r1] = v2_hi; + env->regs[r1 + 1] = v2_lo; + } + + return cc; +} + +/* compare and swap 32-bit */ +uint32_t HELPER(cs)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) +{ + /* FIXME: locking? */ + uint32_t cc; + uint32_t v2 = cpu_ldl_data(env, a2); + + HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3); + if (((uint32_t)env->regs[r1]) == v2) { + cc = 0; + cpu_stl_data(env, a2, (uint32_t)env->regs[r3]); + } else { + cc = 1; + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2; + } + return cc; +} + +static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address, + uint32_t mask) +{ + int pos = 24; /* top of the lower half of r1 */ + uint64_t rmask = 0xff000000ULL; + uint8_t val = 0; + int ccd = 0; + uint32_t cc = 0; + + while (mask) { + if (mask & 8) { + env->regs[r1] &= ~rmask; + val = cpu_ldub_data(env, address); + if ((val & 0x80) && !ccd) { + cc = 1; + } + ccd = 1; + if (val && cc == 0) { + cc = 2; + } + env->regs[r1] |= (uint64_t)val << pos; + address++; + } + mask = (mask << 1) & 0xf; + pos -= 8; + rmask >>= 8; + } + + return cc; +} + +/* execute instruction + this instruction executes an insn modified with the contents of r1 + it does not change the executed instruction in memory + it does not change the program counter + in other words: tricky... + currently implemented by interpreting the cases it is most commonly used in +*/ +uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, + uint64_t addr, uint64_t ret) +{ + uint16_t insn = cpu_lduw_code(env, addr); + + HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr, + insn); + if ((insn & 0xf0ff) == 0xd000) { + uint32_t l, insn2, b1, b2, d1, d2; + + l = v1 & 0xff; + insn2 = cpu_ldl_code(env, addr + 2); + b1 = (insn2 >> 28) & 0xf; + b2 = (insn2 >> 12) & 0xf; + d1 = (insn2 >> 16) & 0xfff; + d2 = insn2 & 0xfff; + switch (insn & 0xf00) { + case 0x200: + helper_mvc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); + break; + case 0x500: + cc = helper_clc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); + break; + case 0x700: + cc = helper_xc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); + break; + case 0xc00: + helper_tr(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); + break; + default: + goto abort; + break; + } + } else if ((insn & 0xff00) == 0x0a00) { + /* supervisor call */ + HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff); + env->psw.addr = ret - 4; + env->int_svc_code = (insn | v1) & 0xff; + env->int_svc_ilc = 4; + helper_exception(env, EXCP_SVC); + } else if ((insn & 0xff00) == 0xbf00) { + uint32_t insn2, r1, r3, b2, d2; + + insn2 = cpu_ldl_code(env, addr + 2); + r1 = (insn2 >> 20) & 0xf; + r3 = (insn2 >> 16) & 0xf; + b2 = (insn2 >> 12) & 0xf; + d2 = insn2 & 0xfff; + cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3); + } else { + abort: + cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n", + insn); + } + return cc; +} + +/* store character under mask high operates on the upper half of r1 */ +void HELPER(stcmh)(CPUS390XState *env, uint32_t r1, uint64_t address, + uint32_t mask) +{ + int pos = 56; /* top of the upper half of r1 */ + + while (mask) { + if (mask & 8) { + cpu_stb_data(env, address, (env->regs[r1] >> pos) & 0xff); + address++; + } + mask = (mask << 1) & 0xf; + pos -= 8; + } +} + +/* insert character under mask high; same as icm, but operates on the + upper half of r1 */ +uint32_t HELPER(icmh)(CPUS390XState *env, uint32_t r1, uint64_t address, + uint32_t mask) +{ + int pos = 56; /* top of the upper half of r1 */ + uint64_t rmask = 0xff00000000000000ULL; + uint8_t val = 0; + int ccd = 0; + uint32_t cc = 0; + + while (mask) { + if (mask & 8) { + env->regs[r1] &= ~rmask; + val = cpu_ldub_data(env, address); + if ((val & 0x80) && !ccd) { + cc = 1; + } + ccd = 1; + if (val && cc == 0) { + cc = 2; + } + env->regs[r1] |= (uint64_t)val << pos; + address++; + } + mask = (mask << 1) & 0xf; + pos -= 8; + rmask >>= 8; + } + + return cc; +} + +/* load access registers r1 to r3 from memory at a2 */ +void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) +{ + int i; + + for (i = r1;; i = (i + 1) % 16) { + env->aregs[i] = cpu_ldl_data(env, a2); + a2 += 4; + + if (i == r3) { + break; + } + } +} + +/* store access registers r1 to r3 in memory at a2 */ +void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) +{ + int i; + + for (i = r1;; i = (i + 1) % 16) { + cpu_stl_data(env, a2, env->aregs[i]); + a2 += 4; + + if (i == r3) { + break; + } + } +} + +/* move long */ +uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) +{ + uint64_t destlen = env->regs[r1 + 1] & 0xffffff; + uint64_t dest = get_address_31fix(env, r1); + uint64_t srclen = env->regs[r2 + 1] & 0xffffff; + uint64_t src = get_address_31fix(env, r2); + uint8_t pad = src >> 24; + uint8_t v; + uint32_t cc; + + if (destlen == srclen) { + cc = 0; + } else if (destlen < srclen) { + cc = 1; + } else { + cc = 2; + } + + if (srclen > destlen) { + srclen = destlen; + } + + for (; destlen && srclen; src++, dest++, destlen--, srclen--) { + v = cpu_ldub_data(env, src); + cpu_stb_data(env, dest, v); + } + + for (; destlen; dest++, destlen--) { + cpu_stb_data(env, dest, pad); + } + + env->regs[r1 + 1] = destlen; + /* can't use srclen here, we trunc'ed it */ + env->regs[r2 + 1] -= src - env->regs[r2]; + env->regs[r1] = dest; + env->regs[r2] = src; + + return cc; +} + +/* move long extended another memcopy insn with more bells and whistles */ +uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, + uint32_t r3) +{ + uint64_t destlen = env->regs[r1 + 1]; + uint64_t dest = env->regs[r1]; + uint64_t srclen = env->regs[r3 + 1]; + uint64_t src = env->regs[r3]; + uint8_t pad = a2 & 0xff; + uint8_t v; + uint32_t cc; + + if (!(env->psw.mask & PSW_MASK_64)) { + destlen = (uint32_t)destlen; + srclen = (uint32_t)srclen; + dest &= 0x7fffffff; + src &= 0x7fffffff; + } + + if (destlen == srclen) { + cc = 0; + } else if (destlen < srclen) { + cc = 1; + } else { + cc = 2; + } + + if (srclen > destlen) { + srclen = destlen; + } + + for (; destlen && srclen; src++, dest++, destlen--, srclen--) { + v = cpu_ldub_data(env, src); + cpu_stb_data(env, dest, v); + } + + for (; destlen; dest++, destlen--) { + cpu_stb_data(env, dest, pad); + } + + env->regs[r1 + 1] = destlen; + /* can't use srclen here, we trunc'ed it */ + /* FIXME: 31-bit mode! */ + env->regs[r3 + 1] -= src - env->regs[r3]; + env->regs[r1] = dest; + env->regs[r3] = src; + + return cc; +} + +/* compare logical long extended memcompare insn with padding */ +uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, + uint32_t r3) +{ + uint64_t destlen = env->regs[r1 + 1]; + uint64_t dest = get_address_31fix(env, r1); + uint64_t srclen = env->regs[r3 + 1]; + uint64_t src = get_address_31fix(env, r3); + uint8_t pad = a2 & 0xff; + uint8_t v1 = 0, v2 = 0; + uint32_t cc = 0; + + if (!(destlen || srclen)) { + return cc; + } + + if (srclen > destlen) { + srclen = destlen; + } + + for (; destlen || srclen; src++, dest++, destlen--, srclen--) { + v1 = srclen ? cpu_ldub_data(env, src) : pad; + v2 = destlen ? cpu_ldub_data(env, dest) : pad; + if (v1 != v2) { + cc = (v1 < v2) ? 1 : 2; + break; + } + } + + env->regs[r1 + 1] = destlen; + /* can't use srclen here, we trunc'ed it */ + env->regs[r3 + 1] -= src - env->regs[r3]; + env->regs[r1] = dest; + env->regs[r3] = src; + + return cc; +} + +/* checksum */ +void HELPER(cksm)(CPUS390XState *env, uint32_t r1, uint32_t r2) +{ + uint64_t src = get_address_31fix(env, r2); + uint64_t src_len = env->regs[(r2 + 1) & 15]; + uint64_t cksm = (uint32_t)env->regs[r1]; + + while (src_len >= 4) { + cksm += cpu_ldl_data(env, src); + + /* move to next word */ + src_len -= 4; + src += 4; + } + + switch (src_len) { + case 0: + break; + case 1: + cksm += cpu_ldub_data(env, src) << 24; + break; + case 2: + cksm += cpu_lduw_data(env, src) << 16; + break; + case 3: + cksm += cpu_lduw_data(env, src) << 16; + cksm += cpu_ldub_data(env, src + 2) << 8; + break; + } + + /* indicate we've processed everything */ + env->regs[r2] = src + src_len; + env->regs[(r2 + 1) & 15] = 0; + + /* store result */ + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | + ((uint32_t)cksm + (cksm >> 32)); +} + +void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, + uint64_t src) +{ + int len_dest = len >> 4; + int len_src = len & 0xf; + uint8_t b; + int second_nibble = 0; + + dest += len_dest; + src += len_src; + + /* last byte is special, it only flips the nibbles */ + b = cpu_ldub_data(env, src); + cpu_stb_data(env, dest, (b << 4) | (b >> 4)); + src--; + len_src--; + + /* now pad every nibble with 0xf0 */ + + while (len_dest > 0) { + uint8_t cur_byte = 0; + + if (len_src > 0) { + cur_byte = cpu_ldub_data(env, src); + } + + len_dest--; + dest--; + + /* only advance one nibble at a time */ + if (second_nibble) { + cur_byte >>= 4; + len_src--; + src--; + } + second_nibble = !second_nibble; + + /* digit */ + cur_byte = (cur_byte & 0xf); + /* zone bits */ + cur_byte |= 0xf0; + + cpu_stb_data(env, dest, cur_byte); + } +} + +void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array, + uint64_t trans) +{ + int i; + + for (i = 0; i <= len; i++) { + uint8_t byte = cpu_ldub_data(env, array + i); + uint8_t new_byte = cpu_ldub_data(env, trans + byte); + + cpu_stb_data(env, array + i, new_byte); + } +} + +#if !defined(CONFIG_USER_ONLY) +void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) +{ + int i; + uint64_t src = a2; + + for (i = r1;; i = (i + 1) % 16) { + env->cregs[i] = cpu_ldq_data(env, src); + HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n", + i, src, env->cregs[i]); + src += sizeof(uint64_t); + + if (i == r3) { + break; + } + } + + tlb_flush(env, 1); +} + +void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) +{ + int i; + uint64_t src = a2; + + for (i = r1;; i = (i + 1) % 16) { + env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | + cpu_ldl_data(env, src); + src += sizeof(uint32_t); + + if (i == r3) { + break; + } + } + + tlb_flush(env, 1); +} + +void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) +{ + int i; + uint64_t dest = a2; + + for (i = r1;; i = (i + 1) % 16) { + cpu_stq_data(env, dest, env->cregs[i]); + dest += sizeof(uint64_t); + + if (i == r3) { + break; + } + } +} + +void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) +{ + int i; + uint64_t dest = a2; + + for (i = r1;; i = (i + 1) % 16) { + cpu_stl_data(env, dest, env->cregs[i]); + dest += sizeof(uint32_t); + + if (i == r3) { + break; + } + } +} + +uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2) +{ + /* XXX implement */ + + return 0; +} + +/* insert storage key extended */ +uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2) +{ + uint64_t addr = get_address(env, 0, 0, r2); + + if (addr > ram_size) { + return 0; + } + + return env->storage_keys[addr / TARGET_PAGE_SIZE]; +} + +/* set storage key extended */ +void HELPER(sske)(CPUS390XState *env, uint32_t r1, uint64_t r2) +{ + uint64_t addr = get_address(env, 0, 0, r2); + + if (addr > ram_size) { + return; + } + + env->storage_keys[addr / TARGET_PAGE_SIZE] = r1; +} + +/* reset reference bit extended */ +uint32_t HELPER(rrbe)(CPUS390XState *env, uint32_t r1, uint64_t r2) +{ + uint8_t re; + uint8_t key; + + if (r2 > ram_size) { + return 0; + } + + key = env->storage_keys[r2 / TARGET_PAGE_SIZE]; + re = key & (SK_R | SK_C); + env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R); + + /* + * cc + * + * 0 Reference bit zero; change bit zero + * 1 Reference bit zero; change bit one + * 2 Reference bit one; change bit zero + * 3 Reference bit one; change bit one + */ + + return re >> 1; +} + +/* compare and swap and purge */ +uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint32_t r2) +{ + uint32_t cc; + uint32_t o1 = env->regs[r1]; + uint64_t a2 = get_address_31fix(env, r2) & ~3ULL; + uint32_t o2 = cpu_ldl_data(env, a2); + + if (o1 == o2) { + cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]); + if (env->regs[r2] & 0x3) { + /* flush TLB / ALB */ + tlb_flush(env, 1); + } + cc = 0; + } else { + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2; + cc = 1; + } + + return cc; +} + +static uint32_t mvc_asc(CPUS390XState *env, int64_t l, uint64_t a1, + uint64_t mode1, uint64_t a2, uint64_t mode2) +{ + target_ulong src, dest; + int flags, cc = 0, i; + + if (!l) { + return 0; + } else if (l > 256) { + /* max 256 */ + l = 256; + cc = 3; + } + + if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) { + cpu_loop_exit(env); + } + dest |= a1 & ~TARGET_PAGE_MASK; + + if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) { + cpu_loop_exit(env); + } + src |= a2 & ~TARGET_PAGE_MASK; + + /* XXX replace w/ memcpy */ + for (i = 0; i < l; i++) { + /* XXX be more clever */ + if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) || + (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) { + mvc_asc(env, l - i, a1 + i, mode1, a2 + i, mode2); + break; + } + stb_phys(dest + i, ldub_phys(src + i)); + } + + return cc; +} + +uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) +{ + HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", + __func__, l, a1, a2); + + return mvc_asc(env, l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY); +} + +uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) +{ + HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", + __func__, l, a1, a2); + + return mvc_asc(env, l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY); +} + +/* invalidate pte */ +void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr) +{ + uint64_t page = vaddr & TARGET_PAGE_MASK; + uint64_t pte = 0; + + /* XXX broadcast to other CPUs */ + + /* XXX Linux is nice enough to give us the exact pte address. + According to spec we'd have to find it out ourselves */ + /* XXX Linux is fine with overwriting the pte, the spec requires + us to only set the invalid bit */ + stq_phys(pte_addr, pte | _PAGE_INVALID); + + /* XXX we exploit the fact that Linux passes the exact virtual + address here - it's not obliged to! */ + tlb_flush_page(env, page); + + /* XXX 31-bit hack */ + if (page & 0x80000000) { + tlb_flush_page(env, page & ~0x80000000); + } else { + tlb_flush_page(env, page | 0x80000000); + } +} + +/* flush local tlb */ +void HELPER(ptlb)(CPUS390XState *env) +{ + tlb_flush(env, 1); +} + +/* store using real address */ +void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint32_t v1) +{ + stw_phys(get_address(env, 0, 0, addr), v1); +} + +/* load real address */ +uint32_t HELPER(lra)(CPUS390XState *env, uint64_t addr, uint32_t r1) +{ + uint32_t cc = 0; + int old_exc = env->exception_index; + uint64_t asc = env->psw.mask & PSW_MASK_ASC; + uint64_t ret; + int flags; + + /* XXX incomplete - has more corner cases */ + if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) { + program_interrupt(env, PGM_SPECIAL_OP, 2); + } + + env->exception_index = old_exc; + if (mmu_translate(env, addr, 0, asc, &ret, &flags)) { + cc = 3; + } + if (env->exception_index == EXCP_PGM) { + ret = env->int_pgm_code | 0x80000000; + } else { + ret |= addr & ~TARGET_PAGE_MASK; + } + env->exception_index = old_exc; + + if (!(env->psw.mask & PSW_MASK_64)) { + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | + (ret & 0xffffffffULL); + } else { + env->regs[r1] = ret; + } + + return cc; +} + +#endif diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c new file mode 100644 index 0000000..2938ac9 --- /dev/null +++ b/target-s390x/misc_helper.c @@ -0,0 +1,430 @@ +/* + * S/390 misc helper routines + * + * Copyright (c) 2009 Ulrich Hecht + * Copyright (c) 2009 Alexander Graf + * + * 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 "cpu.h" +#include "memory.h" +#include "cputlb.h" +#include "host-utils.h" +#include "helper.h" +#include <string.h> +#include "kvm.h" +#include "qemu-timer.h" +#ifdef CONFIG_KVM +#include <linux/kvm.h> +#endif + +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#include "sysemu.h" +#endif + +/* #define DEBUG_HELPER */ +#ifdef DEBUG_HELPER +#define HELPER_LOG(x...) qemu_log(x) +#else +#define HELPER_LOG(x...) +#endif + +/* raise an exception */ +void HELPER(exception)(CPUS390XState *env, uint32_t excp) +{ + HELPER_LOG("%s: exception %d\n", __func__, excp); + env->exception_index = excp; + cpu_loop_exit(env); +} + +#ifndef CONFIG_USER_ONLY +void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) +{ + qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr); + + if (kvm_enabled()) { +#ifdef CONFIG_KVM + kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code); +#endif + } else { + env->int_pgm_code = code; + env->int_pgm_ilc = ilc; + env->exception_index = EXCP_PGM; + cpu_loop_exit(env); + } +} + +/* + * ret < 0 indicates program check, ret = 0, 1, 2, 3 -> cc + */ +int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) +{ + int r = 0; + int shift = 0; + +#ifdef DEBUG_HELPER + printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code); +#endif + + /* basic checks */ + if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) { + return -PGM_ADDRESSING; + } + if (sccb & ~0x7ffffff8ul) { + return -PGM_SPECIFICATION; + } + + switch (code) { + case SCLP_CMDW_READ_SCP_INFO: + case SCLP_CMDW_READ_SCP_INFO_FORCED: + while ((ram_size >> (20 + shift)) > 65535) { + shift++; + } + stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift)); + stb_phys(sccb + SCP_INCREMENT, 1 << shift); + stw_phys(sccb + SCP_RESPONSE_CODE, 0x10); + + s390_sclp_extint(sccb & ~3); + break; + default: +#ifdef DEBUG_HELPER + printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code); +#endif + r = 3; + break; + } + + return r; +} + +/* SCLP service call */ +uint32_t HELPER(servc)(CPUS390XState *env, uint32_t r1, uint64_t r2) +{ + int r; + + r = sclp_service_call(env, r1, r2); + if (r < 0) { + program_interrupt(env, -r, 4); + return 0; + } + return r; +} + +/* DIAG */ +uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem, + uint64_t code) +{ + uint64_t r; + + switch (num) { + case 0x500: + /* KVM hypercall */ + r = s390_virtio_hypercall(env, mem, code); + break; + case 0x44: + /* yield */ + r = 0; + break; + case 0x308: + /* ipl */ + r = 0; + break; + default: + r = -1; + break; + } + + if (r) { + program_interrupt(env, PGM_OPERATION, ILC_LATER_INC); + } + + return r; +} + +/* Store CPU ID */ +void HELPER(stidp)(CPUS390XState *env, uint64_t a1) +{ + cpu_stq_data(env, a1, env->cpu_num); +} + +/* Set Prefix */ +void HELPER(spx)(CPUS390XState *env, uint64_t a1) +{ + uint32_t prefix; + + prefix = cpu_ldl_data(env, a1); + env->psa = prefix & 0xfffff000; + qemu_log("prefix: %#x\n", prefix); + tlb_flush_page(env, 0); + tlb_flush_page(env, TARGET_PAGE_SIZE); +} + +/* Set Clock */ +uint32_t HELPER(sck)(uint64_t a1) +{ + /* XXX not implemented - is it necessary? */ + + return 0; +} + +static inline uint64_t clock_value(CPUS390XState *env) +{ + uint64_t time; + + time = env->tod_offset + + time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime); + + return time; +} + +/* Store Clock */ +uint32_t HELPER(stck)(CPUS390XState *env, uint64_t a1) +{ + cpu_stq_data(env, a1, clock_value(env)); + + return 0; +} + +/* Store Clock Extended */ +uint32_t HELPER(stcke)(CPUS390XState *env, uint64_t a1) +{ + cpu_stb_data(env, a1, 0); + /* basically the same value as stck */ + cpu_stq_data(env, a1 + 1, clock_value(env) | env->cpu_num); + /* more fine grained than stck */ + cpu_stq_data(env, a1 + 9, 0); + /* XXX programmable fields */ + cpu_stw_data(env, a1 + 17, 0); + + return 0; +} + +/* Set Clock Comparator */ +void HELPER(sckc)(CPUS390XState *env, uint64_t a1) +{ + uint64_t time = cpu_ldq_data(env, a1); + + if (time == -1ULL) { + return; + } + + /* difference between now and then */ + time -= clock_value(env); + /* nanoseconds */ + time = (time * 125) >> 9; + + qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time); +} + +/* Store Clock Comparator */ +void HELPER(stckc)(CPUS390XState *env, uint64_t a1) +{ + /* XXX implement */ + cpu_stq_data(env, a1, 0); +} + +/* Set CPU Timer */ +void HELPER(spt)(CPUS390XState *env, uint64_t a1) +{ + uint64_t time = cpu_ldq_data(env, a1); + + if (time == -1ULL) { + return; + } + + /* nanoseconds */ + time = (time * 125) >> 9; + + qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time); +} + +/* Store CPU Timer */ +void HELPER(stpt)(CPUS390XState *env, uint64_t a1) +{ + /* XXX implement */ + cpu_stq_data(env, a1, 0); +} + +/* Store System Information */ +uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint32_t r0, + uint32_t r1) +{ + int cc = 0; + int sel1, sel2; + + if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 && + ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) { + /* valid function code, invalid reserved bits */ + program_interrupt(env, PGM_SPECIFICATION, 2); + } + + sel1 = r0 & STSI_R0_SEL1_MASK; + sel2 = r1 & STSI_R1_SEL2_MASK; + + /* XXX: spec exception if sysib is not 4k-aligned */ + + switch (r0 & STSI_LEVEL_MASK) { + case STSI_LEVEL_1: + if ((sel1 == 1) && (sel2 == 1)) { + /* Basic Machine Configuration */ + struct sysib_111 sysib; + + memset(&sysib, 0, sizeof(sysib)); + ebcdic_put(sysib.manuf, "QEMU ", 16); + /* same as machine type number in STORE CPU ID */ + ebcdic_put(sysib.type, "QEMU", 4); + /* same as model number in STORE CPU ID */ + ebcdic_put(sysib.model, "QEMU ", 16); + ebcdic_put(sysib.sequence, "QEMU ", 16); + ebcdic_put(sysib.plant, "QEMU", 4); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else if ((sel1 == 2) && (sel2 == 1)) { + /* Basic Machine CPU */ + struct sysib_121 sysib; + + memset(&sysib, 0, sizeof(sysib)); + /* XXX make different for different CPUs? */ + ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); + ebcdic_put(sysib.plant, "QEMU", 4); + stw_p(&sysib.cpu_addr, env->cpu_num); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else if ((sel1 == 2) && (sel2 == 2)) { + /* Basic Machine CPUs */ + struct sysib_122 sysib; + + memset(&sysib, 0, sizeof(sysib)); + stl_p(&sysib.capability, 0x443afc29); + /* XXX change when SMP comes */ + stw_p(&sysib.total_cpus, 1); + stw_p(&sysib.active_cpus, 1); + stw_p(&sysib.standby_cpus, 0); + stw_p(&sysib.reserved_cpus, 0); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else { + cc = 3; + } + break; + case STSI_LEVEL_2: + { + if ((sel1 == 2) && (sel2 == 1)) { + /* LPAR CPU */ + struct sysib_221 sysib; + + memset(&sysib, 0, sizeof(sysib)); + /* XXX make different for different CPUs? */ + ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); + ebcdic_put(sysib.plant, "QEMU", 4); + stw_p(&sysib.cpu_addr, env->cpu_num); + stw_p(&sysib.cpu_id, 0); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else if ((sel1 == 2) && (sel2 == 2)) { + /* LPAR CPUs */ + struct sysib_222 sysib; + + memset(&sysib, 0, sizeof(sysib)); + stw_p(&sysib.lpar_num, 0); + sysib.lcpuc = 0; + /* XXX change when SMP comes */ + stw_p(&sysib.total_cpus, 1); + stw_p(&sysib.conf_cpus, 1); + stw_p(&sysib.standby_cpus, 0); + stw_p(&sysib.reserved_cpus, 0); + ebcdic_put(sysib.name, "QEMU ", 8); + stl_p(&sysib.caf, 1000); + stw_p(&sysib.dedicated_cpus, 0); + stw_p(&sysib.shared_cpus, 0); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else { + cc = 3; + } + break; + } + case STSI_LEVEL_3: + { + if ((sel1 == 2) && (sel2 == 2)) { + /* VM CPUs */ + struct sysib_322 sysib; + + memset(&sysib, 0, sizeof(sysib)); + sysib.count = 1; + /* XXX change when SMP comes */ + stw_p(&sysib.vm[0].total_cpus, 1); + stw_p(&sysib.vm[0].conf_cpus, 1); + stw_p(&sysib.vm[0].standby_cpus, 0); + stw_p(&sysib.vm[0].reserved_cpus, 0); + ebcdic_put(sysib.vm[0].name, "KVMguest", 8); + stl_p(&sysib.vm[0].caf, 1000); + ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16); + cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else { + cc = 3; + } + break; + } + case STSI_LEVEL_CURRENT: + env->regs[0] = STSI_LEVEL_3; + break; + default: + cc = 3; + break; + } + + return cc; +} + +uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1, + uint64_t cpu_addr) +{ + int cc = 0; + + HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n", + __func__, order_code, r1, cpu_addr); + + /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register" + as parameter (input). Status (output) is always R1. */ + + switch (order_code) { + case SIGP_SET_ARCH: + /* switch arch */ + break; + case SIGP_SENSE: + /* enumerate CPU status */ + if (cpu_addr) { + /* XXX implement when SMP comes */ + return 3; + } + env->regs[r1] &= 0xffffffff00000000ULL; + cc = 1; + break; +#if !defined(CONFIG_USER_ONLY) + case SIGP_RESTART: + qemu_system_reset_request(); + cpu_loop_exit(env); + break; + case SIGP_STOP: + qemu_system_shutdown_request(); + cpu_loop_exit(env); + break; +#endif + default: + /* unknown sigp */ + fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code); + cc = 3; + } + + return cc; +} +#endif diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c deleted file mode 100644 index abc35dd..0000000 --- a/target-s390x/op_helper.c +++ /dev/null @@ -1,3019 +0,0 @@ -/* - * S/390 helper routines - * - * Copyright (c) 2009 Ulrich Hecht - * Copyright (c) 2009 Alexander Graf - * - * 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 "cpu.h" -#include "memory.h" -#include "cputlb.h" -#include "dyngen-exec.h" -#include "host-utils.h" -#include "helper.h" -#include <string.h> -#include "kvm.h" -#include "qemu-timer.h" -#ifdef CONFIG_KVM -#include <linux/kvm.h> -#endif - -#if !defined (CONFIG_USER_ONLY) -#include "sysemu.h" -#endif - -/*****************************************************************************/ -/* Softmmu support */ -#if !defined (CONFIG_USER_ONLY) -#include "softmmu_exec.h" - -#define MMUSUFFIX _mmu - -#define SHIFT 0 -#include "softmmu_template.h" - -#define SHIFT 1 -#include "softmmu_template.h" - -#define SHIFT 2 -#include "softmmu_template.h" - -#define SHIFT 3 -#include "softmmu_template.h" - -/* try to fill the TLB and return an exception if error. If retaddr is - NULL, it means that the function was called in C code (i.e. not - from generated code or from helper.c) */ -/* XXX: fix it to restore all registers */ -void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx, - uintptr_t retaddr) -{ - TranslationBlock *tb; - CPUS390XState *saved_env; - int ret; - - saved_env = env; - env = env1; - ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx); - if (unlikely(ret != 0)) { - if (likely(retaddr)) { - /* now we have a real cpu fault */ - tb = tb_find_pc(retaddr); - if (likely(tb)) { - /* the PC is inside the translated code. It means that we have - a virtual CPU fault */ - cpu_restore_state(tb, env, retaddr); - } - } - cpu_loop_exit(env); - } - env = saved_env; -} - -#endif - -/* #define DEBUG_HELPER */ -#ifdef DEBUG_HELPER -#define HELPER_LOG(x...) qemu_log(x) -#else -#define HELPER_LOG(x...) -#endif - -/* raise an exception */ -void HELPER(exception)(uint32_t excp) -{ - HELPER_LOG("%s: exception %d\n", __FUNCTION__, excp); - env->exception_index = excp; - cpu_loop_exit(env); -} - -#ifndef CONFIG_USER_ONLY -static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest, - uint8_t byte) -{ - target_phys_addr_t dest_phys; - target_phys_addr_t len = l; - void *dest_p; - uint64_t asc = env->psw.mask & PSW_MASK_ASC; - int flags; - - if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { - stb(dest, byte); - cpu_abort(env, "should never reach here"); - } - dest_phys |= dest & ~TARGET_PAGE_MASK; - - dest_p = cpu_physical_memory_map(dest_phys, &len, 1); - - memset(dest_p, byte, len); - - cpu_physical_memory_unmap(dest_p, 1, len, len); -} - -static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest, - uint64_t src) -{ - target_phys_addr_t dest_phys; - target_phys_addr_t src_phys; - target_phys_addr_t len = l; - void *dest_p; - void *src_p; - uint64_t asc = env->psw.mask & PSW_MASK_ASC; - int flags; - - if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { - stb(dest, 0); - cpu_abort(env, "should never reach here"); - } - dest_phys |= dest & ~TARGET_PAGE_MASK; - - if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) { - ldub(src); - cpu_abort(env, "should never reach here"); - } - src_phys |= src & ~TARGET_PAGE_MASK; - - dest_p = cpu_physical_memory_map(dest_phys, &len, 1); - src_p = cpu_physical_memory_map(src_phys, &len, 0); - - memmove(dest_p, src_p, len); - - cpu_physical_memory_unmap(dest_p, 1, len, len); - cpu_physical_memory_unmap(src_p, 0, len, len); -} -#endif - -/* and on array */ -uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src) -{ - int i; - unsigned char x; - uint32_t cc = 0; - - HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", - __FUNCTION__, l, dest, src); - for (i = 0; i <= l; i++) { - x = ldub(dest + i) & ldub(src + i); - if (x) { - cc = 1; - } - stb(dest + i, x); - } - return cc; -} - -/* xor on array */ -uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src) -{ - int i; - unsigned char x; - uint32_t cc = 0; - - HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", - __FUNCTION__, l, dest, src); - -#ifndef CONFIG_USER_ONLY - /* xor with itself is the same as memset(0) */ - if ((l > 32) && (src == dest) && - (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) { - mvc_fast_memset(env, l + 1, dest, 0); - return 0; - } -#else - if (src == dest) { - memset(g2h(dest), 0, l + 1); - return 0; - } -#endif - - for (i = 0; i <= l; i++) { - x = ldub(dest + i) ^ ldub(src + i); - if (x) { - cc = 1; - } - stb(dest + i, x); - } - return cc; -} - -/* or on array */ -uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src) -{ - int i; - unsigned char x; - uint32_t cc = 0; - - HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", - __FUNCTION__, l, dest, src); - for (i = 0; i <= l; i++) { - x = ldub(dest + i) | ldub(src + i); - if (x) { - cc = 1; - } - stb(dest + i, x); - } - return cc; -} - -/* memmove */ -void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) -{ - int i = 0; - int x = 0; - uint32_t l_64 = (l + 1) / 8; - - HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", - __FUNCTION__, l, dest, src); - -#ifndef CONFIG_USER_ONLY - if ((l > 32) && - (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) && - (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) { - if (dest == (src + 1)) { - mvc_fast_memset(env, l + 1, dest, ldub(src)); - return; - } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) { - mvc_fast_memmove(env, l + 1, dest, src); - return; - } - } -#else - if (dest == (src + 1)) { - memset(g2h(dest), ldub(src), l + 1); - return; - } else { - memmove(g2h(dest), g2h(src), l + 1); - return; - } -#endif - - /* handle the parts that fit into 8-byte loads/stores */ - if (dest != (src + 1)) { - for (i = 0; i < l_64; i++) { - stq(dest + x, ldq(src + x)); - x += 8; - } - } - - /* slow version crossing pages with byte accesses */ - for (i = x; i <= l; i++) { - stb(dest + i, ldub(src + i)); - } -} - -/* compare unsigned byte arrays */ -uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) -{ - int i; - unsigned char x,y; - uint32_t cc; - HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n", - __FUNCTION__, l, s1, s2); - for (i = 0; i <= l; i++) { - x = ldub(s1 + i); - y = ldub(s2 + i); - HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y); - if (x < y) { - cc = 1; - goto done; - } else if (x > y) { - cc = 2; - goto done; - } - } - cc = 0; -done: - HELPER_LOG("\n"); - return cc; -} - -/* compare logical under mask */ -uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) -{ - uint8_t r,d; - uint32_t cc; - HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __FUNCTION__, r1, - mask, addr); - cc = 0; - while (mask) { - if (mask & 8) { - d = ldub(addr); - r = (r1 & 0xff000000UL) >> 24; - HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d, - addr); - if (r < d) { - cc = 1; - break; - } else if (r > d) { - cc = 2; - break; - } - addr++; - } - mask = (mask << 1) & 0xf; - r1 <<= 8; - } - HELPER_LOG("\n"); - return cc; -} - -/* store character under mask */ -void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) -{ - uint8_t r; - HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __FUNCTION__, r1, mask, - addr); - while (mask) { - if (mask & 8) { - r = (r1 & 0xff000000UL) >> 24; - stb(addr, r); - HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr); - addr++; - } - mask = (mask << 1) & 0xf; - r1 <<= 8; - } - HELPER_LOG("\n"); -} - -/* 64/64 -> 128 unsigned multiplication */ -void HELPER(mlg)(uint32_t r1, uint64_t v2) -{ -#if HOST_LONG_BITS == 64 && defined(__GNUC__) - /* assuming 64-bit hosts have __uint128_t */ - __uint128_t res = (__uint128_t)env->regs[r1 + 1]; - res *= (__uint128_t)v2; - env->regs[r1] = (uint64_t)(res >> 64); - env->regs[r1 + 1] = (uint64_t)res; -#else - mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2); -#endif -} - -/* 128 -> 64/64 unsigned division */ -void HELPER(dlg)(uint32_t r1, uint64_t v2) -{ - uint64_t divisor = v2; - - if (!env->regs[r1]) { - /* 64 -> 64/64 case */ - env->regs[r1] = env->regs[r1+1] % divisor; - env->regs[r1+1] = env->regs[r1+1] / divisor; - return; - } else { - -#if HOST_LONG_BITS == 64 && defined(__GNUC__) - /* assuming 64-bit hosts have __uint128_t */ - __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | - (env->regs[r1+1]); - __uint128_t quotient = dividend / divisor; - env->regs[r1+1] = quotient; - __uint128_t remainder = dividend % divisor; - env->regs[r1] = remainder; -#else - /* 32-bit hosts would need special wrapper functionality - just abort if - we encounter such a case; it's very unlikely anyways. */ - cpu_abort(env, "128 -> 64/64 division not implemented\n"); -#endif - } -} - -static inline uint64_t get_address(int x2, int b2, int d2) -{ - uint64_t r = d2; - - if (x2) { - r += env->regs[x2]; - } - - if (b2) { - r += env->regs[b2]; - } - - /* 31-Bit mode */ - if (!(env->psw.mask & PSW_MASK_64)) { - r &= 0x7fffffff; - } - - return r; -} - -static inline uint64_t get_address_31fix(int reg) -{ - uint64_t r = env->regs[reg]; - - /* 31-Bit mode */ - if (!(env->psw.mask & PSW_MASK_64)) { - r &= 0x7fffffff; - } - - return r; -} - -/* search string (c is byte to search, r2 is string, r1 end of string) */ -uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2) -{ - uint64_t i; - uint32_t cc = 2; - uint64_t str = get_address_31fix(r2); - uint64_t end = get_address_31fix(r1); - - HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __FUNCTION__, - c, env->regs[r1], env->regs[r2]); - - for (i = str; i != end; i++) { - if (ldub(i) == c) { - env->regs[r1] = i; - cc = 1; - break; - } - } - - return cc; -} - -/* unsigned string compare (c is string terminator) */ -uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) -{ - uint64_t s1 = get_address_31fix(r1); - uint64_t s2 = get_address_31fix(r2); - uint8_t v1, v2; - uint32_t cc; - c = c & 0xff; -#ifdef CONFIG_USER_ONLY - if (!c) { - HELPER_LOG("%s: comparing '%s' and '%s'\n", - __FUNCTION__, (char*)g2h(s1), (char*)g2h(s2)); - } -#endif - for (;;) { - v1 = ldub(s1); - v2 = ldub(s2); - if ((v1 == c || v2 == c) || (v1 != v2)) { - break; - } - s1++; - s2++; - } - - if (v1 == v2) { - cc = 0; - } else { - cc = (v1 < v2) ? 1 : 2; - /* FIXME: 31-bit mode! */ - env->regs[r1] = s1; - env->regs[r2] = s2; - } - return cc; -} - -/* move page */ -void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2) -{ - /* XXX missing r0 handling */ -#ifdef CONFIG_USER_ONLY - int i; - - for (i = 0; i < TARGET_PAGE_SIZE; i++) { - stb(r1 + i, ldub(r2 + i)); - } -#else - mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2); -#endif -} - -/* string copy (c is string terminator) */ -void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) -{ - uint64_t dest = get_address_31fix(r1); - uint64_t src = get_address_31fix(r2); - uint8_t v; - c = c & 0xff; -#ifdef CONFIG_USER_ONLY - if (!c) { - HELPER_LOG("%s: copy '%s' to 0x%lx\n", __FUNCTION__, (char*)g2h(src), - dest); - } -#endif - for (;;) { - v = ldub(src); - stb(dest, v); - if (v == c) { - break; - } - src++; - dest++; - } - env->regs[r1] = dest; /* FIXME: 31-bit mode! */ -} - -/* compare and swap 64-bit */ -uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - /* FIXME: locking? */ - uint32_t cc; - uint64_t v2 = ldq(a2); - if (env->regs[r1] == v2) { - cc = 0; - stq(a2, env->regs[r3]); - } else { - cc = 1; - env->regs[r1] = v2; - } - return cc; -} - -/* compare double and swap 64-bit */ -uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - /* FIXME: locking? */ - uint32_t cc; - uint64_t v2_hi = ldq(a2); - uint64_t v2_lo = ldq(a2 + 8); - uint64_t v1_hi = env->regs[r1]; - uint64_t v1_lo = env->regs[r1 + 1]; - - if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) { - cc = 0; - stq(a2, env->regs[r3]); - stq(a2 + 8, env->regs[r3 + 1]); - } else { - cc = 1; - env->regs[r1] = v2_hi; - env->regs[r1 + 1] = v2_lo; - } - - return cc; -} - -/* compare and swap 32-bit */ -uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - /* FIXME: locking? */ - uint32_t cc; - HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __FUNCTION__, r1, a2, r3); - uint32_t v2 = ldl(a2); - if (((uint32_t)env->regs[r1]) == v2) { - cc = 0; - stl(a2, (uint32_t)env->regs[r3]); - } else { - cc = 1; - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2; - } - return cc; -} - -static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask) -{ - int pos = 24; /* top of the lower half of r1 */ - uint64_t rmask = 0xff000000ULL; - uint8_t val = 0; - int ccd = 0; - uint32_t cc = 0; - - while (mask) { - if (mask & 8) { - env->regs[r1] &= ~rmask; - val = ldub(address); - if ((val & 0x80) && !ccd) { - cc = 1; - } - ccd = 1; - if (val && cc == 0) { - cc = 2; - } - env->regs[r1] |= (uint64_t)val << pos; - address++; - } - mask = (mask << 1) & 0xf; - pos -= 8; - rmask >>= 8; - } - - return cc; -} - -/* execute instruction - this instruction executes an insn modified with the contents of r1 - it does not change the executed instruction in memory - it does not change the program counter - in other words: tricky... - currently implemented by interpreting the cases it is most commonly used in - */ -uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) -{ - uint16_t insn = lduw_code(addr); - HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __FUNCTION__, v1, addr, - insn); - if ((insn & 0xf0ff) == 0xd000) { - uint32_t l, insn2, b1, b2, d1, d2; - l = v1 & 0xff; - insn2 = ldl_code(addr + 2); - b1 = (insn2 >> 28) & 0xf; - b2 = (insn2 >> 12) & 0xf; - d1 = (insn2 >> 16) & 0xfff; - d2 = insn2 & 0xfff; - switch (insn & 0xf00) { - case 0x200: - helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2)); - break; - case 0x500: - cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2)); - break; - case 0x700: - cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2)); - break; - case 0xc00: - helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2)); - break; - default: - goto abort; - break; - } - } else if ((insn & 0xff00) == 0x0a00) { - /* supervisor call */ - HELPER_LOG("%s: svc %ld via execute\n", __FUNCTION__, (insn|v1) & 0xff); - env->psw.addr = ret - 4; - env->int_svc_code = (insn|v1) & 0xff; - env->int_svc_ilc = 4; - helper_exception(EXCP_SVC); - } else if ((insn & 0xff00) == 0xbf00) { - uint32_t insn2, r1, r3, b2, d2; - insn2 = ldl_code(addr + 2); - r1 = (insn2 >> 20) & 0xf; - r3 = (insn2 >> 16) & 0xf; - b2 = (insn2 >> 12) & 0xf; - d2 = insn2 & 0xfff; - cc = helper_icm(r1, get_address(0, b2, d2), r3); - } else { -abort: - cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n", - insn); - } - return cc; -} - -/* absolute value 32-bit */ -uint32_t HELPER(abs_i32)(int32_t val) -{ - if (val < 0) { - return -val; - } else { - return val; - } -} - -/* negative absolute value 32-bit */ -int32_t HELPER(nabs_i32)(int32_t val) -{ - if (val < 0) { - return val; - } else { - return -val; - } -} - -/* absolute value 64-bit */ -uint64_t HELPER(abs_i64)(int64_t val) -{ - HELPER_LOG("%s: val 0x%" PRIx64 "\n", __FUNCTION__, val); - - if (val < 0) { - return -val; - } else { - return val; - } -} - -/* negative absolute value 64-bit */ -int64_t HELPER(nabs_i64)(int64_t val) -{ - if (val < 0) { - return val; - } else { - return -val; - } -} - -/* add with carry 32-bit unsigned */ -uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2) -{ - uint32_t res; - - res = v1 + v2; - if (cc & 2) { - res++; - } - - return res; -} - -/* store character under mask high operates on the upper half of r1 */ -void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask) -{ - int pos = 56; /* top of the upper half of r1 */ - - while (mask) { - if (mask & 8) { - stb(address, (env->regs[r1] >> pos) & 0xff); - address++; - } - mask = (mask << 1) & 0xf; - pos -= 8; - } -} - -/* insert character under mask high; same as icm, but operates on the - upper half of r1 */ -uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) -{ - int pos = 56; /* top of the upper half of r1 */ - uint64_t rmask = 0xff00000000000000ULL; - uint8_t val = 0; - int ccd = 0; - uint32_t cc = 0; - - while (mask) { - if (mask & 8) { - env->regs[r1] &= ~rmask; - val = ldub(address); - if ((val & 0x80) && !ccd) { - cc = 1; - } - ccd = 1; - if (val && cc == 0) { - cc = 2; - } - env->regs[r1] |= (uint64_t)val << pos; - address++; - } - mask = (mask << 1) & 0xf; - pos -= 8; - rmask >>= 8; - } - - return cc; -} - -/* insert psw mask and condition code into r1 */ -void HELPER(ipm)(uint32_t cc, uint32_t r1) -{ - uint64_t r = env->regs[r1]; - - r &= 0xffffffff00ffffffULL; - r |= (cc << 28) | ( (env->psw.mask >> 40) & 0xf ); - env->regs[r1] = r; - HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __FUNCTION__, - cc, env->psw.mask, r); -} - -/* load access registers r1 to r3 from memory at a2 */ -void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - int i; - - for (i = r1;; i = (i + 1) % 16) { - env->aregs[i] = ldl(a2); - a2 += 4; - - if (i == r3) { - break; - } - } -} - -/* store access registers r1 to r3 in memory at a2 */ -void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - int i; - - for (i = r1;; i = (i + 1) % 16) { - stl(a2, env->aregs[i]); - a2 += 4; - - if (i == r3) { - break; - } - } -} - -/* move long */ -uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2) -{ - uint64_t destlen = env->regs[r1 + 1] & 0xffffff; - uint64_t dest = get_address_31fix(r1); - uint64_t srclen = env->regs[r2 + 1] & 0xffffff; - uint64_t src = get_address_31fix(r2); - uint8_t pad = src >> 24; - uint8_t v; - uint32_t cc; - - if (destlen == srclen) { - cc = 0; - } else if (destlen < srclen) { - cc = 1; - } else { - cc = 2; - } - - if (srclen > destlen) { - srclen = destlen; - } - - for (; destlen && srclen; src++, dest++, destlen--, srclen--) { - v = ldub(src); - stb(dest, v); - } - - for (; destlen; dest++, destlen--) { - stb(dest, pad); - } - - env->regs[r1 + 1] = destlen; - /* can't use srclen here, we trunc'ed it */ - env->regs[r2 + 1] -= src - env->regs[r2]; - env->regs[r1] = dest; - env->regs[r2] = src; - - return cc; -} - -/* move long extended another memcopy insn with more bells and whistles */ -uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - uint64_t destlen = env->regs[r1 + 1]; - uint64_t dest = env->regs[r1]; - uint64_t srclen = env->regs[r3 + 1]; - uint64_t src = env->regs[r3]; - uint8_t pad = a2 & 0xff; - uint8_t v; - uint32_t cc; - - if (!(env->psw.mask & PSW_MASK_64)) { - destlen = (uint32_t)destlen; - srclen = (uint32_t)srclen; - dest &= 0x7fffffff; - src &= 0x7fffffff; - } - - if (destlen == srclen) { - cc = 0; - } else if (destlen < srclen) { - cc = 1; - } else { - cc = 2; - } - - if (srclen > destlen) { - srclen = destlen; - } - - for (; destlen && srclen; src++, dest++, destlen--, srclen--) { - v = ldub(src); - stb(dest, v); - } - - for (; destlen; dest++, destlen--) { - stb(dest, pad); - } - - env->regs[r1 + 1] = destlen; - /* can't use srclen here, we trunc'ed it */ - /* FIXME: 31-bit mode! */ - env->regs[r3 + 1] -= src - env->regs[r3]; - env->regs[r1] = dest; - env->regs[r3] = src; - - return cc; -} - -/* compare logical long extended memcompare insn with padding */ -uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - uint64_t destlen = env->regs[r1 + 1]; - uint64_t dest = get_address_31fix(r1); - uint64_t srclen = env->regs[r3 + 1]; - uint64_t src = get_address_31fix(r3); - uint8_t pad = a2 & 0xff; - uint8_t v1 = 0,v2 = 0; - uint32_t cc = 0; - - if (!(destlen || srclen)) { - return cc; - } - - if (srclen > destlen) { - srclen = destlen; - } - - for (; destlen || srclen; src++, dest++, destlen--, srclen--) { - v1 = srclen ? ldub(src) : pad; - v2 = destlen ? ldub(dest) : pad; - if (v1 != v2) { - cc = (v1 < v2) ? 1 : 2; - break; - } - } - - env->regs[r1 + 1] = destlen; - /* can't use srclen here, we trunc'ed it */ - env->regs[r3 + 1] -= src - env->regs[r3]; - env->regs[r1] = dest; - env->regs[r3] = src; - - return cc; -} - -/* subtract unsigned v2 from v1 with borrow */ -uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2) -{ - uint32_t v1 = env->regs[r1]; - uint32_t res = v1 + (~v2) + (cc >> 1); - - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; - if (cc & 2) { - /* borrow */ - return v1 ? 1 : 0; - } else { - return v1 ? 3 : 2; - } -} - -/* subtract unsigned v2 from v1 with borrow */ -uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2) -{ - uint64_t res = v1 + (~v2) + (cc >> 1); - - env->regs[r1] = res; - if (cc & 2) { - /* borrow */ - return v1 ? 1 : 0; - } else { - return v1 ? 3 : 2; - } -} - -static inline int float_comp_to_cc(int float_compare) -{ - switch (float_compare) { - case float_relation_equal: - return 0; - case float_relation_less: - return 1; - case float_relation_greater: - return 2; - case float_relation_unordered: - return 3; - default: - cpu_abort(env, "unknown return value for float compare\n"); - } -} - -/* condition codes for binary FP ops */ -static uint32_t set_cc_f32(float32 v1, float32 v2) -{ - return float_comp_to_cc(float32_compare_quiet(v1, v2, &env->fpu_status)); -} - -static uint32_t set_cc_f64(float64 v1, float64 v2) -{ - return float_comp_to_cc(float64_compare_quiet(v1, v2, &env->fpu_status)); -} - -/* condition codes for unary FP ops */ -static uint32_t set_cc_nz_f32(float32 v) -{ - if (float32_is_any_nan(v)) { - return 3; - } else if (float32_is_zero(v)) { - return 0; - } else if (float32_is_neg(v)) { - return 1; - } else { - return 2; - } -} - -static uint32_t set_cc_nz_f64(float64 v) -{ - if (float64_is_any_nan(v)) { - return 3; - } else if (float64_is_zero(v)) { - return 0; - } else if (float64_is_neg(v)) { - return 1; - } else { - return 2; - } -} - -static uint32_t set_cc_nz_f128(float128 v) -{ - if (float128_is_any_nan(v)) { - return 3; - } else if (float128_is_zero(v)) { - return 0; - } else if (float128_is_neg(v)) { - return 1; - } else { - return 2; - } -} - -/* convert 32-bit int to 64-bit float */ -void HELPER(cdfbr)(uint32_t f1, int32_t v2) -{ - HELPER_LOG("%s: converting %d to f%d\n", __FUNCTION__, v2, f1); - env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); -} - -/* convert 32-bit int to 128-bit float */ -void HELPER(cxfbr)(uint32_t f1, int32_t v2) -{ - CPU_QuadU v1; - v1.q = int32_to_float128(v2, &env->fpu_status); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; -} - -/* convert 64-bit int to 32-bit float */ -void HELPER(cegbr)(uint32_t f1, int64_t v2) -{ - HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1); - env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status); -} - -/* convert 64-bit int to 64-bit float */ -void HELPER(cdgbr)(uint32_t f1, int64_t v2) -{ - HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1); - env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); -} - -/* convert 64-bit int to 128-bit float */ -void HELPER(cxgbr)(uint32_t f1, int64_t v2) -{ - CPU_QuadU x1; - x1.q = int64_to_float128(v2, &env->fpu_status); - HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __FUNCTION__, v2, - x1.ll.upper, x1.ll.lower); - env->fregs[f1].ll = x1.ll.upper; - env->fregs[f1 + 2].ll = x1.ll.lower; -} - -/* convert 32-bit int to 32-bit float */ -void HELPER(cefbr)(uint32_t f1, int32_t v2) -{ - env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); - HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __FUNCTION__, v2, - env->fregs[f1].l.upper, f1); -} - -/* 32-bit FP addition RR */ -uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__, - env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); - - return set_cc_nz_f32(env->fregs[f1].l.upper); -} - -/* 64-bit FP addition RR */ -uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __FUNCTION__, - env->fregs[f2].d, env->fregs[f1].d, f1); - - return set_cc_nz_f64(env->fregs[f1].d); -} - -/* 32-bit FP subtraction RR */ -uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); - HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__, - env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); - - return set_cc_nz_f32(env->fregs[f1].l.upper); -} - -/* 64-bit FP subtraction RR */ -uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); - HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", - __FUNCTION__, env->fregs[f2].d, env->fregs[f1].d, f1); - - return set_cc_nz_f64(env->fregs[f1].d); -} - -/* 32-bit FP division RR */ -void HELPER(debr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); -} - -/* 128-bit FP division RR */ -void HELPER(dxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - CPU_QuadU v2; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - CPU_QuadU res; - res.q = float128_div(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; -} - -/* 64-bit FP multiplication RR */ -void HELPER(mdbr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); -} - -/* 128-bit FP multiplication RR */ -void HELPER(mxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - CPU_QuadU v2; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - CPU_QuadU res; - res.q = float128_mul(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; -} - -/* convert 32-bit float to 64-bit float */ -void HELPER(ldebr)(uint32_t r1, uint32_t r2) -{ - env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper, - &env->fpu_status); -} - -/* convert 128-bit float to 64-bit float */ -void HELPER(ldxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU x2; - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status); - HELPER_LOG("%s: to 0x%ld\n", __FUNCTION__, env->fregs[f1].d); -} - -/* convert 64-bit float to 128-bit float */ -void HELPER(lxdbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU res; - res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; -} - -/* convert 64-bit float to 32-bit float */ -void HELPER(ledbr)(uint32_t f1, uint32_t f2) -{ - float64 d2 = env->fregs[f2].d; - env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status); -} - -/* convert 128-bit float to 32-bit float */ -void HELPER(lexbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU x2; - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status); - HELPER_LOG("%s: to 0x%d\n", __FUNCTION__, env->fregs[f1].l.upper); -} - -/* absolute value of 32-bit float */ -uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) -{ - float32 v1; - float32 v2 = env->fregs[f2].d; - v1 = float32_abs(v2); - env->fregs[f1].d = v1; - return set_cc_nz_f32(v1); -} - -/* absolute value of 64-bit float */ -uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) -{ - float64 v1; - float64 v2 = env->fregs[f2].d; - v1 = float64_abs(v2); - env->fregs[f1].d = v1; - return set_cc_nz_f64(v1); -} - -/* absolute value of 128-bit float */ -uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - CPU_QuadU v2; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - v1.q = float128_abs(v2.q); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; - return set_cc_nz_f128(v1.q); -} - -/* load and test 64-bit float */ -uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = env->fregs[f2].d; - return set_cc_nz_f64(env->fregs[f1].d); -} - -/* load and test 32-bit float */ -uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = env->fregs[f2].l.upper; - return set_cc_nz_f32(env->fregs[f1].l.upper); -} - -/* load and test 128-bit float */ -uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU x; - x.ll.upper = env->fregs[f2].ll; - x.ll.lower = env->fregs[f2 + 2].ll; - env->fregs[f1].ll = x.ll.upper; - env->fregs[f1 + 2].ll = x.ll.lower; - return set_cc_nz_f128(x.q); -} - -/* load complement of 32-bit float */ -uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper); - - return set_cc_nz_f32(env->fregs[f1].l.upper); -} - -/* load complement of 64-bit float */ -uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_chs(env->fregs[f2].d); - - return set_cc_nz_f64(env->fregs[f1].d); -} - -/* load complement of 128-bit float */ -uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU x1, x2; - x2.ll.upper = env->fregs[f2].ll; - x2.ll.lower = env->fregs[f2 + 2].ll; - x1.q = float128_chs(x2.q); - env->fregs[f1].ll = x1.ll.upper; - env->fregs[f1 + 2].ll = x1.ll.lower; - return set_cc_nz_f128(x1.q); -} - -/* 32-bit FP addition RM */ -void HELPER(aeb)(uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - v2.l = val; - HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __FUNCTION__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status); -} - -/* 32-bit FP division RM */ -void HELPER(deb)(uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - v2.l = val; - HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __FUNCTION__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status); -} - -/* 32-bit FP multiplication RM */ -void HELPER(meeb)(uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - v2.l = val; - HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __FUNCTION__, - v1, f1, v2.f); - env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); -} - -/* 32-bit FP compare RR */ -uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2) -{ - float32 v1 = env->fregs[f1].l.upper; - float32 v2 = env->fregs[f2].l.upper; - HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__, - v1, f1, v2); - return set_cc_f32(v1, v2); -} - -/* 64-bit FP compare RR */ -uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) -{ - float64 v1 = env->fregs[f1].d; - float64 v2 = env->fregs[f2].d; - HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __FUNCTION__, - v1, f1, v2); - return set_cc_f64(v1, v2); -} - -/* 128-bit FP compare RR */ -uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - CPU_QuadU v2; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - - return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q, - &env->fpu_status)); -} - -/* 64-bit FP compare RM */ -uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - v2.ll = ldq(a2); - HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __FUNCTION__, v1, - f1, v2.d); - return set_cc_f64(v1, v2.d); -} - -/* 64-bit FP addition RM */ -uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - v2.ll = ldq(a2); - HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __FUNCTION__, - v1, f1, v2.d); - env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); - return set_cc_nz_f64(v1); -} - -/* 32-bit FP subtraction RM */ -void HELPER(seb)(uint32_t f1, uint32_t val) -{ - float32 v1 = env->fregs[f1].l.upper; - CPU_FloatU v2; - v2.l = val; - env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status); -} - -/* 64-bit FP subtraction RM */ -uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - v2.ll = ldq(a2); - env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); - return set_cc_nz_f64(v1); -} - -/* 64-bit FP multiplication RM */ -void HELPER(mdb)(uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - v2.ll = ldq(a2); - HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __FUNCTION__, - v1, f1, v2.d); - env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); -} - -/* 64-bit FP division RM */ -void HELPER(ddb)(uint32_t f1, uint64_t a2) -{ - float64 v1 = env->fregs[f1].d; - CPU_DoubleU v2; - v2.ll = ldq(a2); - HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __FUNCTION__, - v1, f1, v2.d); - env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); -} - -static void set_round_mode(int m3) -{ - switch (m3) { - case 0: - /* current mode */ - break; - case 1: - /* biased round no nearest */ - case 4: - /* round to nearest */ - set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); - break; - case 5: - /* round to zero */ - set_float_rounding_mode(float_round_to_zero, &env->fpu_status); - break; - case 6: - /* round to +inf */ - set_float_rounding_mode(float_round_up, &env->fpu_status); - break; - case 7: - /* round to -inf */ - set_float_rounding_mode(float_round_down, &env->fpu_status); - break; - } -} - -/* convert 32-bit float to 64-bit int */ -uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) -{ - float32 v2 = env->fregs[f2].l.upper; - set_round_mode(m3); - env->regs[r1] = float32_to_int64(v2, &env->fpu_status); - return set_cc_nz_f32(v2); -} - -/* convert 64-bit float to 64-bit int */ -uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) -{ - float64 v2 = env->fregs[f2].d; - set_round_mode(m3); - env->regs[r1] = float64_to_int64(v2, &env->fpu_status); - return set_cc_nz_f64(v2); -} - -/* convert 128-bit float to 64-bit int */ -uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) -{ - CPU_QuadU v2; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - set_round_mode(m3); - env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status); - if (float128_is_any_nan(v2.q)) { - return 3; - } else if (float128_is_zero(v2.q)) { - return 0; - } else if (float128_is_neg(v2.q)) { - return 1; - } else { - return 2; - } -} - -/* convert 32-bit float to 32-bit int */ -uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) -{ - float32 v2 = env->fregs[f2].l.upper; - set_round_mode(m3); - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float32_to_int32(v2, &env->fpu_status); - return set_cc_nz_f32(v2); -} - -/* convert 64-bit float to 32-bit int */ -uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) -{ - float64 v2 = env->fregs[f2].d; - set_round_mode(m3); - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float64_to_int32(v2, &env->fpu_status); - return set_cc_nz_f64(v2); -} - -/* convert 128-bit float to 32-bit int */ -uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) -{ - CPU_QuadU v2; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - float128_to_int32(v2.q, &env->fpu_status); - return set_cc_nz_f128(v2.q); -} - -/* load 32-bit FP zero */ -void HELPER(lzer)(uint32_t f1) -{ - env->fregs[f1].l.upper = float32_zero; -} - -/* load 64-bit FP zero */ -void HELPER(lzdr)(uint32_t f1) -{ - env->fregs[f1].d = float64_zero; -} - -/* load 128-bit FP zero */ -void HELPER(lzxr)(uint32_t f1) -{ - CPU_QuadU x; - x.q = float64_to_float128(float64_zero, &env->fpu_status); - env->fregs[f1].ll = x.ll.upper; - env->fregs[f1 + 1].ll = x.ll.lower; -} - -/* 128-bit FP subtraction RR */ -uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - CPU_QuadU v2; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - CPU_QuadU res; - res.q = float128_sub(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; - return set_cc_nz_f128(res.q); -} - -/* 128-bit FP addition RR */ -uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) -{ - CPU_QuadU v1; - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - CPU_QuadU v2; - v2.ll.upper = env->fregs[f2].ll; - v2.ll.lower = env->fregs[f2 + 2].ll; - CPU_QuadU res; - res.q = float128_add(v1.q, v2.q, &env->fpu_status); - env->fregs[f1].ll = res.ll.upper; - env->fregs[f1 + 2].ll = res.ll.lower; - return set_cc_nz_f128(res.q); -} - -/* 32-bit FP multiplication RR */ -void HELPER(meebr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper, - env->fregs[f2].l.upper, - &env->fpu_status); -} - -/* 64-bit FP division RR */ -void HELPER(ddbr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, - &env->fpu_status); -} - -/* 64-bit FP multiply and add RM */ -void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) -{ - HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __FUNCTION__, f1, a2, f3); - CPU_DoubleU v2; - v2.ll = ldq(a2); - env->fregs[f1].d = float64_add(env->fregs[f1].d, - float64_mul(v2.d, env->fregs[f3].d, - &env->fpu_status), - &env->fpu_status); -} - -/* 64-bit FP multiply and add RR */ -void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) -{ - HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3); - env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, - env->fregs[f3].d, - &env->fpu_status), - env->fregs[f1].d, &env->fpu_status); -} - -/* 64-bit FP multiply and subtract RR */ -void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) -{ - HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3); - env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, - env->fregs[f3].d, - &env->fpu_status), - env->fregs[f1].d, &env->fpu_status); -} - -/* 32-bit FP multiply and add RR */ -void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) -{ - env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, - float32_mul(env->fregs[f2].l.upper, - env->fregs[f3].l.upper, - &env->fpu_status), - &env->fpu_status); -} - -/* convert 32-bit float to 64-bit float */ -void HELPER(ldeb)(uint32_t f1, uint64_t a2) -{ - uint32_t v2; - v2 = ldl(a2); - env->fregs[f1].d = float32_to_float64(v2, - &env->fpu_status); -} - -/* convert 64-bit float to 128-bit float */ -void HELPER(lxdb)(uint32_t f1, uint64_t a2) -{ - CPU_DoubleU v2; - v2.ll = ldq(a2); - CPU_QuadU v1; - v1.q = float64_to_float128(v2.d, &env->fpu_status); - env->fregs[f1].ll = v1.ll.upper; - env->fregs[f1 + 2].ll = v1.ll.lower; -} - -/* test data class 32-bit */ -uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) -{ - float32 v1 = env->fregs[f1].l.upper; - int neg = float32_is_neg(v1); - uint32_t cc = 0; - - HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, (long)v1, m2, neg); - if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) || - (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) || - (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || - (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { - cc = 1; - } else if (m2 & (1 << (9-neg))) { - /* assume normalized number */ - cc = 1; - } - - /* FIXME: denormalized? */ - return cc; -} - -/* test data class 64-bit */ -uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) -{ - float64 v1 = env->fregs[f1].d; - int neg = float64_is_neg(v1); - uint32_t cc = 0; - - HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, v1, m2, neg); - if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) || - (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) || - (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || - (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { - cc = 1; - } else if (m2 & (1 << (9-neg))) { - /* assume normalized number */ - cc = 1; - } - /* FIXME: denormalized? */ - return cc; -} - -/* test data class 128-bit */ -uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) -{ - CPU_QuadU v1; - uint32_t cc = 0; - v1.ll.upper = env->fregs[f1].ll; - v1.ll.lower = env->fregs[f1 + 2].ll; - - int neg = float128_is_neg(v1.q); - if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) || - (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) || - (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) || - (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) { - cc = 1; - } else if (m2 & (1 << (9-neg))) { - /* assume normalized number */ - cc = 1; - } - /* FIXME: denormalized? */ - return cc; -} - -/* find leftmost one */ -uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2) -{ - uint64_t res = 0; - uint64_t ov2 = v2; - - while (!(v2 & 0x8000000000000000ULL) && v2) { - v2 <<= 1; - res++; - } - - if (!v2) { - env->regs[r1] = 64; - env->regs[r1 + 1] = 0; - return 0; - } else { - env->regs[r1] = res; - env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res); - return 2; - } -} - -/* square root 64-bit RR */ -void HELPER(sqdbr)(uint32_t f1, uint32_t f2) -{ - env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); -} - -/* checksum */ -void HELPER(cksm)(uint32_t r1, uint32_t r2) -{ - uint64_t src = get_address_31fix(r2); - uint64_t src_len = env->regs[(r2 + 1) & 15]; - uint64_t cksm = (uint32_t)env->regs[r1]; - - while (src_len >= 4) { - cksm += ldl(src); - - /* move to next word */ - src_len -= 4; - src += 4; - } - - switch (src_len) { - case 0: - break; - case 1: - cksm += ldub(src) << 24; - break; - case 2: - cksm += lduw(src) << 16; - break; - case 3: - cksm += lduw(src) << 16; - cksm += ldub(src + 2) << 8; - break; - } - - /* indicate we've processed everything */ - env->regs[r2] = src + src_len; - env->regs[(r2 + 1) & 15] = 0; - - /* store result */ - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - ((uint32_t)cksm + (cksm >> 32)); -} - -static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src, - int32_t dst) -{ - if (src == dst) { - return 0; - } else if (src < dst) { - return 1; - } else { - return 2; - } -} - -static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst) -{ - return cc_calc_ltgt_32(env, dst, 0); -} - -static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src, - int64_t dst) -{ - if (src == dst) { - return 0; - } else if (src < dst) { - return 1; - } else { - return 2; - } -} - -static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst) -{ - return cc_calc_ltgt_64(env, dst, 0); -} - -static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src, - uint32_t dst) -{ - if (src == dst) { - return 0; - } else if (src < dst) { - return 1; - } else { - return 2; - } -} - -static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, - uint64_t dst) -{ - if (src == dst) { - return 0; - } else if (src < dst) { - return 1; - } else { - return 2; - } -} - -static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t mask) -{ - HELPER_LOG("%s: val 0x%x mask 0x%x\n", __FUNCTION__, val, mask); - uint16_t r = val & mask; - if (r == 0 || mask == 0) { - return 0; - } else if (r == mask) { - return 3; - } else { - return 1; - } -} - -/* set condition code for test under mask */ -static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, uint32_t mask) -{ - uint16_t r = val & mask; - HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __FUNCTION__, val, mask, r); - if (r == 0 || mask == 0) { - return 0; - } else if (r == mask) { - return 3; - } else { - while (!(mask & 0x8000)) { - mask <<= 1; - val <<= 1; - } - if (val & 0x8000) { - return 2; - } else { - return 1; - } - } -} - -static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst) -{ - return !!dst; -} - -static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, int64_t a2, - int64_t ar) -{ - if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { - return 3; /* overflow */ - } else { - if (ar < 0) { - return 1; - } else if (ar > 0) { - return 2; - } else { - return 0; - } - } -} - -static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, uint64_t a2, - uint64_t ar) -{ - if (ar == 0) { - if (a1) { - return 2; - } else { - return 0; - } - } else { - if (ar < a1 || ar < a2) { - return 3; - } else { - return 1; - } - } -} - -static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, int64_t a2, - int64_t ar) -{ - if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { - return 3; /* overflow */ - } else { - if (ar < 0) { - return 1; - } else if (ar > 0) { - return 2; - } else { - return 0; - } - } -} - -static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, uint64_t a2, - uint64_t ar) -{ - if (ar == 0) { - return 2; - } else { - if (a2 > a1) { - return 1; - } else { - return 3; - } - } -} - -static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) -{ - if ((uint64_t)dst == 0x8000000000000000ULL) { - return 3; - } else if (dst) { - return 1; - } else { - return 0; - } -} - -static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst) -{ - return !!dst; -} - -static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst) -{ - if ((uint64_t)dst == 0x8000000000000000ULL) { - return 3; - } else if (dst < 0) { - return 1; - } else if (dst > 0) { - return 2; - } else { - return 0; - } -} - - -static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, int32_t a2, - int32_t ar) -{ - if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { - return 3; /* overflow */ - } else { - if (ar < 0) { - return 1; - } else if (ar > 0) { - return 2; - } else { - return 0; - } - } -} - -static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, uint32_t a2, - uint32_t ar) -{ - if (ar == 0) { - if (a1) { - return 2; - } else { - return 0; - } - } else { - if (ar < a1 || ar < a2) { - return 3; - } else { - return 1; - } - } -} - -static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, int32_t a2, - int32_t ar) -{ - if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { - return 3; /* overflow */ - } else { - if (ar < 0) { - return 1; - } else if (ar > 0) { - return 2; - } else { - return 0; - } - } -} - -static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, uint32_t a2, - uint32_t ar) -{ - if (ar == 0) { - return 2; - } else { - if (a2 > a1) { - return 1; - } else { - return 3; - } - } -} - -static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) -{ - if ((uint32_t)dst == 0x80000000UL) { - return 3; - } else if (dst) { - return 1; - } else { - return 0; - } -} - -static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst) -{ - return !!dst; -} - -static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst) -{ - if ((uint32_t)dst == 0x80000000UL) { - return 3; - } else if (dst < 0) { - return 1; - } else if (dst > 0) { - return 2; - } else { - return 0; - } -} - -/* calculate condition code for insert character under mask insn */ -static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, uint32_t val) -{ - HELPER_LOG("%s: mask 0x%x val %d\n", __FUNCTION__, mask, val); - uint32_t cc; - - if (mask == 0xf) { - if (!val) { - return 0; - } else if (val & 0x80000000) { - return 1; - } else { - return 2; - } - } - - if (!val || !mask) { - cc = 0; - } else { - while (mask != 1) { - mask >>= 1; - val >>= 8; - } - if (val & 0x80) { - cc = 1; - } else { - cc = 2; - } - } - return cc; -} - -static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, uint64_t shift) -{ - uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); - uint64_t match, r; - - /* check if the sign bit stays the same */ - if (src & (1ULL << 63)) { - match = mask; - } else { - match = 0; - } - - if ((src & mask) != match) { - /* overflow */ - return 3; - } - - r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63)); - - if ((int64_t)r == 0) { - return 0; - } else if ((int64_t)r < 0) { - return 1; - } - - return 2; -} - - -static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, - uint64_t dst, uint64_t vr) -{ - uint32_t r = 0; - - switch (cc_op) { - case CC_OP_CONST0: - case CC_OP_CONST1: - case CC_OP_CONST2: - case CC_OP_CONST3: - /* cc_op value _is_ cc */ - r = cc_op; - break; - case CC_OP_LTGT0_32: - r = cc_calc_ltgt0_32(env, dst); - break; - case CC_OP_LTGT0_64: - r = cc_calc_ltgt0_64(env, dst); - break; - case CC_OP_LTGT_32: - r = cc_calc_ltgt_32(env, src, dst); - break; - case CC_OP_LTGT_64: - r = cc_calc_ltgt_64(env, src, dst); - break; - case CC_OP_LTUGTU_32: - r = cc_calc_ltugtu_32(env, src, dst); - break; - case CC_OP_LTUGTU_64: - r = cc_calc_ltugtu_64(env, src, dst); - break; - case CC_OP_TM_32: - r = cc_calc_tm_32(env, src, dst); - break; - case CC_OP_TM_64: - r = cc_calc_tm_64(env, src, dst); - break; - case CC_OP_NZ: - r = cc_calc_nz(env, dst); - break; - case CC_OP_ADD_64: - r = cc_calc_add_64(env, src, dst, vr); - break; - case CC_OP_ADDU_64: - r = cc_calc_addu_64(env, src, dst, vr); - break; - case CC_OP_SUB_64: - r = cc_calc_sub_64(env, src, dst, vr); - break; - case CC_OP_SUBU_64: - r = cc_calc_subu_64(env, src, dst, vr); - break; - case CC_OP_ABS_64: - r = cc_calc_abs_64(env, dst); - break; - case CC_OP_NABS_64: - r = cc_calc_nabs_64(env, dst); - break; - case CC_OP_COMP_64: - r = cc_calc_comp_64(env, dst); - break; - - case CC_OP_ADD_32: - r = cc_calc_add_32(env, src, dst, vr); - break; - case CC_OP_ADDU_32: - r = cc_calc_addu_32(env, src, dst, vr); - break; - case CC_OP_SUB_32: - r = cc_calc_sub_32(env, src, dst, vr); - break; - case CC_OP_SUBU_32: - r = cc_calc_subu_32(env, src, dst, vr); - break; - case CC_OP_ABS_32: - r = cc_calc_abs_64(env, dst); - break; - case CC_OP_NABS_32: - r = cc_calc_nabs_64(env, dst); - break; - case CC_OP_COMP_32: - r = cc_calc_comp_32(env, dst); - break; - - case CC_OP_ICM: - r = cc_calc_icm_32(env, src, dst); - break; - case CC_OP_SLAG: - r = cc_calc_slag(env, src, dst); - break; - - case CC_OP_LTGT_F32: - r = set_cc_f32(src, dst); - break; - case CC_OP_LTGT_F64: - r = set_cc_f64(src, dst); - break; - case CC_OP_NZ_F32: - r = set_cc_nz_f32(dst); - break; - case CC_OP_NZ_F64: - r = set_cc_nz_f64(dst); - break; - - default: - cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op)); - } - - HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __FUNCTION__, - cc_name(cc_op), src, dst, vr, r); - return r; -} - -uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, - uint64_t vr) -{ - return do_calc_cc(env, cc_op, src, dst, vr); -} - -uint32_t HELPER(calc_cc)(uint32_t cc_op, uint64_t src, uint64_t dst, - uint64_t vr) -{ - return do_calc_cc(env, cc_op, src, dst, vr); -} - -uint64_t HELPER(cvd)(int32_t bin) -{ - /* positive 0 */ - uint64_t dec = 0x0c; - int shift = 4; - - if (bin < 0) { - bin = -bin; - dec = 0x0d; - } - - for (shift = 4; (shift < 64) && bin; shift += 4) { - int current_number = bin % 10; - - dec |= (current_number) << shift; - bin /= 10; - } - - return dec; -} - -void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) -{ - int len_dest = len >> 4; - int len_src = len & 0xf; - uint8_t b; - int second_nibble = 0; - - dest += len_dest; - src += len_src; - - /* last byte is special, it only flips the nibbles */ - b = ldub(src); - stb(dest, (b << 4) | (b >> 4)); - src--; - len_src--; - - /* now pad every nibble with 0xf0 */ - - while (len_dest > 0) { - uint8_t cur_byte = 0; - - if (len_src > 0) { - cur_byte = ldub(src); - } - - len_dest--; - dest--; - - /* only advance one nibble at a time */ - if (second_nibble) { - cur_byte >>= 4; - len_src--; - src--; - } - second_nibble = !second_nibble; - - /* digit */ - cur_byte = (cur_byte & 0xf); - /* zone bits */ - cur_byte |= 0xf0; - - stb(dest, cur_byte); - } -} - -void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans) -{ - int i; - - for (i = 0; i <= len; i++) { - uint8_t byte = ldub(array + i); - uint8_t new_byte = ldub(trans + byte); - stb(array + i, new_byte); - } -} - -#ifndef CONFIG_USER_ONLY - -void HELPER(load_psw)(uint64_t mask, uint64_t addr) -{ - load_psw(env, mask, addr); - cpu_loop_exit(env); -} - -static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) -{ - qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr); - - if (kvm_enabled()) { -#ifdef CONFIG_KVM - kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code); -#endif - } else { - env->int_pgm_code = code; - env->int_pgm_ilc = ilc; - env->exception_index = EXCP_PGM; - cpu_loop_exit(env); - } -} - -/* - * ret < 0 indicates program check, ret = 0,1,2,3 -> cc - */ -int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) -{ - int r = 0; - int shift = 0; - -#ifdef DEBUG_HELPER - printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code); -#endif - - /* basic checks */ - if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) { - return -PGM_ADDRESSING; - } - if (sccb & ~0x7ffffff8ul) { - return -PGM_SPECIFICATION; - } - - switch(code) { - case SCLP_CMDW_READ_SCP_INFO: - case SCLP_CMDW_READ_SCP_INFO_FORCED: - while ((ram_size >> (20 + shift)) > 65535) { - shift++; - } - stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift)); - stb_phys(sccb + SCP_INCREMENT, 1 << shift); - stw_phys(sccb + SCP_RESPONSE_CODE, 0x10); - - s390_sclp_extint(sccb & ~3); - break; - default: -#ifdef DEBUG_HELPER - printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code); -#endif - r = 3; - break; - } - - return r; -} - -/* SCLP service call */ -uint32_t HELPER(servc)(uint32_t r1, uint64_t r2) -{ - int r; - - r = sclp_service_call(env, r1, r2); - if (r < 0) { - program_interrupt(env, -r, 4); - return 0; - } - return r; -} - -/* DIAG */ -uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code) -{ - uint64_t r; - - switch (num) { - case 0x500: - /* KVM hypercall */ - r = s390_virtio_hypercall(env, mem, code); - break; - case 0x44: - /* yield */ - r = 0; - break; - case 0x308: - /* ipl */ - r = 0; - break; - default: - r = -1; - break; - } - - if (r) { - program_interrupt(env, PGM_OPERATION, ILC_LATER_INC); - } - - return r; -} - -/* Store CPU ID */ -void HELPER(stidp)(uint64_t a1) -{ - stq(a1, env->cpu_num); -} - -/* Set Prefix */ -void HELPER(spx)(uint64_t a1) -{ - uint32_t prefix; - - prefix = ldl(a1); - env->psa = prefix & 0xfffff000; - qemu_log("prefix: %#x\n", prefix); - tlb_flush_page(env, 0); - tlb_flush_page(env, TARGET_PAGE_SIZE); -} - -/* Set Clock */ -uint32_t HELPER(sck)(uint64_t a1) -{ - /* XXX not implemented - is it necessary? */ - - return 0; -} - -static inline uint64_t clock_value(CPUS390XState *env) -{ - uint64_t time; - - time = env->tod_offset + - time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime); - - return time; -} - -/* Store Clock */ -uint32_t HELPER(stck)(uint64_t a1) -{ - stq(a1, clock_value(env)); - - return 0; -} - -/* Store Clock Extended */ -uint32_t HELPER(stcke)(uint64_t a1) -{ - stb(a1, 0); - /* basically the same value as stck */ - stq(a1 + 1, clock_value(env) | env->cpu_num); - /* more fine grained than stck */ - stq(a1 + 9, 0); - /* XXX programmable fields */ - stw(a1 + 17, 0); - - - return 0; -} - -/* Set Clock Comparator */ -void HELPER(sckc)(uint64_t a1) -{ - uint64_t time = ldq(a1); - - if (time == -1ULL) { - return; - } - - /* difference between now and then */ - time -= clock_value(env); - /* nanoseconds */ - time = (time * 125) >> 9; - - qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time); -} - -/* Store Clock Comparator */ -void HELPER(stckc)(uint64_t a1) -{ - /* XXX implement */ - stq(a1, 0); -} - -/* Set CPU Timer */ -void HELPER(spt)(uint64_t a1) -{ - uint64_t time = ldq(a1); - - if (time == -1ULL) { - return; - } - - /* nanoseconds */ - time = (time * 125) >> 9; - - qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time); -} - -/* Store CPU Timer */ -void HELPER(stpt)(uint64_t a1) -{ - /* XXX implement */ - stq(a1, 0); -} - -/* Store System Information */ -uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) -{ - int cc = 0; - int sel1, sel2; - - if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 && - ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) { - /* valid function code, invalid reserved bits */ - program_interrupt(env, PGM_SPECIFICATION, 2); - } - - sel1 = r0 & STSI_R0_SEL1_MASK; - sel2 = r1 & STSI_R1_SEL2_MASK; - - /* XXX: spec exception if sysib is not 4k-aligned */ - - switch (r0 & STSI_LEVEL_MASK) { - case STSI_LEVEL_1: - if ((sel1 == 1) && (sel2 == 1)) { - /* Basic Machine Configuration */ - struct sysib_111 sysib; - - memset(&sysib, 0, sizeof(sysib)); - ebcdic_put(sysib.manuf, "QEMU ", 16); - /* same as machine type number in STORE CPU ID */ - ebcdic_put(sysib.type, "QEMU", 4); - /* same as model number in STORE CPU ID */ - ebcdic_put(sysib.model, "QEMU ", 16); - ebcdic_put(sysib.sequence, "QEMU ", 16); - ebcdic_put(sysib.plant, "QEMU", 4); - cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); - } else if ((sel1 == 2) && (sel2 == 1)) { - /* Basic Machine CPU */ - struct sysib_121 sysib; - - memset(&sysib, 0, sizeof(sysib)); - /* XXX make different for different CPUs? */ - ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); - ebcdic_put(sysib.plant, "QEMU", 4); - stw_p(&sysib.cpu_addr, env->cpu_num); - cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); - } else if ((sel1 == 2) && (sel2 == 2)) { - /* Basic Machine CPUs */ - struct sysib_122 sysib; - - memset(&sysib, 0, sizeof(sysib)); - stl_p(&sysib.capability, 0x443afc29); - /* XXX change when SMP comes */ - stw_p(&sysib.total_cpus, 1); - stw_p(&sysib.active_cpus, 1); - stw_p(&sysib.standby_cpus, 0); - stw_p(&sysib.reserved_cpus, 0); - cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); - } else { - cc = 3; - } - break; - case STSI_LEVEL_2: - { - if ((sel1 == 2) && (sel2 == 1)) { - /* LPAR CPU */ - struct sysib_221 sysib; - - memset(&sysib, 0, sizeof(sysib)); - /* XXX make different for different CPUs? */ - ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); - ebcdic_put(sysib.plant, "QEMU", 4); - stw_p(&sysib.cpu_addr, env->cpu_num); - stw_p(&sysib.cpu_id, 0); - cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); - } else if ((sel1 == 2) && (sel2 == 2)) { - /* LPAR CPUs */ - struct sysib_222 sysib; - - memset(&sysib, 0, sizeof(sysib)); - stw_p(&sysib.lpar_num, 0); - sysib.lcpuc = 0; - /* XXX change when SMP comes */ - stw_p(&sysib.total_cpus, 1); - stw_p(&sysib.conf_cpus, 1); - stw_p(&sysib.standby_cpus, 0); - stw_p(&sysib.reserved_cpus, 0); - ebcdic_put(sysib.name, "QEMU ", 8); - stl_p(&sysib.caf, 1000); - stw_p(&sysib.dedicated_cpus, 0); - stw_p(&sysib.shared_cpus, 0); - cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); - } else { - cc = 3; - } - break; - } - case STSI_LEVEL_3: - { - if ((sel1 == 2) && (sel2 == 2)) { - /* VM CPUs */ - struct sysib_322 sysib; - - memset(&sysib, 0, sizeof(sysib)); - sysib.count = 1; - /* XXX change when SMP comes */ - stw_p(&sysib.vm[0].total_cpus, 1); - stw_p(&sysib.vm[0].conf_cpus, 1); - stw_p(&sysib.vm[0].standby_cpus, 0); - stw_p(&sysib.vm[0].reserved_cpus, 0); - ebcdic_put(sysib.vm[0].name, "KVMguest", 8); - stl_p(&sysib.vm[0].caf, 1000); - ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16); - cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); - } else { - cc = 3; - } - break; - } - case STSI_LEVEL_CURRENT: - env->regs[0] = STSI_LEVEL_3; - break; - default: - cc = 3; - break; - } - - return cc; -} - -void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - int i; - uint64_t src = a2; - - for (i = r1;; i = (i + 1) % 16) { - env->cregs[i] = ldq(src); - HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n", - i, src, env->cregs[i]); - src += sizeof(uint64_t); - - if (i == r3) { - break; - } - } - - tlb_flush(env, 1); -} - -void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - int i; - uint64_t src = a2; - - for (i = r1;; i = (i + 1) % 16) { - env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src); - src += sizeof(uint32_t); - - if (i == r3) { - break; - } - } - - tlb_flush(env, 1); -} - -void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - int i; - uint64_t dest = a2; - - for (i = r1;; i = (i + 1) % 16) { - stq(dest, env->cregs[i]); - dest += sizeof(uint64_t); - - if (i == r3) { - break; - } - } -} - -void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3) -{ - int i; - uint64_t dest = a2; - - for (i = r1;; i = (i + 1) % 16) { - stl(dest, env->cregs[i]); - dest += sizeof(uint32_t); - - if (i == r3) { - break; - } - } -} - -uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2) -{ - /* XXX implement */ - - return 0; -} - -/* insert storage key extended */ -uint64_t HELPER(iske)(uint64_t r2) -{ - uint64_t addr = get_address(0, 0, r2); - - if (addr > ram_size) { - return 0; - } - - return env->storage_keys[addr / TARGET_PAGE_SIZE]; -} - -/* set storage key extended */ -void HELPER(sske)(uint32_t r1, uint64_t r2) -{ - uint64_t addr = get_address(0, 0, r2); - - if (addr > ram_size) { - return; - } - - env->storage_keys[addr / TARGET_PAGE_SIZE] = r1; -} - -/* reset reference bit extended */ -uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2) -{ - uint8_t re; - uint8_t key; - if (r2 > ram_size) { - return 0; - } - - key = env->storage_keys[r2 / TARGET_PAGE_SIZE]; - re = key & (SK_R | SK_C); - env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R); - - /* - * cc - * - * 0 Reference bit zero; change bit zero - * 1 Reference bit zero; change bit one - * 2 Reference bit one; change bit zero - * 3 Reference bit one; change bit one - */ - - return re >> 1; -} - -/* compare and swap and purge */ -uint32_t HELPER(csp)(uint32_t r1, uint32_t r2) -{ - uint32_t cc; - uint32_t o1 = env->regs[r1]; - uint64_t a2 = get_address_31fix(r2) & ~3ULL; - uint32_t o2 = ldl(a2); - - if (o1 == o2) { - stl(a2, env->regs[(r1 + 1) & 15]); - if (env->regs[r2] & 0x3) { - /* flush TLB / ALB */ - tlb_flush(env, 1); - } - cc = 0; - } else { - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2; - cc = 1; - } - - return cc; -} - -static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2, - uint64_t mode2) -{ - target_ulong src, dest; - int flags, cc = 0, i; - - if (!l) { - return 0; - } else if (l > 256) { - /* max 256 */ - l = 256; - cc = 3; - } - - if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) { - cpu_loop_exit(env); - } - dest |= a1 & ~TARGET_PAGE_MASK; - - if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) { - cpu_loop_exit(env); - } - src |= a2 & ~TARGET_PAGE_MASK; - - /* XXX replace w/ memcpy */ - for (i = 0; i < l; i++) { - /* XXX be more clever */ - if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) || - (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) { - mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2); - break; - } - stb_phys(dest + i, ldub_phys(src + i)); - } - - return cc; -} - -uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2) -{ - HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", - __FUNCTION__, l, a1, a2); - - return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY); -} - -uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2) -{ - HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", - __FUNCTION__, l, a1, a2); - - return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY); -} - -uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) -{ - int cc = 0; - - HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n", - __FUNCTION__, order_code, r1, cpu_addr); - - /* Remember: Use "R1 or R1+1, whichever is the odd-numbered register" - as parameter (input). Status (output) is always R1. */ - - switch (order_code) { - case SIGP_SET_ARCH: - /* switch arch */ - break; - case SIGP_SENSE: - /* enumerate CPU status */ - if (cpu_addr) { - /* XXX implement when SMP comes */ - return 3; - } - env->regs[r1] &= 0xffffffff00000000ULL; - cc = 1; - break; -#if !defined (CONFIG_USER_ONLY) - case SIGP_RESTART: - qemu_system_reset_request(); - cpu_loop_exit(env); - break; - case SIGP_STOP: - qemu_system_shutdown_request(); - cpu_loop_exit(env); - break; -#endif - default: - /* unknown sigp */ - fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code); - cc = 3; - } - - return cc; -} - -void HELPER(sacf)(uint64_t a1) -{ - HELPER_LOG("%s: %16" PRIx64 "\n", __FUNCTION__, a1); - - switch (a1 & 0xf00) { - case 0x000: - env->psw.mask &= ~PSW_MASK_ASC; - env->psw.mask |= PSW_ASC_PRIMARY; - break; - case 0x100: - env->psw.mask &= ~PSW_MASK_ASC; - env->psw.mask |= PSW_ASC_SECONDARY; - break; - case 0x300: - env->psw.mask &= ~PSW_MASK_ASC; - env->psw.mask |= PSW_ASC_HOME; - break; - default: - qemu_log("unknown sacf mode: %" PRIx64 "\n", a1); - program_interrupt(env, PGM_SPECIFICATION, 2); - break; - } -} - -/* invalidate pte */ -void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr) -{ - uint64_t page = vaddr & TARGET_PAGE_MASK; - uint64_t pte = 0; - - /* XXX broadcast to other CPUs */ - - /* XXX Linux is nice enough to give us the exact pte address. - According to spec we'd have to find it out ourselves */ - /* XXX Linux is fine with overwriting the pte, the spec requires - us to only set the invalid bit */ - stq_phys(pte_addr, pte | _PAGE_INVALID); - - /* XXX we exploit the fact that Linux passes the exact virtual - address here - it's not obliged to! */ - tlb_flush_page(env, page); - - /* XXX 31-bit hack */ - if (page & 0x80000000) { - tlb_flush_page(env, page & ~0x80000000); - } else { - tlb_flush_page(env, page | 0x80000000); - } -} - -/* flush local tlb */ -void HELPER(ptlb)(void) -{ - tlb_flush(env, 1); -} - -/* store using real address */ -void HELPER(stura)(uint64_t addr, uint32_t v1) -{ - stw_phys(get_address(0, 0, addr), v1); -} - -/* load real address */ -uint32_t HELPER(lra)(uint64_t addr, uint32_t r1) -{ - uint32_t cc = 0; - int old_exc = env->exception_index; - uint64_t asc = env->psw.mask & PSW_MASK_ASC; - uint64_t ret; - int flags; - - /* XXX incomplete - has more corner cases */ - if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) { - program_interrupt(env, PGM_SPECIAL_OP, 2); - } - - env->exception_index = old_exc; - if (mmu_translate(env, addr, 0, asc, &ret, &flags)) { - cc = 3; - } - if (env->exception_index == EXCP_PGM) { - ret = env->int_pgm_code | 0x80000000; - } else { - ret |= addr & ~TARGET_PAGE_MASK; - } - env->exception_index = old_exc; - - if (!(env->psw.mask & PSW_MASK_64)) { - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | (ret & 0xffffffffULL); - } else { - env->regs[r1] = ret; - } - - return cc; -} - -#endif diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 1c1baf5..66119cd 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -276,19 +276,19 @@ static inline void potential_page_fault(DisasContext *s) static inline uint64_t ld_code2(uint64_t pc) { - return (uint64_t)lduw_code(pc); + return (uint64_t)cpu_lduw_code(cpu_single_env, pc); } static inline uint64_t ld_code4(uint64_t pc) { - return (uint64_t)ldl_code(pc); + return (uint64_t)cpu_ldl_code(cpu_single_env, pc); } static inline uint64_t ld_code6(uint64_t pc) { uint64_t opc; - opc = (uint64_t)lduw_code(pc) << 32; - opc |= (uint64_t)(uint32_t)ldl_code(pc+2); + opc = (uint64_t)cpu_lduw_code(cpu_single_env, pc) << 32; + opc |= (uint64_t)(uint32_t)cpu_ldl_code(cpu_single_env, pc + 2); return opc; } @@ -312,7 +312,7 @@ static inline void gen_debug(DisasContext *s) TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); update_psw_addr(s); gen_op_calc_cc(s); - gen_helper_exception(tmp); + gen_helper_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); s->is_jmp = DISAS_EXCP; } @@ -324,7 +324,7 @@ static void gen_illegal_opcode(DisasContext *s, int ilc) TCGv_i32 tmp = tcg_const_i32(EXCP_SPEC); update_psw_addr(s); gen_op_calc_cc(s); - gen_helper_exception(tmp); + gen_helper_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); s->is_jmp = DISAS_EXCP; } @@ -377,7 +377,7 @@ static void gen_program_exception(DisasContext *s, int ilc, int code) /* trigger exception */ tmp = tcg_const_i32(EXCP_PGM); - gen_helper_exception(tmp); + gen_helper_exception(cpu_env, tmp); tcg_temp_free_i32(tmp); /* end TB here */ @@ -667,16 +667,11 @@ static void set_cc_cmp_f32_i64(DisasContext *s, TCGv_i32 v1, TCGv_i64 v2) s->cc_op = CC_OP_LTGT_F32; } -static void set_cc_nz_f32(DisasContext *s, TCGv_i32 v1) +static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i32 v1) { gen_op_update1_cc_i32(s, CC_OP_NZ_F32, v1); } -static inline void set_cc_nz_f64(DisasContext *s, TCGv_i64 v1) -{ - gen_op_update1_cc_i64(s, CC_OP_NZ_F64, v1); -} - /* CC value is in env->cc_op */ static inline void set_cc_static(DisasContext *s) { @@ -727,7 +722,7 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_NZ_F32: case CC_OP_NZ_F64: /* 1 argument */ - gen_helper_calc_cc(cc_op, local_cc_op, dummy, cc_dst, dummy); + gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, dummy, cc_dst, dummy); break; case CC_OP_ICM: case CC_OP_LTGT_32: @@ -740,7 +735,7 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_LTGT_F64: case CC_OP_SLAG: /* 2 arguments */ - gen_helper_calc_cc(cc_op, local_cc_op, cc_src, cc_dst, dummy); + gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy); break; case CC_OP_ADD_64: case CC_OP_ADDU_64: @@ -751,11 +746,11 @@ static void gen_op_calc_cc(DisasContext *s) case CC_OP_SUB_32: case CC_OP_SUBU_32: /* 3 arguments */ - gen_helper_calc_cc(cc_op, local_cc_op, cc_src, cc_dst, cc_vr); + gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, cc_vr); break; case CC_OP_DYNAMIC: /* unknown operation - assume 3 arguments and cc_op in env */ - gen_helper_calc_cc(cc_op, cc_op, cc_src, cc_dst, cc_vr); + gen_helper_calc_cc(cc_op, cpu_env, cc_op, cc_src, cc_dst, cc_vr); break; default: tcg_abort(); @@ -1268,7 +1263,7 @@ static void gen_op_mvc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) /* Fall back to helper */ vl = tcg_const_i32(l); potential_page_fault(s); - gen_helper_mvc(vl, s1, s2); + gen_helper_mvc(cpu_env, vl, s1, s2); tcg_temp_free_i32(vl); return; } @@ -1460,7 +1455,7 @@ static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) potential_page_fault(s); vl = tcg_const_i32(l); - gen_helper_clc(cc_op, vl, s1, s2); + gen_helper_clc(cc_op, cpu_env, vl, s1, s2); tcg_temp_free_i32(vl); set_cc_static(s); } @@ -1808,7 +1803,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) tmp2 = tcg_temp_new_i64(); tmp32_1 = tcg_const_i32(r1); tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - gen_helper_mlg(tmp32_1, tmp2); + gen_helper_mlg(cpu_env, tmp32_1, tmp2); tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; @@ -1816,7 +1811,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) tmp2 = tcg_temp_new_i64(); tmp32_1 = tcg_const_i32(r1); tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); - gen_helper_dlg(tmp32_1, tmp2); + gen_helper_dlg(cpu_env, tmp32_1, tmp2); tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); break; @@ -1842,7 +1837,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); /* XXX possible optimization point */ gen_op_calc_cc(s); - gen_helper_slbg(cc_op, cc_op, tmp32_1, regs[r1], tmp2); + gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, regs[r1], tmp2); set_cc_static(s); tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); @@ -1922,7 +1917,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) tcg_gen_trunc_i64_i32(tmp32_2, tmp2); /* XXX possible optimization point */ gen_op_calc_cc(s); - gen_helper_slb(cc_op, cc_op, tmp32_1, tmp32_2); + gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_1, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp2); tcg_temp_free_i32(tmp32_1); @@ -2099,7 +2094,7 @@ do_mh: tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_stcmh(tmp32_1, tmp, tmp32_2); + gen_helper_stcmh(cpu_env, tmp32_1, tmp, tmp32_2); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -2112,7 +2107,7 @@ do_mh: tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_lctlg(tmp32_1, tmp, tmp32_2); + gen_helper_lctlg(cpu_env, tmp32_1, tmp, tmp32_2); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -2124,7 +2119,7 @@ do_mh: tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_stctg(tmp32_1, tmp, tmp32_2); + gen_helper_stctg(cpu_env, tmp32_1, tmp, tmp32_2); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -2136,7 +2131,7 @@ do_mh: tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); /* XXX rewrite in tcg */ - gen_helper_csg(cc_op, tmp32_1, tmp, tmp32_2); + gen_helper_csg(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -2148,7 +2143,7 @@ do_mh: tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); /* XXX rewrite in tcg */ - gen_helper_cdsg(cc_op, tmp32_1, tmp, tmp32_2); + gen_helper_cdsg(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -2188,7 +2183,7 @@ do_mh: tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); /* XXX split CC calculation out */ - gen_helper_icmh(cc_op, tmp32_1, tmp, tmp32_2); + gen_helper_icmh(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -2211,11 +2206,11 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, switch (op) { case 0x4: /* LDEB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_ldeb(tmp_r1, addr); + gen_helper_ldeb(cpu_env, tmp_r1, addr); break; case 0x5: /* LXDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_lxdb(tmp_r1, addr); + gen_helper_lxdb(cpu_env, tmp_r1, addr); break; case 0x9: /* CEB R1,D2(X2,B2) [RXE] */ tmp = tcg_temp_new_i64(); @@ -2230,12 +2225,12 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, tmp32 = tcg_temp_new_i32(); tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_aeb(tmp_r1, tmp32); + gen_helper_aeb(cpu_env, tmp_r1, tmp32); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32); tmp32 = load_freg32(r1); - set_cc_nz_f32(s, tmp32); + gen_set_cc_nz_f32(s, tmp32); tcg_temp_free_i32(tmp32); break; case 0xb: /* SEB R1,D2(X2,B2) [RXE] */ @@ -2243,12 +2238,12 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, tmp32 = tcg_temp_new_i32(); tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_seb(tmp_r1, tmp32); + gen_helper_seb(cpu_env, tmp_r1, tmp32); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32); tmp32 = load_freg32(r1); - set_cc_nz_f32(s, tmp32); + gen_set_cc_nz_f32(s, tmp32); tcg_temp_free_i32(tmp32); break; case 0xd: /* DEB R1,D2(X2,B2) [RXE] */ @@ -2256,23 +2251,23 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, tmp32 = tcg_temp_new_i32(); tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_deb(tmp_r1, tmp32); + gen_helper_deb(cpu_env, tmp_r1, tmp32); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32); break; case 0x10: /* TCEB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_tceb(cc_op, tmp_r1, addr); + gen_helper_tceb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; case 0x11: /* TCDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_tcdb(cc_op, tmp_r1, addr); + gen_helper_tcdb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; case 0x12: /* TCXB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_tcxb(cc_op, tmp_r1, addr); + gen_helper_tcxb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; case 0x17: /* MEEB R1,D2(X2,B2) [RXE] */ @@ -2280,38 +2275,38 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, tmp32 = tcg_temp_new_i32(); tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); tcg_gen_trunc_i64_i32(tmp32, tmp); - gen_helper_meeb(tmp_r1, tmp32); + gen_helper_meeb(cpu_env, tmp_r1, tmp32); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32); break; case 0x19: /* CDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_cdb(cc_op, tmp_r1, addr); + gen_helper_cdb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; case 0x1a: /* ADB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_adb(cc_op, tmp_r1, addr); + gen_helper_adb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; case 0x1b: /* SDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_sdb(cc_op, tmp_r1, addr); + gen_helper_sdb(cc_op, cpu_env, tmp_r1, addr); set_cc_static(s); break; case 0x1c: /* MDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_mdb(tmp_r1, addr); + gen_helper_mdb(cpu_env, tmp_r1, addr); break; case 0x1d: /* DDB R1,D2(X2,B2) [RXE] */ potential_page_fault(s); - gen_helper_ddb(tmp_r1, addr); + gen_helper_ddb(cpu_env, tmp_r1, addr); break; case 0x1e: /* MADB R1,R3,D2(X2,B2) [RXF] */ /* for RXF insns, r1 is R3 and r1b is R1 */ tmp32 = tcg_const_i32(r1b); potential_page_fault(s); - gen_helper_madb(tmp32, addr, tmp_r1); + gen_helper_madb(cpu_env, tmp32, addr, tmp_r1); tcg_temp_free_i32(tmp32); break; default: @@ -2633,14 +2628,14 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) case 0x22: /* IPM R1 [RRE] */ tmp32_1 = tcg_const_i32(r1); gen_op_calc_cc(s); - gen_helper_ipm(cc_op, tmp32_1); + gen_helper_ipm(cpu_env, cc_op, tmp32_1); tcg_temp_free_i32(tmp32_1); break; case 0x41: /* CKSM R1,R2 [RRE] */ tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r2); potential_page_fault(s); - gen_helper_cksm(tmp32_1, tmp32_2); + gen_helper_cksm(cpu_env, tmp32_1, tmp32_2); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); gen_op_movi_cc(s, 0); @@ -2669,7 +2664,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tmp2 = load_reg(r1); tmp3 = load_reg(r2); potential_page_fault(s); - gen_helper_mvpg(tmp, tmp2, tmp3); + gen_helper_mvpg(cpu_env, tmp, tmp2, tmp3); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp3); @@ -2681,7 +2676,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tmp32_2 = tcg_const_i32(r1); tmp32_3 = tcg_const_i32(r2); potential_page_fault(s); - gen_helper_mvst(tmp32_1, tmp32_2, tmp32_3); + gen_helper_mvst(cpu_env, tmp32_1, tmp32_2, tmp32_3); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); tcg_temp_free_i32(tmp32_3); @@ -2692,7 +2687,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tmp32_2 = tcg_const_i32(r1); tmp32_3 = tcg_const_i32(r2); potential_page_fault(s); - gen_helper_clst(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_clst(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -2703,7 +2698,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tmp32_2 = tcg_const_i32(r1); tmp32_3 = tcg_const_i32(r2); potential_page_fault(s); - gen_helper_srst(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_srst(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -2717,7 +2712,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_stidp(tmp); + gen_helper_stidp(cpu_env, tmp); tcg_temp_free_i64(tmp); break; case 0x04: /* SCK D2(B2) [S] */ @@ -2735,7 +2730,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_stck(cc_op, tmp); + gen_helper_stck(cc_op, cpu_env, tmp); set_cc_static(s); tcg_temp_free_i64(tmp); break; @@ -2745,7 +2740,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_sckc(tmp); + gen_helper_sckc(cpu_env, tmp); tcg_temp_free_i64(tmp); break; case 0x07: /* STCKC D2(B2) [S] */ @@ -2754,7 +2749,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_stckc(tmp); + gen_helper_stckc(cpu_env, tmp); tcg_temp_free_i64(tmp); break; case 0x08: /* SPT D2(B2) [S] */ @@ -2763,7 +2758,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_spt(tmp); + gen_helper_spt(cpu_env, tmp); tcg_temp_free_i64(tmp); break; case 0x09: /* STPT D2(B2) [S] */ @@ -2772,7 +2767,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_stpt(tmp); + gen_helper_stpt(cpu_env, tmp); tcg_temp_free_i64(tmp); break; case 0x0a: /* SPKA D2(B2) [S] */ @@ -2790,7 +2785,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) case 0x0d: /* PTLB [S] */ /* Purge TLB */ check_privileged(s, ilc); - gen_helper_ptlb(); + gen_helper_ptlb(cpu_env); break; case 0x10: /* SPX D2(B2) [S] */ /* Set Prefix Register */ @@ -2798,7 +2793,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_spx(tmp); + gen_helper_spx(cpu_env, tmp); tcg_temp_free_i64(tmp); break; case 0x11: /* STPX D2(B2) [S] */ @@ -2833,7 +2828,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) r2 = insn & 0xf; tmp = load_reg(r1); tmp2 = load_reg(r2); - gen_helper_ipte(tmp, tmp2); + gen_helper_ipte(cpu_env, tmp, tmp2); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); break; @@ -2844,7 +2839,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) r2 = insn & 0xf; tmp = load_reg(r2); tmp2 = tcg_temp_new_i64(); - gen_helper_iske(tmp2, tmp); + gen_helper_iske(tmp2, cpu_env, tmp); store_reg(r1, tmp2); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); @@ -2856,7 +2851,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) r2 = insn & 0xf; tmp32_1 = load_reg32(r1); tmp = load_reg(r2); - gen_helper_rrbe(cc_op, tmp32_1, tmp); + gen_helper_rrbe(cc_op, cpu_env, tmp32_1, tmp); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); @@ -2868,7 +2863,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) r2 = insn & 0xf; tmp32_1 = load_reg32(r1); tmp = load_reg(r2); - gen_helper_sske(tmp32_1, tmp); + gen_helper_sske(cpu_env, tmp32_1, tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; @@ -2885,7 +2880,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tmp32_1 = load_reg32(r1); tmp = load_reg(r2); potential_page_fault(s); - gen_helper_stura(tmp, tmp32_1); + gen_helper_stura(cpu_env, tmp, tmp32_1); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; @@ -2896,7 +2891,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) r2 = insn & 0xf; tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r2); - gen_helper_csp(cc_op, tmp32_1, tmp32_2); + gen_helper_csp(cc_op, cpu_env, tmp32_1, tmp32_2); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -2911,7 +2906,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_stcke(cc_op, tmp); + gen_helper_stcke(cc_op, cpu_env, tmp); set_cc_static(s); tcg_temp_free_i64(tmp); break; @@ -2921,7 +2916,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) decode_rs(s, insn, &r1, &r3, &b2, &d2); tmp = get_address(s, 0, b2, d2); potential_page_fault(s); - gen_helper_sacf(tmp); + gen_helper_sacf(cpu_env, tmp); tcg_temp_free_i64(tmp); /* addressing mode has changed, so end the block */ s->pc += ilc * 2; @@ -2935,7 +2930,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tmp32_1 = load_reg32(0); tmp32_2 = load_reg32(1); potential_page_fault(s); - gen_helper_stsi(cc_op, tmp, tmp32_1, tmp32_2); + gen_helper_stsi(cc_op, cpu_env, tmp, tmp32_1, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -2972,7 +2967,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s)); tcg_gen_addi_i64(tmp, tmp, 8); tcg_gen_qemu_ld64(tmp3, tmp, get_mem_index(s)); - gen_helper_load_psw(tmp2, tmp3); + gen_helper_load_psw(cpu_env, tmp2, tmp3); /* we need to keep cc_op intact */ s->is_jmp = DISAS_JUMP; tcg_temp_free_i64(tmp); @@ -2985,7 +2980,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) potential_page_fault(s); tmp32_1 = load_reg32(r2); tmp = load_reg(r1); - gen_helper_servc(cc_op, tmp32_1, tmp); + gen_helper_servc(cc_op, cpu_env, tmp32_1, tmp); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); @@ -3006,14 +3001,14 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) #define FP_HELPER(i) \ tmp32_1 = tcg_const_i32(r1); \ tmp32_2 = tcg_const_i32(r2); \ - gen_helper_ ## i (tmp32_1, tmp32_2); \ + gen_helper_ ## i(cpu_env, tmp32_1, tmp32_2); \ tcg_temp_free_i32(tmp32_1); \ tcg_temp_free_i32(tmp32_2); #define FP_HELPER_CC(i) \ tmp32_1 = tcg_const_i32(r1); \ tmp32_2 = tcg_const_i32(r2); \ - gen_helper_ ## i (cc_op, tmp32_1, tmp32_2); \ + gen_helper_ ## i(cc_op, cpu_env, tmp32_1, tmp32_2); \ set_cc_static(s); \ tcg_temp_free_i32(tmp32_1); \ tcg_temp_free_i32(tmp32_2); @@ -3085,13 +3080,13 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) tmp32_3 = tcg_const_i32(r1); switch (op) { case 0xe: - gen_helper_maebr(tmp32_1, tmp32_3, tmp32_2); + gen_helper_maebr(cpu_env, tmp32_1, tmp32_3, tmp32_2); break; case 0x1e: - gen_helper_madbr(tmp32_1, tmp32_3, tmp32_2); + gen_helper_madbr(cpu_env, tmp32_1, tmp32_3, tmp32_2); break; case 0x1f: - gen_helper_msdbr(tmp32_1, tmp32_3, tmp32_2); + gen_helper_msdbr(cpu_env, tmp32_1, tmp32_3, tmp32_2); break; default: tcg_abort(); @@ -3143,17 +3138,17 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) break; case 0x74: /* LZER R1 [RRE] */ tmp32_1 = tcg_const_i32(r1); - gen_helper_lzer(tmp32_1); + gen_helper_lzer(cpu_env, tmp32_1); tcg_temp_free_i32(tmp32_1); break; case 0x75: /* LZDR R1 [RRE] */ tmp32_1 = tcg_const_i32(r1); - gen_helper_lzdr(tmp32_1); + gen_helper_lzdr(cpu_env, tmp32_1); tcg_temp_free_i32(tmp32_1); break; case 0x76: /* LZXR R1 [RRE] */ tmp32_1 = tcg_const_i32(r1); - gen_helper_lzxr(tmp32_1); + gen_helper_lzxr(cpu_env, tmp32_1); tcg_temp_free_i32(tmp32_1); break; case 0x84: /* SFPC R1 [RRE] */ @@ -3174,13 +3169,13 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) tmp32_2 = load_reg32(r2); switch (op) { case 0x94: - gen_helper_cefbr(tmp32_1, tmp32_2); + gen_helper_cefbr(cpu_env, tmp32_1, tmp32_2); break; case 0x95: - gen_helper_cdfbr(tmp32_1, tmp32_2); + gen_helper_cdfbr(cpu_env, tmp32_1, tmp32_2); break; case 0x96: - gen_helper_cxfbr(tmp32_1, tmp32_2); + gen_helper_cxfbr(cpu_env, tmp32_1, tmp32_2); break; default: tcg_abort(); @@ -3196,13 +3191,13 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) tmp32_3 = tcg_const_i32(m3); switch (op) { case 0x98: - gen_helper_cfebr(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_cfebr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); break; case 0x99: - gen_helper_cfdbr(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_cfdbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); break; case 0x9a: - gen_helper_cfxbr(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_cfxbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); break; default: tcg_abort(); @@ -3218,10 +3213,10 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) tmp = load_reg(r2); switch (op) { case 0xa4: - gen_helper_cegbr(tmp32_1, tmp); + gen_helper_cegbr(cpu_env, tmp32_1, tmp); break; case 0xa5: - gen_helper_cdgbr(tmp32_1, tmp); + gen_helper_cdgbr(cpu_env, tmp32_1, tmp); break; default: tcg_abort(); @@ -3232,7 +3227,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) case 0xa6: /* CXGBR R1,R2 [RRE] */ tmp32_1 = tcg_const_i32(r1); tmp = load_reg(r2); - gen_helper_cxgbr(tmp32_1, tmp); + gen_helper_cxgbr(cpu_env, tmp32_1, tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp); break; @@ -3240,7 +3235,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r2); tmp32_3 = tcg_const_i32(m3); - gen_helper_cgebr(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_cgebr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -3250,7 +3245,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r2); tmp32_3 = tcg_const_i32(m3); - gen_helper_cgdbr(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_cgdbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -3260,7 +3255,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r2); tmp32_3 = tcg_const_i32(m3); - gen_helper_cgxbr(cc_op, tmp32_1, tmp32_2, tmp32_3); + gen_helper_cgxbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -3540,7 +3535,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2) case 0x83: /* FLOGR R1,R2 [RRE] */ tmp = load_reg(r2); tmp32_1 = tcg_const_i32(r1); - gen_helper_flogr(cc_op, tmp32_1, tmp); + gen_helper_flogr(cc_op, cpu_env, tmp32_1, tmp); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -3560,7 +3555,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2) case 0x87: /* DLGR R1,R2 [RRE] */ tmp32_1 = tcg_const_i32(r1); tmp = load_reg(r2); - gen_helper_dlg(tmp32_1, tmp); + gen_helper_dlg(cpu_env, tmp32_1, tmp); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); break; @@ -3585,7 +3580,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2) tmp2 = load_reg(r2); tmp32_1 = tcg_const_i32(r1); gen_op_calc_cc(s); - gen_helper_slbg(cc_op, cc_op, tmp32_1, tmp, tmp2); + gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, tmp, tmp2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); @@ -3652,7 +3647,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2) tmp32_1 = load_reg32(r2); tmp32_2 = tcg_const_i32(r1); gen_op_calc_cc(s); - gen_helper_slb(cc_op, cc_op, tmp32_2, tmp32_1); + gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_2, tmp32_1); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -3870,7 +3865,7 @@ static void disas_s390_insn(DisasContext *s) int ilc; int l1; - opc = ldub_code(s->pc); + opc = cpu_ldub_code(cpu_single_env, s->pc); LOG_DISAS("opc 0x%x\n", opc); ilc = get_ilc(opc); @@ -3931,7 +3926,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_3 = tcg_const_i32(EXCP_SVC); tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, int_svc_code)); tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUS390XState, int_svc_ilc)); - gen_helper_exception(tmp32_3); + gen_helper_exception(cpu_env, tmp32_3); s->is_jmp = DISAS_EXCP; tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -3956,7 +3951,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r2); potential_page_fault(s); - gen_helper_mvcl(cc_op, tmp32_1, tmp32_2); + gen_helper_mvcl(cc_op, cpu_env, tmp32_1, tmp32_2); set_cc_static(s); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -4170,7 +4165,7 @@ static void disas_s390_insn(DisasContext *s) tmp3 = tcg_const_i64(s->pc + 4); update_psw_addr(s); gen_op_calc_cc(s); - gen_helper_ex(cc_op, cc_op, tmp2, tmp, tmp3); + gen_helper_ex(cc_op, cpu_env, cc_op, tmp2, tmp, tmp3); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); @@ -4532,7 +4527,7 @@ static void disas_s390_insn(DisasContext *s) tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); tcg_gen_addi_i64(tmp, tmp, 4); tcg_gen_qemu_ld32u(tmp3, tmp, get_mem_index(s)); - gen_helper_load_psw(tmp2, tmp3); + gen_helper_load_psw(cpu_env, tmp2, tmp3); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); tcg_temp_free_i64(tmp3); @@ -4548,7 +4543,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(insn & 0xfff); tmp2 = load_reg(2); tmp3 = load_reg(1); - gen_helper_diag(tmp2, tmp32_1, tmp2, tmp3); + gen_helper_diag(tmp2, cpu_env, tmp32_1, tmp2, tmp3); store_reg(2, tmp2); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i64(tmp2); @@ -4699,7 +4694,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_lam(tmp32_1, tmp, tmp32_2); + gen_helper_lam(cpu_env, tmp32_1, tmp, tmp32_2); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -4711,7 +4706,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_stam(tmp32_1, tmp, tmp32_2); + gen_helper_stam(cpu_env, tmp32_1, tmp, tmp32_2); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -4737,7 +4732,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_mvcle(cc_op, tmp32_1, tmp, tmp32_2); + gen_helper_mvcle(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -4750,7 +4745,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_clcle(cc_op, tmp32_1, tmp, tmp32_2); + gen_helper_clcle(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -4782,7 +4777,7 @@ static void disas_s390_insn(DisasContext *s) tmp2 = load_reg(r3); tmp32_1 = tcg_const_i32(r1); potential_page_fault(s); - gen_helper_sigp(cc_op, tmp, tmp32_1, tmp2); + gen_helper_sigp(cc_op, cpu_env, tmp, tmp32_1, tmp2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i64(tmp2); @@ -4794,7 +4789,7 @@ static void disas_s390_insn(DisasContext *s) tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); tmp32_1 = tcg_const_i32(r1); potential_page_fault(s); - gen_helper_lra(cc_op, tmp, tmp32_1); + gen_helper_lra(cc_op, cpu_env, tmp, tmp32_1); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -4840,7 +4835,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_stctl(tmp32_1, tmp, tmp32_2); + gen_helper_stctl(cpu_env, tmp32_1, tmp, tmp32_2); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -4854,7 +4849,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_lctl(tmp32_1, tmp, tmp32_2); + gen_helper_lctl(cpu_env, tmp32_1, tmp, tmp32_2); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -4874,7 +4869,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = tcg_const_i32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_cs(cc_op, tmp32_1, tmp, tmp32_2); + gen_helper_cs(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -4887,7 +4882,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = load_reg32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_clm(cc_op, tmp32_1, tmp32_2, tmp); + gen_helper_clm(cc_op, cpu_env, tmp32_1, tmp32_2, tmp); set_cc_static(s); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); @@ -4900,7 +4895,7 @@ static void disas_s390_insn(DisasContext *s) tmp32_1 = load_reg32(r1); tmp32_2 = tcg_const_i32(r3); potential_page_fault(s); - gen_helper_stcm(tmp32_1, tmp32_2, tmp); + gen_helper_stcm(cpu_env, tmp32_1, tmp32_2, tmp); tcg_temp_free_i64(tmp); tcg_temp_free_i32(tmp32_1); tcg_temp_free_i32(tmp32_2); @@ -4997,7 +4992,7 @@ static void disas_s390_insn(DisasContext *s) break; case 0xd4: potential_page_fault(s); - gen_helper_nc(cc_op, vl, tmp, tmp2); + gen_helper_nc(cc_op, cpu_env, vl, tmp, tmp2); set_cc_static(s); break; case 0xd5: @@ -5005,22 +5000,22 @@ static void disas_s390_insn(DisasContext *s) break; case 0xd6: potential_page_fault(s); - gen_helper_oc(cc_op, vl, tmp, tmp2); + gen_helper_oc(cc_op, cpu_env, vl, tmp, tmp2); set_cc_static(s); break; case 0xd7: potential_page_fault(s); - gen_helper_xc(cc_op, vl, tmp, tmp2); + gen_helper_xc(cc_op, cpu_env, vl, tmp, tmp2); set_cc_static(s); break; case 0xdc: potential_page_fault(s); - gen_helper_tr(vl, tmp, tmp2); + gen_helper_tr(cpu_env, vl, tmp, tmp2); set_cc_static(s); break; case 0xf3: potential_page_fault(s); - gen_helper_unpk(vl, tmp, tmp2); + gen_helper_unpk(cpu_env, vl, tmp, tmp2); break; default: tcg_abort(); @@ -5045,9 +5040,9 @@ static void disas_s390_insn(DisasContext *s) tmp2 = get_address(s, 0, b1, d1); tmp3 = get_address(s, 0, b2, d2); if (opc == 0xda) { - gen_helper_mvcp(cc_op, tmp, tmp2, tmp3); + gen_helper_mvcp(cc_op, cpu_env, tmp, tmp2, tmp3); } else { - gen_helper_mvcs(cc_op, tmp, tmp2, tmp3); + gen_helper_mvcs(cc_op, cpu_env, tmp, tmp2, tmp3); } set_cc_static(s); tcg_temp_free_i64(tmp); diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c index 9c64ef8..f4b62a5 100644 --- a/target-sparc/fop_helper.c +++ b/target-sparc/fop_helper.c @@ -334,34 +334,28 @@ void helper_fsqrtq(CPUSPARCState *env) } #define GEN_FCMP(name, size, reg1, reg2, FS, E) \ - void glue(helper_, name) (CPUSPARCState *env) \ + void glue(helper_, name) (CPUSPARCState *env) \ { \ - env->fsr &= FSR_FTT_NMASK; \ - if (E && (glue(size, _is_any_nan)(reg1) || \ - glue(size, _is_any_nan)(reg2)) && \ - (env->fsr & FSR_NVM)) { \ - env->fsr |= FSR_NVC; \ - env->fsr |= FSR_FTT_IEEE_EXCP; \ - helper_raise_exception(env, TT_FP_EXCP); \ + int ret; \ + clear_float_exceptions(env); \ + if (E) { \ + ret = glue(size, _compare)(reg1, reg2, &env->fp_status); \ + } else { \ + ret = glue(size, _compare_quiet)(reg1, reg2, \ + &env->fp_status); \ } \ - switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \ + check_ieee_exceptions(env); \ + switch (ret) { \ case float_relation_unordered: \ - if ((env->fsr & FSR_NVM)) { \ - env->fsr |= FSR_NVC; \ - env->fsr |= FSR_FTT_IEEE_EXCP; \ - helper_raise_exception(env, TT_FP_EXCP); \ - } else { \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ - env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ - env->fsr |= FSR_NVA; \ - } \ + env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ + env->fsr |= FSR_NVA; \ break; \ case float_relation_less: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr &= ~(FSR_FCC1) << FS; \ env->fsr |= FSR_FCC0 << FS; \ break; \ case float_relation_greater: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr &= ~(FSR_FCC0) << FS; \ env->fsr |= FSR_FCC1 << FS; \ break; \ default: \ @@ -370,34 +364,27 @@ void helper_fsqrtq(CPUSPARCState *env) } \ } #define GEN_FCMP_T(name, size, FS, E) \ - void glue(helper_, name)(CPUSPARCState *env, size src1, size src2) \ + void glue(helper_, name)(CPUSPARCState *env, size src1, size src2) \ { \ - env->fsr &= FSR_FTT_NMASK; \ - if (E && (glue(size, _is_any_nan)(src1) || \ - glue(size, _is_any_nan)(src2)) && \ - (env->fsr & FSR_NVM)) { \ - env->fsr |= FSR_NVC; \ - env->fsr |= FSR_FTT_IEEE_EXCP; \ - helper_raise_exception(env, TT_FP_EXCP); \ + int ret; \ + clear_float_exceptions(env); \ + if (E) { \ + ret = glue(size, _compare)(src1, src2, &env->fp_status); \ + } else { \ + ret = glue(size, _compare_quiet)(src1, src2, \ + &env->fp_status); \ } \ - switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \ + check_ieee_exceptions(env); \ + switch (ret) { \ case float_relation_unordered: \ - if ((env->fsr & FSR_NVM)) { \ - env->fsr |= FSR_NVC; \ - env->fsr |= FSR_FTT_IEEE_EXCP; \ - helper_raise_exception(env, TT_FP_EXCP); \ - } else { \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ - env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ - env->fsr |= FSR_NVA; \ - } \ + env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ break; \ case float_relation_less: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr &= ~(FSR_FCC1 << FS); \ env->fsr |= FSR_FCC0 << FS; \ break; \ case float_relation_greater: \ - env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ + env->fsr &= ~(FSR_FCC0 << FS); \ env->fsr |= FSR_FCC1 << FS; \ break; \ default: \ diff --git a/target-xtensa/xtensa-semi.c b/target-xtensa/xtensa-semi.c index 6d001c2..52be07a 100644 --- a/target-xtensa/xtensa-semi.c +++ b/target-xtensa/xtensa-semi.c @@ -54,6 +54,102 @@ enum { SELECT_ONE_EXCEPT = 3, }; +enum { + TARGET_EPERM = 1, + TARGET_ENOENT = 2, + TARGET_ESRCH = 3, + TARGET_EINTR = 4, + TARGET_EIO = 5, + TARGET_ENXIO = 6, + TARGET_E2BIG = 7, + TARGET_ENOEXEC = 8, + TARGET_EBADF = 9, + TARGET_ECHILD = 10, + TARGET_EAGAIN = 11, + TARGET_ENOMEM = 12, + TARGET_EACCES = 13, + TARGET_EFAULT = 14, + TARGET_ENOTBLK = 15, + TARGET_EBUSY = 16, + TARGET_EEXIST = 17, + TARGET_EXDEV = 18, + TARGET_ENODEV = 19, + TARGET_ENOTDIR = 20, + TARGET_EISDIR = 21, + TARGET_EINVAL = 22, + TARGET_ENFILE = 23, + TARGET_EMFILE = 24, + TARGET_ENOTTY = 25, + TARGET_ETXTBSY = 26, + TARGET_EFBIG = 27, + TARGET_ENOSPC = 28, + TARGET_ESPIPE = 29, + TARGET_EROFS = 30, + TARGET_EMLINK = 31, + TARGET_EPIPE = 32, + TARGET_EDOM = 33, + TARGET_ERANGE = 34, + TARGET_ENOSYS = 88, + TARGET_ELOOP = 92, +}; + +static uint32_t errno_h2g(int host_errno) +{ + static const uint32_t guest_errno[] = { + [EPERM] = TARGET_EPERM, + [ENOENT] = TARGET_ENOENT, + [ESRCH] = TARGET_ESRCH, + [EINTR] = TARGET_EINTR, + [EIO] = TARGET_EIO, + [ENXIO] = TARGET_ENXIO, + [E2BIG] = TARGET_E2BIG, + [ENOEXEC] = TARGET_ENOEXEC, + [EBADF] = TARGET_EBADF, + [ECHILD] = TARGET_ECHILD, + [EAGAIN] = TARGET_EAGAIN, + [ENOMEM] = TARGET_ENOMEM, + [EACCES] = TARGET_EACCES, + [EFAULT] = TARGET_EFAULT, +#ifdef ENOTBLK + [ENOTBLK] = TARGET_ENOTBLK, +#endif + [EBUSY] = TARGET_EBUSY, + [EEXIST] = TARGET_EEXIST, + [EXDEV] = TARGET_EXDEV, + [ENODEV] = TARGET_ENODEV, + [ENOTDIR] = TARGET_ENOTDIR, + [EISDIR] = TARGET_EISDIR, + [EINVAL] = TARGET_EINVAL, + [ENFILE] = TARGET_ENFILE, + [EMFILE] = TARGET_EMFILE, + [ENOTTY] = TARGET_ENOTTY, +#ifdef ETXTBSY + [ETXTBSY] = TARGET_ETXTBSY, +#endif + [EFBIG] = TARGET_EFBIG, + [ENOSPC] = TARGET_ENOSPC, + [ESPIPE] = TARGET_ESPIPE, + [EROFS] = TARGET_EROFS, + [EMLINK] = TARGET_EMLINK, + [EPIPE] = TARGET_EPIPE, + [EDOM] = TARGET_EDOM, + [ERANGE] = TARGET_ERANGE, + [ENOSYS] = TARGET_ENOSYS, +#ifdef ELOOP + [ELOOP] = TARGET_ELOOP, +#endif + }; + + if (host_errno == 0) { + return 0; + } else if (host_errno > 0 && host_errno < ARRAY_SIZE(guest_errno) && + guest_errno[host_errno]) { + return guest_errno[host_errno]; + } else { + return TARGET_EINVAL; + } +} + void HELPER(simcall)(CPUXtensaState *env) { uint32_t *regs = env->regs; @@ -87,14 +183,14 @@ void HELPER(simcall)(CPUXtensaState *env) regs[2] = is_write ? write(fd, buf, io_sz) : read(fd, buf, io_sz); - regs[3] = errno; + regs[3] = errno_h2g(errno); cpu_physical_memory_unmap(buf, sz, is_write, sz); if (regs[2] == -1) { break; } } else { regs[2] = -1; - regs[3] = EINVAL; + regs[3] = TARGET_EINVAL; break; } } @@ -117,10 +213,10 @@ void HELPER(simcall)(CPUXtensaState *env) if (rc == 0 && i < ARRAY_SIZE(name)) { regs[2] = open(name, regs[4], regs[5]); - regs[3] = errno; + regs[3] = errno_h2g(errno); } else { regs[2] = -1; - regs[3] = EINVAL; + regs[3] = TARGET_EINVAL; } } break; @@ -130,13 +226,13 @@ void HELPER(simcall)(CPUXtensaState *env) regs[2] = regs[3] = 0; } else { regs[2] = close(regs[3]); - regs[3] = errno; + regs[3] = errno_h2g(errno); } break; case TARGET_SYS_lseek: regs[2] = lseek(regs[3], (off_t)(int32_t)regs[4], regs[5]); - regs[3] = errno; + regs[3] = errno_h2g(errno); break; case TARGET_SYS_select_one: @@ -163,7 +259,7 @@ void HELPER(simcall)(CPUXtensaState *env) rq == SELECT_ONE_WRITE ? &fdset : NULL, rq == SELECT_ONE_EXCEPT ? &fdset : NULL, target_tv ? &tv : NULL); - regs[3] = errno; + regs[3] = errno_h2g(errno); } break; @@ -219,7 +315,7 @@ void HELPER(simcall)(CPUXtensaState *env) default: qemu_log("%s(%d): not implemented\n", __func__, regs[2]); regs[2] = -1; - regs[3] = ENOSYS; + regs[3] = TARGET_ENOSYS; break; } } diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index 04662c1..99b5339 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -1509,11 +1509,13 @@ static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R4, mem_index); #ifdef CONFIG_TCG_PASS_AREG0 /* XXX/FIXME: suboptimal */ - tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], tcg_target_call_iarg_regs[1]); - tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[1], tcg_target_call_iarg_regs[0]); - tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], TCG_AREG0); #endif tgen_calli(s, (tcg_target_ulong)qemu_st_helpers[s_bits]); @@ -1521,13 +1523,11 @@ static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index); #ifdef CONFIG_TCG_PASS_AREG0 /* XXX/FIXME: suboptimal */ - tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], - tcg_target_call_iarg_regs[2]); tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], tcg_target_call_iarg_regs[1]); - tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[1], tcg_target_call_iarg_regs[0]); - tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], TCG_AREG0); #endif tgen_calli(s, (tcg_target_ulong)qemu_ld_helpers[s_bits]); |