diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2021-07-04 14:04:12 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-07-04 14:04:12 +0100 |
commit | 711c0418c8c1ce3a24346f058b001c4c5a2f0f81 (patch) | |
tree | 022f1fd134bdf5f6680313f7fed3e962a0439b88 | |
parent | 73c8bf4ccff8951d228b8a0d49968c56e32da4de (diff) | |
parent | a13bfa5a056b2ffe5f2ce71170c15772fa3b2cda (diff) | |
download | qemu-711c0418c8c1ce3a24346f058b001c4c5a2f0f81.zip qemu-711c0418c8c1ce3a24346f058b001c4c5a2f0f81.tar.gz qemu-711c0418c8c1ce3a24346f058b001c4c5a2f0f81.tar.bz2 |
Merge remote-tracking branch 'remotes/philmd/tags/mips-20210702' into staging
MIPS patches queue
- Extract nanoMIPS, microMIPS, Code Compaction from translate.c
- Allow PCI config accesses smaller than 32-bit on Bonito64 device
- Fix migration of g364fb device on Jazz Magnum
- Fix dp8393x PROM checksum on Jazz Magnum and Quadra 800
- Map the UART devices unconditionally on Jazz Magnum
- Add functional test booting Linux on the Fuloong 2E
# gpg: Signature made Fri 02 Jul 2021 16:36:19 BST
# gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE
# gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full]
# Primary key fingerprint: FAAB E75E 1291 7221 DCFD 6BB2 E3E3 2C2C DEAD C0DE
* remotes/philmd/tags/mips-20210702:
hw/mips/jazz: Map the UART devices unconditionally
hw/mips/jazz: specify correct endian for dp8393x device
hw/m68k/q800: fix PROM checksum and MAC address storage
qemu/bitops.h: add bitrev8 implementation
dp8393x: remove onboard PROM containing MAC address and checksum
hw/m68k/q800: move PROM and checksum calculation from dp8393x device to board
hw/mips/jazz: move PROM and checksum calculation from dp8393x device to board
dp8393x: convert to trace-events
dp8393x: checkpatch fixes
g364fb: add VMStateDescription for G364SysBusState
g364fb: use RAM memory region for framebuffer
tests/acceptance: Test Linux on the Fuloong 2E machine
hw/pci-host/bonito: Allow PCI config accesses smaller than 32-bit
hw/pci-host/bonito: Trace PCI config accesses smaller than 32-bit
target/mips: Extract nanoMIPS ISA translation routines
target/mips: Extract the microMIPS ISA translation routines
target/mips: Extract Code Compaction ASE translation routines
target/mips: Add declarations for generic TCG helpers
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | MAINTAINERS | 2 | ||||
-rw-r--r-- | hw/display/g364fb.c | 32 | ||||
-rw-r--r-- | hw/m68k/q800.c | 21 | ||||
-rw-r--r-- | hw/mips/jazz.c | 48 | ||||
-rw-r--r-- | hw/net/dp8393x.c | 302 | ||||
-rw-r--r-- | hw/net/trace-events | 17 | ||||
-rw-r--r-- | hw/pci-host/bonito.c | 12 | ||||
-rw-r--r-- | hw/pci-host/trace-events | 3 | ||||
-rw-r--r-- | include/qemu/bitops.h | 22 | ||||
-rw-r--r-- | target/mips/tcg/micromips_translate.c.inc | 3231 | ||||
-rw-r--r-- | target/mips/tcg/mips16e_translate.c.inc | 1123 | ||||
-rw-r--r-- | target/mips/tcg/nanomips_translate.c.inc | 4922 | ||||
-rw-r--r-- | target/mips/tcg/translate.c | 9277 | ||||
-rw-r--r-- | target/mips/tcg/translate.h | 5 | ||||
-rw-r--r-- | tests/acceptance/machine_mips_fuloong2e.py | 42 |
15 files changed, 9603 insertions, 9456 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index cfbf7ef..cb8f3ea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -246,6 +246,7 @@ K: ^Subject:.*(?i)mips MIPS TCG CPUs (nanoMIPS ISA) S: Orphan F: disas/nanomips.* +F: target/mips/tcg/*nanomips* NiosII TCG CPUs M: Chris Wulff <crwulff@gmail.com> @@ -1177,6 +1178,7 @@ F: hw/isa/vt82c686.c F: hw/pci-host/bonito.c F: hw/usb/vt82c686-uhci-pci.c F: include/hw/isa/vt82c686.h +F: tests/acceptance/machine_mips_fuloong2e.py Loongson-3 virtual platforms M: Huacai Chen <chenhuacai@kernel.org> diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c index 8f17254..caca86d 100644 --- a/hw/display/g364fb.c +++ b/hw/display/g364fb.c @@ -22,6 +22,7 @@ #include "hw/hw.h" #include "hw/irq.h" #include "hw/qdev-properties.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/module.h" #include "ui/console.h" @@ -33,7 +34,6 @@ typedef struct G364State { /* hardware */ - uint8_t *vram; uint32_t vram_size; qemu_irq irq; MemoryRegion mem_vram; @@ -125,7 +125,7 @@ static void g364fb_draw_graphic8(G364State *s) xcursor = ycursor = -65; } - vram = s->vram + s->top_of_screen; + vram = memory_region_get_ram_ptr(&s->mem_vram) + s->top_of_screen; /* XXX: out of range in vram? */ data_display = dd = surface_data(surface); snap = memory_region_snapshot_and_clear_dirty(&s->mem_vram, 0, s->vram_size, @@ -274,6 +274,8 @@ static inline void g364fb_invalidate_display(void *opaque) static void g364fb_reset(G364State *s) { + uint8_t *vram = memory_region_get_ram_ptr(&s->mem_vram); + qemu_irq_lower(s->irq); memset(s->color_palette, 0, sizeof(s->color_palette)); @@ -283,7 +285,7 @@ static void g364fb_reset(G364State *s) s->ctla = 0; s->top_of_screen = 0; s->width = s->height = 0; - memset(s->vram, 0, s->vram_size); + memset(vram, 0, s->vram_size); g364fb_invalidate_display(s); } @@ -450,11 +452,10 @@ static int g364fb_post_load(void *opaque, int version_id) static const VMStateDescription vmstate_g364fb = { .name = "g364fb", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .post_load = g364fb_post_load, .fields = (VMStateField[]) { - VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, vram_size), VMSTATE_BUFFER_UNSAFE(color_palette, G364State, 0, 256 * 3), VMSTATE_BUFFER_UNSAFE(cursor_palette, G364State, 0, 9), VMSTATE_UINT16_ARRAY(cursor, G364State, 512), @@ -474,15 +475,12 @@ static const GraphicHwOps g364fb_ops = { static void g364fb_init(DeviceState *dev, G364State *s) { - s->vram = g_malloc0(s->vram_size); - s->con = graphic_console_init(dev, 0, &g364fb_ops, s); memory_region_init_io(&s->mem_ctrl, OBJECT(dev), &g364fb_ctrl_ops, s, "ctrl", 0x180000); - memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram", - s->vram_size, s->vram); - vmstate_register_ram(&s->mem_vram, dev); + memory_region_init_ram(&s->mem_vram, NULL, "g364fb.vram", s->vram_size, + &error_fatal); memory_region_set_log(&s->mem_vram, true, DIRTY_MEMORY_VGA); } @@ -519,6 +517,16 @@ static Property g364fb_sysbus_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static const VMStateDescription vmstate_g364fb_sysbus = { + .name = "g364fb-sysbus", + .version_id = 2, + .minimum_version_id = 2, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(g364, G364SysBusState, 2, vmstate_g364fb, G364State), + VMSTATE_END_OF_LIST() + } +}; + static void g364fb_sysbus_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -527,7 +535,7 @@ static void g364fb_sysbus_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->desc = "G364 framebuffer"; dc->reset = g364fb_sysbus_reset; - dc->vmsd = &vmstate_g364fb; + dc->vmsd = &vmstate_g364fb_sysbus; device_class_set_props(dc, g364fb_sysbus_properties); } diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 11376da..6817c8b 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -70,6 +70,8 @@ #define NUBUS_SUPER_SLOT_BASE 0x60000000 #define NUBUS_SLOT_BASE 0xf0000000 +#define SONIC_PROM_SIZE 0x1000 + /* * the video base, whereas it a Nubus address, * is needed by the kernel to have early display and @@ -211,8 +213,10 @@ static void q800_init(MachineState *machine) int32_t initrd_size; MemoryRegion *rom; MemoryRegion *io; + MemoryRegion *dp8393x_prom = g_new(MemoryRegion, 1); + uint8_t *prom; const int io_slice_nb = (IO_SIZE / IO_SLICE) - 1; - int i; + int i, checksum; ram_addr_t ram_size = machine->ram_size; const char *kernel_filename = machine->kernel_filename; const char *initrd_filename = machine->initrd_filename; @@ -319,9 +323,22 @@ static void q800_init(MachineState *machine) sysbus = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 0, SONIC_BASE); - sysbus_mmio_map(sysbus, 1, SONIC_PROM_BASE); sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 2)); + memory_region_init_rom(dp8393x_prom, NULL, "dp8393x-q800.prom", + SONIC_PROM_SIZE, &error_fatal); + memory_region_add_subregion(get_system_memory(), SONIC_PROM_BASE, + dp8393x_prom); + + /* Add MAC address with valid checksum to PROM */ + prom = memory_region_get_ram_ptr(dp8393x_prom); + checksum = 0; + for (i = 0; i < 6; i++) { + prom[i] = bitrev8(nd_table[0].macaddr.a[i]); + checksum ^= prom[i]; + } + prom[7] = 0xff - checksum; + /* SCC */ dev = qdev_new(TYPE_ESCC); diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index 1e1cf81..d6183e1 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -119,12 +119,14 @@ static const MemoryRegionOps dma_dummy_ops = { #define MAGNUM_BIOS_SIZE \ (BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX) +#define SONIC_PROM_SIZE 0x1000 + static void mips_jazz_init(MachineState *machine, enum jazz_model_e jazz_model) { MemoryRegion *address_space = get_system_memory(); char *filename; - int bios_size, n; + int bios_size, n, big_endian; Clock *cpuclk; MIPSCPU *cpu; MIPSCPUClass *mcc; @@ -137,6 +139,7 @@ static void mips_jazz_init(MachineState *machine, MemoryRegion *rtc = g_new(MemoryRegion, 1); MemoryRegion *i8042 = g_new(MemoryRegion, 1); MemoryRegion *dma_dummy = g_new(MemoryRegion, 1); + MemoryRegion *dp8393x_prom = g_new(MemoryRegion, 1); NICInfo *nd; DeviceState *dev, *rc4030; SysBusDevice *sysbus; @@ -155,6 +158,12 @@ static void mips_jazz_init(MachineState *machine, [JAZZ_PICA61] = {33333333, 4}, }; +#ifdef TARGET_WORDS_BIGENDIAN + big_endian = 1; +#else + big_endian = 0; +#endif + if (machine->ram_size > 256 * MiB) { error_report("RAM size more than 256Mb is not supported"); exit(EXIT_FAILURE); @@ -228,6 +237,10 @@ static void mips_jazz_init(MachineState *machine, NULL, "dummy_dma", 0x1000); memory_region_add_subregion(address_space, 0x8000d000, dma_dummy); + memory_region_init_rom(dp8393x_prom, NULL, "dp8393x-jazz.prom", + SONIC_PROM_SIZE, &error_fatal); + memory_region_add_subregion(address_space, 0x8000b000, dp8393x_prom); + /* ISA bus: IO space at 0x90000000, mem space at 0x91000000 */ memory_region_init(isa_io, NULL, "isa-io", 0x00010000); memory_region_init(isa_mem, NULL, "isa-mem", 0x01000000); @@ -275,18 +288,33 @@ static void mips_jazz_init(MachineState *machine, nd->model = g_strdup("dp83932"); } if (strcmp(nd->model, "dp83932") == 0) { + int checksum, i; + uint8_t *prom; + qemu_check_nic_model(nd, "dp83932"); dev = qdev_new("dp8393x"); qdev_set_nic_properties(dev, nd); qdev_prop_set_uint8(dev, "it_shift", 2); + qdev_prop_set_bit(dev, "big_endian", big_endian > 0); object_property_set_link(OBJECT(dev), "dma_mr", OBJECT(rc4030_dma_mr), &error_abort); sysbus = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(sysbus, &error_fatal); sysbus_mmio_map(sysbus, 0, 0x80001000); - sysbus_mmio_map(sysbus, 1, 0x8000b000); sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(rc4030, 4)); + + /* Add MAC address with valid checksum to PROM */ + prom = memory_region_get_ram_ptr(dp8393x_prom); + checksum = 0; + for (i = 0; i < 6; i++) { + prom[i] = nd->macaddr.a[i]; + checksum += prom[i]; + if (checksum > 0xff) { + checksum = (checksum + 1) & 0xff; + } + } + prom[7] = 0xff - checksum; break; } else if (is_help_option(nd->model)) { error_report("Supported NICs: dp83932"); @@ -333,16 +361,12 @@ static void mips_jazz_init(MachineState *machine, memory_region_add_subregion(address_space, 0x80005000, i8042); /* Serial ports */ - if (serial_hd(0)) { - serial_mm_init(address_space, 0x80006000, 0, - qdev_get_gpio_in(rc4030, 8), 8000000 / 16, - serial_hd(0), DEVICE_NATIVE_ENDIAN); - } - if (serial_hd(1)) { - serial_mm_init(address_space, 0x80007000, 0, - qdev_get_gpio_in(rc4030, 9), 8000000 / 16, - serial_hd(1), DEVICE_NATIVE_ENDIAN); - } + serial_mm_init(address_space, 0x80006000, 0, + qdev_get_gpio_in(rc4030, 8), 8000000 / 16, + serial_hd(0), DEVICE_NATIVE_ENDIAN); + serial_mm_init(address_space, 0x80007000, 0, + qdev_get_gpio_in(rc4030, 9), 8000000 / 16, + serial_hd(1), DEVICE_NATIVE_ENDIAN); /* Parallel port */ if (parallel_hds[0]) diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index 533a830..252c0a2 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -28,15 +28,9 @@ #include "qemu/timer.h" #include <zlib.h> #include "qom/object.h" +#include "trace.h" -//#define DEBUG_SONIC - -#define SONIC_PROM_SIZE 0x1000 - -#ifdef DEBUG_SONIC -#define DPRINTF(fmt, ...) \ -do { printf("sonic: " fmt , ## __VA_ARGS__); } while (0) -static const char* reg_names[] = { +static const char *reg_names[] = { "CR", "DCR", "RCR", "TCR", "IMR", "ISR", "UTDA", "CTDA", "TPS", "TFC", "TSA0", "TSA1", "TFS", "URDA", "CRDA", "CRBA0", "CRBA1", "RBWC0", "RBWC1", "EOBC", "URRA", "RSA", "REA", "RRP", @@ -45,12 +39,6 @@ static const char* reg_names[] = { "SR", "WT0", "WT1", "RSC", "CRCT", "FAET", "MPT", "MDT", "0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37", "0x38", "0x39", "0x3a", "0x3b", "0x3c", "0x3d", "0x3e", "DCR2" }; -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif - -#define SONIC_ERROR(fmt, ...) \ -do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0) #define SONIC_CR 0x00 #define SONIC_DCR 0x01 @@ -161,15 +149,12 @@ struct dp8393xState { bool big_endian; bool last_rba_is_full; qemu_irq irq; -#ifdef DEBUG_SONIC int irq_level; -#endif QEMUTimer *watchdog; int64_t wt_last_update; NICConf conf; NICState *nic; MemoryRegion mmio; - MemoryRegion prom; /* Registers */ uint8_t cam[16][6]; @@ -185,7 +170,8 @@ struct dp8393xState { AddressSpace as; }; -/* Accessor functions for values which are formed by +/* + * Accessor functions for values which are formed by * concatenating two 16 bit device registers. By putting these * in their own functions with a uint32_t return type we avoid the * pitfall of implicit sign extension where ((x << 16) | y) is a @@ -269,16 +255,14 @@ static void dp8393x_update_irq(dp8393xState *s) { int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0; -#ifdef DEBUG_SONIC if (level != s->irq_level) { s->irq_level = level; if (level) { - DPRINTF("raise irq, isr is 0x%04x\n", s->regs[SONIC_ISR]); + trace_dp8393x_raise_irq(s->regs[SONIC_ISR]); } else { - DPRINTF("lower irq\n"); + trace_dp8393x_lower_irq(); } } -#endif qemu_set_irq(s->irq, level); } @@ -301,9 +285,9 @@ static void dp8393x_do_load_cam(dp8393xState *s) s->cam[index][3] = dp8393x_get(s, width, 2) >> 8; s->cam[index][4] = dp8393x_get(s, width, 3) & 0xff; s->cam[index][5] = dp8393x_get(s, width, 3) >> 8; - DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index, - s->cam[index][0], s->cam[index][1], s->cam[index][2], - s->cam[index][3], s->cam[index][4], s->cam[index][5]); + trace_dp8393x_load_cam(index, s->cam[index][0], s->cam[index][1], + s->cam[index][2], s->cam[index][3], + s->cam[index][4], s->cam[index][5]); /* Move to next entry */ s->regs[SONIC_CDC]--; s->regs[SONIC_CDP] += size; @@ -314,7 +298,7 @@ static void dp8393x_do_load_cam(dp8393xState *s) address_space_read(&s->as, dp8393x_cdp(s), MEMTXATTRS_UNSPECIFIED, s->data, size); s->regs[SONIC_CE] = dp8393x_get(s, width, 0); - DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]); + trace_dp8393x_load_cam_done(s->regs[SONIC_CE]); /* Done */ s->regs[SONIC_CR] &= ~SONIC_CR_LCAM; @@ -337,9 +321,8 @@ static void dp8393x_do_read_rra(dp8393xState *s) s->regs[SONIC_CRBA1] = dp8393x_get(s, width, 1); s->regs[SONIC_RBWC0] = dp8393x_get(s, width, 2); s->regs[SONIC_RBWC1] = dp8393x_get(s, width, 3); - DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n", - s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1], - s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]); + trace_dp8393x_read_rra_regs(s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1], + s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]); /* Go to next entry */ s->regs[SONIC_RRP] += size; @@ -350,8 +333,7 @@ static void dp8393x_do_read_rra(dp8393xState *s) } /* Warn the host if CRBA now has the last available resource */ - if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP]) - { + if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP]) { s->regs[SONIC_ISR] |= SONIC_ISR_RBE; dp8393x_update_irq(s); } @@ -364,7 +346,8 @@ static void dp8393x_do_software_reset(dp8393xState *s) { timer_del(s->watchdog); - s->regs[SONIC_CR] &= ~(SONIC_CR_LCAM | SONIC_CR_RRRA | SONIC_CR_TXP | SONIC_CR_HTX); + s->regs[SONIC_CR] &= ~(SONIC_CR_LCAM | SONIC_CR_RRRA | SONIC_CR_TXP | + SONIC_CR_HTX); s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS; } @@ -443,7 +426,7 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) /* Read memory */ size = sizeof(uint16_t) * 6 * width; s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA]; - DPRINTF("Transmit packet at %08x\n", dp8393x_ttda(s)); + trace_dp8393x_transmit_packet(dp8393x_ttda(s)); address_space_read(&s->as, dp8393x_ttda(s) + sizeof(uint16_t) * width, MEMTXATTRS_UNSPECIFIED, s->data, size); tx_len = 0; @@ -490,13 +473,15 @@ static void dp8393x_do_transmit_packets(dp8393xState *s) /* Handle Ethernet checksum */ if (!(s->regs[SONIC_TCR] & SONIC_TCR_CRCI)) { - /* Don't append FCS there, to look like slirp packets - * which don't have one */ + /* + * Don't append FCS there, to look like slirp packets + * which don't have one + */ } else { /* Remove existing FCS */ tx_len -= 4; if (tx_len < 0) { - SONIC_ERROR("tx_len is %d\n", tx_len); + trace_dp8393x_transmit_txlen_error(tx_len); break; } } @@ -558,26 +543,34 @@ static void dp8393x_do_command(dp8393xState *s, uint16_t command) s->regs[SONIC_CR] |= (command & SONIC_CR_MASK); - if (command & SONIC_CR_HTX) + if (command & SONIC_CR_HTX) { dp8393x_do_halt_transmission(s); - if (command & SONIC_CR_TXP) + } + if (command & SONIC_CR_TXP) { dp8393x_do_transmit_packets(s); - if (command & SONIC_CR_RXDIS) + } + if (command & SONIC_CR_RXDIS) { dp8393x_do_receiver_disable(s); - if (command & SONIC_CR_RXEN) + } + if (command & SONIC_CR_RXEN) { dp8393x_do_receiver_enable(s); - if (command & SONIC_CR_STP) + } + if (command & SONIC_CR_STP) { dp8393x_do_stop_timer(s); - if (command & SONIC_CR_ST) + } + if (command & SONIC_CR_ST) { dp8393x_do_start_timer(s); - if (command & SONIC_CR_RST) + } + if (command & SONIC_CR_RST) { dp8393x_do_software_reset(s); + } if (command & SONIC_CR_RRRA) { dp8393x_do_read_rra(s); s->regs[SONIC_CR] &= ~SONIC_CR_RRRA; } - if (command & SONIC_CR_LCAM) + if (command & SONIC_CR_LCAM) { dp8393x_do_load_cam(s); + } } static uint64_t dp8393x_read(void *opaque, hwaddr addr, unsigned int size) @@ -587,27 +580,27 @@ static uint64_t dp8393x_read(void *opaque, hwaddr addr, unsigned int size) uint16_t val = 0; switch (reg) { - /* Update data before reading it */ - case SONIC_WT0: - case SONIC_WT1: - dp8393x_update_wt_regs(s); - val = s->regs[reg]; - break; - /* Accept read to some registers only when in reset mode */ - case SONIC_CAP2: - case SONIC_CAP1: - case SONIC_CAP0: - if (s->regs[SONIC_CR] & SONIC_CR_RST) { - val = s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg) + 1] << 8; - val |= s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg)]; - } - break; - /* All other registers have no special contrainst */ - default: - val = s->regs[reg]; + /* Update data before reading it */ + case SONIC_WT0: + case SONIC_WT1: + dp8393x_update_wt_regs(s); + val = s->regs[reg]; + break; + /* Accept read to some registers only when in reset mode */ + case SONIC_CAP2: + case SONIC_CAP1: + case SONIC_CAP0: + if (s->regs[SONIC_CR] & SONIC_CR_RST) { + val = s->cam[s->regs[SONIC_CEP] & 0xf][2 * (SONIC_CAP0 - reg) + 1] << 8; + val |= s->cam[s->regs[SONIC_CEP] & 0xf][2 * (SONIC_CAP0 - reg)]; + } + break; + /* All other registers have no special contraints */ + default: + val = s->regs[reg]; } - DPRINTF("read 0x%04x from reg %s\n", val, reg_names[reg]); + trace_dp8393x_read(reg, reg_names[reg], val, size); return s->big_endian ? val << 16 : val; } @@ -619,78 +612,78 @@ static void dp8393x_write(void *opaque, hwaddr addr, uint64_t data, int reg = addr >> s->it_shift; uint32_t val = s->big_endian ? data >> 16 : data; - DPRINTF("write 0x%04x to reg %s\n", (uint16_t)val, reg_names[reg]); + trace_dp8393x_write(reg, reg_names[reg], val, size); switch (reg) { - /* Command register */ - case SONIC_CR: - dp8393x_do_command(s, val); - break; - /* Prevent write to read-only registers */ - case SONIC_CAP2: - case SONIC_CAP1: - case SONIC_CAP0: - case SONIC_SR: - case SONIC_MDT: - DPRINTF("writing to reg %d invalid\n", reg); - break; - /* Accept write to some registers only when in reset mode */ - case SONIC_DCR: - if (s->regs[SONIC_CR] & SONIC_CR_RST) { - s->regs[reg] = val & 0xbfff; - } else { - DPRINTF("writing to DCR invalid\n"); - } - break; - case SONIC_DCR2: - if (s->regs[SONIC_CR] & SONIC_CR_RST) { - s->regs[reg] = val & 0xf017; - } else { - DPRINTF("writing to DCR2 invalid\n"); - } - break; - /* 12 lower bytes are Read Only */ - case SONIC_TCR: - s->regs[reg] = val & 0xf000; - break; - /* 9 lower bytes are Read Only */ - case SONIC_RCR: - s->regs[reg] = val & 0xffe0; - break; - /* Ignore most significant bit */ - case SONIC_IMR: - s->regs[reg] = val & 0x7fff; - dp8393x_update_irq(s); - break; - /* Clear bits by writing 1 to them */ - case SONIC_ISR: - val &= s->regs[reg]; - s->regs[reg] &= ~val; - if (val & SONIC_ISR_RBE) { - dp8393x_do_read_rra(s); - } - dp8393x_update_irq(s); - break; - /* The guest is required to store aligned pointers here */ - case SONIC_RSA: - case SONIC_REA: - case SONIC_RRP: - case SONIC_RWP: - if (s->regs[SONIC_DCR] & SONIC_DCR_DW) { - s->regs[reg] = val & 0xfffc; - } else { - s->regs[reg] = val & 0xfffe; - } - break; - /* Invert written value for some registers */ - case SONIC_CRCT: - case SONIC_FAET: - case SONIC_MPT: - s->regs[reg] = val ^ 0xffff; - break; - /* All other registers have no special contrainst */ - default: - s->regs[reg] = val; + /* Command register */ + case SONIC_CR: + dp8393x_do_command(s, val); + break; + /* Prevent write to read-only registers */ + case SONIC_CAP2: + case SONIC_CAP1: + case SONIC_CAP0: + case SONIC_SR: + case SONIC_MDT: + trace_dp8393x_write_invalid(reg); + break; + /* Accept write to some registers only when in reset mode */ + case SONIC_DCR: + if (s->regs[SONIC_CR] & SONIC_CR_RST) { + s->regs[reg] = val & 0xbfff; + } else { + trace_dp8393x_write_invalid_dcr("DCR"); + } + break; + case SONIC_DCR2: + if (s->regs[SONIC_CR] & SONIC_CR_RST) { + s->regs[reg] = val & 0xf017; + } else { + trace_dp8393x_write_invalid_dcr("DCR2"); + } + break; + /* 12 lower bytes are Read Only */ + case SONIC_TCR: + s->regs[reg] = val & 0xf000; + break; + /* 9 lower bytes are Read Only */ + case SONIC_RCR: + s->regs[reg] = val & 0xffe0; + break; + /* Ignore most significant bit */ + case SONIC_IMR: + s->regs[reg] = val & 0x7fff; + dp8393x_update_irq(s); + break; + /* Clear bits by writing 1 to them */ + case SONIC_ISR: + val &= s->regs[reg]; + s->regs[reg] &= ~val; + if (val & SONIC_ISR_RBE) { + dp8393x_do_read_rra(s); + } + dp8393x_update_irq(s); + break; + /* The guest is required to store aligned pointers here */ + case SONIC_RSA: + case SONIC_REA: + case SONIC_RRP: + case SONIC_RWP: + if (s->regs[SONIC_DCR] & SONIC_DCR_DW) { + s->regs[reg] = val & 0xfffc; + } else { + s->regs[reg] = val & 0xfffe; + } + break; + /* Invert written value for some registers */ + case SONIC_CRCT: + case SONIC_FAET: + case SONIC_MPT: + s->regs[reg] = val ^ 0xffff; + break; + /* All other registers have no special contrainst */ + default: + s->regs[reg] = val; } if (reg == SONIC_WT0 || reg == SONIC_WT1) { @@ -747,17 +740,18 @@ static int dp8393x_receive_filter(dp8393xState *s, const uint8_t * buf, } /* Check broadcast */ - if ((s->regs[SONIC_RCR] & SONIC_RCR_BRD) && !memcmp(buf, bcast, sizeof(bcast))) { + if ((s->regs[SONIC_RCR] & SONIC_RCR_BRD) && + !memcmp(buf, bcast, sizeof(bcast))) { return SONIC_RCR_BC; } /* Check CAM */ for (i = 0; i < 16; i++) { if (s->regs[SONIC_CE] & (1 << i)) { - /* Entry enabled */ - if (!memcmp(buf, s->cam[i], sizeof(s->cam[i]))) { - return 0; - } + /* Entry enabled */ + if (!memcmp(buf, s->cam[i], sizeof(s->cam[i]))) { + return 0; + } } } @@ -791,7 +785,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, } if (padded_len > dp8393x_rbwc(s) * 2) { - DPRINTF("oversize packet, pkt_size is %d\n", pkt_size); + trace_dp8393x_receive_oversize(pkt_size); s->regs[SONIC_ISR] |= SONIC_ISR_RBAE; dp8393x_update_irq(s); s->regs[SONIC_RCR] |= SONIC_RCR_LPKT; @@ -800,7 +794,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, packet_type = dp8393x_receive_filter(s, buf, pkt_size); if (packet_type < 0) { - DPRINTF("packet not for netcard\n"); + trace_dp8393x_receive_not_netcard(); return -1; } @@ -838,7 +832,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, checksum = cpu_to_le32(crc32(0, buf, pkt_size)); /* Put packet into RBA */ - DPRINTF("Receive packet at %08x\n", dp8393x_crba(s)); + trace_dp8393x_receive_packet(dp8393x_crba(s)); address = dp8393x_crba(s); address_space_write(&s->as, address, MEMTXATTRS_UNSPECIFIED, buf, pkt_size); @@ -876,7 +870,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, } /* Write status to memory */ - DPRINTF("Write status at %08x\n", dp8393x_crda(s)); + trace_dp8393x_receive_write_status(dp8393x_crda(s)); dp8393x_put(s, width, 0, s->regs[SONIC_RCR]); /* status */ dp8393x_put(s, width, 1, rx_len); /* byte count */ dp8393x_put(s, width, 2, s->regs[SONIC_TRBA0]); /* pkt_ptr0 */ @@ -938,7 +932,8 @@ static void dp8393x_reset(DeviceState *dev) s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux/mips */ s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS; s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR); - s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT); + s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | + SONIC_RCR_RNT); s->regs[SONIC_TCR] |= SONIC_TCR_NCRS | SONIC_TCR_PTX; s->regs[SONIC_TCR] &= ~SONIC_TCR_BCM; s->regs[SONIC_IMR] = 0; @@ -968,16 +963,12 @@ static void dp8393x_instance_init(Object *obj) dp8393xState *s = DP8393X(obj); sysbus_init_mmio(sbd, &s->mmio); - sysbus_init_mmio(sbd, &s->prom); sysbus_init_irq(sbd, &s->irq); } static void dp8393x_realize(DeviceState *dev, Error **errp) { dp8393xState *s = DP8393X(dev); - int i, checksum; - uint8_t *prom; - Error *local_err = NULL; address_space_init(&s->as, s->dma_mr, "dp8393x"); memory_region_init_io(&s->mmio, OBJECT(dev), &dp8393x_ops, s, @@ -988,23 +979,6 @@ static void dp8393x_realize(DeviceState *dev, Error **errp) qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); s->watchdog = timer_new_ns(QEMU_CLOCK_VIRTUAL, dp8393x_watchdog, s); - - memory_region_init_rom(&s->prom, OBJECT(dev), "dp8393x-prom", - SONIC_PROM_SIZE, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - prom = memory_region_get_ram_ptr(&s->prom); - checksum = 0; - for (i = 0; i < 6; i++) { - prom[i] = s->conf.macaddr.a[i]; - checksum += prom[i]; - if (checksum > 0xff) { - checksum = (checksum + 1) & 0xff; - } - } - prom[7] = 0xff - checksum; } static const VMStateDescription vmstate_dp8393x = { diff --git a/hw/net/trace-events b/hw/net/trace-events index c28b91e..643338f 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -436,3 +436,20 @@ npcm7xx_emc_received_packet(uint32_t len) "Received %u byte packet" npcm7xx_emc_rx_done(uint32_t crxdsa) "RX done, CRXDSA=0x%x" npcm7xx_emc_reg_read(int emc_num, uint32_t result, const char *name, int regno) "emc%d: 0x%x = reg[%s/%d]" npcm7xx_emc_reg_write(int emc_num, const char *name, int regno, uint32_t value) "emc%d: reg[%s/%d] = 0x%x" + +# dp8398x.c +dp8393x_raise_irq(int isr) "raise irq, isr is 0x%04x" +dp8393x_lower_irq(void) "lower irq" +dp8393x_load_cam(int idx, int cam0, int cam1, int cam2, int cam3, int cam4, int cam5) "load cam[%d] with 0x%02x0x%02x0x%02x0x%02x0x%02x0x%02x" +dp8393x_load_cam_done(int cen) "load cam done. cam enable mask 0x%04x" +dp8393x_read_rra_regs(int crba0, int crba1, int rbwc0, int rbwc1) "CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x" +dp8393x_transmit_packet(int ttda) "Transmit packet at 0x%"PRIx32 +dp8393x_transmit_txlen_error(int len) "tx_len is %d" +dp8393x_read(int reg, const char *name, int val, int size) "reg=0x%x [%s] val=0x%04x size=%d" +dp8393x_write(int reg, const char *name, int val, int size) "reg=0x%x [%s] val=0x%04x size=%d" +dp8393x_write_invalid(int reg) "writing to reg %d invalid" +dp8393x_write_invalid_dcr(const char *name) "writing to %s invalid" +dp8393x_receive_oversize(int size) "oversize packet, pkt_size is %d" +dp8393x_receive_not_netcard(void) "packet not for netcard" +dp8393x_receive_packet(int crba) "Receive packet at 0x%"PRIx32 +dp8393x_receive_write_status(int crba) "Write status at 0x%"PRIx32 diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index afb3d1f..a57e81e 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -52,6 +52,7 @@ #include "hw/misc/unimp.h" #include "hw/registerfields.h" #include "qom/object.h" +#include "trace.h" /* #define DEBUG_BONITO */ @@ -185,7 +186,8 @@ FIELD(BONGENCFG, PCIQUEUE, 12, 1) #define BONITO_PCICONF_IDSEL_OFFSET 11 #define BONITO_PCICONF_FUN_MASK 0x700 /* [10:8] */ #define BONITO_PCICONF_FUN_OFFSET 8 -#define BONITO_PCICONF_REG_MASK 0xFC +#define BONITO_PCICONF_REG_MASK_DS (~3) /* Per datasheet */ +#define BONITO_PCICONF_REG_MASK_HW 0xff /* As seen running PMON */ #define BONITO_PCICONF_REG_OFFSET 0 @@ -464,7 +466,7 @@ static uint32_t bonito_sbridge_pciaddr(void *opaque, hwaddr addr) BONITO_PCICONF_IDSEL_OFFSET; devno = ctz32(idsel); funno = (cfgaddr & BONITO_PCICONF_FUN_MASK) >> BONITO_PCICONF_FUN_OFFSET; - regno = (cfgaddr & BONITO_PCICONF_REG_MASK) >> BONITO_PCICONF_REG_OFFSET; + regno = (cfgaddr & BONITO_PCICONF_REG_MASK_HW) >> BONITO_PCICONF_REG_OFFSET; if (idsel == 0) { error_report("error in bonito pci config address 0x" TARGET_FMT_plx @@ -495,6 +497,9 @@ static void bonito_spciconf_write(void *opaque, hwaddr addr, uint64_t val, if (pciaddr == 0xffffffff) { return; } + if (addr & ~BONITO_PCICONF_REG_MASK_DS) { + trace_bonito_spciconf_small_access(addr, size); + } /* set the pci address in s->config_reg */ phb->config_reg = (pciaddr) | (1u << 31); @@ -521,6 +526,9 @@ static uint64_t bonito_spciconf_read(void *opaque, hwaddr addr, unsigned size) if (pciaddr == 0xffffffff) { return MAKE_64BIT_MASK(0, size * 8); } + if (addr & ~BONITO_PCICONF_REG_MASK_DS) { + trace_bonito_spciconf_small_access(addr, size); + } /* set the pci address in s->config_reg */ phb->config_reg = (pciaddr) | (1u << 31); diff --git a/hw/pci-host/trace-events b/hw/pci-host/trace-events index f4b3a50..630e9fc 100644 --- a/hw/pci-host/trace-events +++ b/hw/pci-host/trace-events @@ -1,5 +1,8 @@ # See docs/devel/tracing.rst for syntax documentation. +# bonito.c +bonito_spciconf_small_access(uint64_t addr, unsigned size) "PCI config address is smaller then 32-bit, addr: 0x%"PRIx64", size: %u" + # grackle.c grackle_set_irq(int irq_num, int level) "set_irq num %d level %d" diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h index 03213ce..110c56e 100644 --- a/include/qemu/bitops.h +++ b/include/qemu/bitops.h @@ -618,4 +618,26 @@ static inline uint64_t half_unshuffle64(uint64_t x) return x; } +/** + * bitrev8: + * @x: 8-bit value to be reversed + * + * Given an input value with bits:: + * + * ABCDEFGH + * + * return the value with its bits reversed from left to right:: + * + * HGFEDCBA + * + * Returns: the bit-reversed value. + */ +static inline uint8_t bitrev8(uint8_t x) +{ + x = ((x >> 1) & 0x55) | ((x << 1) & 0xaa); + x = ((x >> 2) & 0x33) | ((x << 2) & 0xcc); + x = (x >> 4) | (x << 4) ; + return x; +} + #endif diff --git a/target/mips/tcg/micromips_translate.c.inc b/target/mips/tcg/micromips_translate.c.inc new file mode 100644 index 0000000..5e95f47 --- /dev/null +++ b/target/mips/tcg/micromips_translate.c.inc @@ -0,0 +1,3231 @@ +/* + * microMIPS translation routines + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * Copyright (c) 2006 Marius Groeger (FPU operations) + * Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support) + * Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support) + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +/* + * microMIPS32/microMIPS64 major opcodes + * + * 1. MIPS Architecture for Programmers Volume II-B: + * The microMIPS32 Instruction Set (Revision 3.05) + * + * Table 6.2 microMIPS32 Encoding of Major Opcode Field + * + * 2. MIPS Architecture For Programmers Volume II-A: + * The MIPS64 Instruction Set (Revision 3.51) + */ + +enum { + POOL32A = 0x00, + POOL16A = 0x01, + LBU16 = 0x02, + MOVE16 = 0x03, + ADDI32 = 0x04, + R6_LUI = 0x04, + AUI = 0x04, + LBU32 = 0x05, + SB32 = 0x06, + LB32 = 0x07, + + POOL32B = 0x08, + POOL16B = 0x09, + LHU16 = 0x0a, + ANDI16 = 0x0b, + ADDIU32 = 0x0c, + LHU32 = 0x0d, + SH32 = 0x0e, + LH32 = 0x0f, + + POOL32I = 0x10, + POOL16C = 0x11, + LWSP16 = 0x12, + POOL16D = 0x13, + ORI32 = 0x14, + POOL32F = 0x15, + POOL32S = 0x16, /* MIPS64 */ + DADDIU32 = 0x17, /* MIPS64 */ + + POOL32C = 0x18, + LWGP16 = 0x19, + LW16 = 0x1a, + POOL16E = 0x1b, + XORI32 = 0x1c, + JALS32 = 0x1d, + BOVC = 0x1d, + BEQC = 0x1d, + BEQZALC = 0x1d, + ADDIUPC = 0x1e, + PCREL = 0x1e, + BNVC = 0x1f, + BNEC = 0x1f, + BNEZALC = 0x1f, + + R6_BEQZC = 0x20, + JIC = 0x20, + POOL16F = 0x21, + SB16 = 0x22, + BEQZ16 = 0x23, + BEQZC16 = 0x23, + SLTI32 = 0x24, + BEQ32 = 0x25, + BC = 0x25, + SWC132 = 0x26, + LWC132 = 0x27, + + /* 0x29 is reserved */ + RES_29 = 0x29, + R6_BNEZC = 0x28, + JIALC = 0x28, + SH16 = 0x2a, + BNEZ16 = 0x2b, + BNEZC16 = 0x2b, + SLTIU32 = 0x2c, + BNE32 = 0x2d, + BALC = 0x2d, + SDC132 = 0x2e, + LDC132 = 0x2f, + + /* 0x31 is reserved */ + RES_31 = 0x31, + BLEZALC = 0x30, + BGEZALC = 0x30, + BGEUC = 0x30, + SWSP16 = 0x32, + B16 = 0x33, + BC16 = 0x33, + ANDI32 = 0x34, + J32 = 0x35, + BGTZC = 0x35, + BLTZC = 0x35, + BLTC = 0x35, + SD32 = 0x36, /* MIPS64 */ + LD32 = 0x37, /* MIPS64 */ + + /* 0x39 is reserved */ + RES_39 = 0x39, + BGTZALC = 0x38, + BLTZALC = 0x38, + BLTUC = 0x38, + SW16 = 0x3a, + LI16 = 0x3b, + JALX32 = 0x3c, + JAL32 = 0x3d, + BLEZC = 0x3d, + BGEZC = 0x3d, + BGEC = 0x3d, + SW32 = 0x3e, + LW32 = 0x3f +}; + +/* PCREL Instructions perform PC-Relative address calculation. bits 20..16 */ +enum { + ADDIUPC_00 = 0x00, + ADDIUPC_01 = 0x01, + ADDIUPC_02 = 0x02, + ADDIUPC_03 = 0x03, + ADDIUPC_04 = 0x04, + ADDIUPC_05 = 0x05, + ADDIUPC_06 = 0x06, + ADDIUPC_07 = 0x07, + AUIPC = 0x1e, + ALUIPC = 0x1f, + LWPC_08 = 0x08, + LWPC_09 = 0x09, + LWPC_0A = 0x0A, + LWPC_0B = 0x0B, + LWPC_0C = 0x0C, + LWPC_0D = 0x0D, + LWPC_0E = 0x0E, + LWPC_0F = 0x0F, +}; + +/* POOL32A encoding of minor opcode field */ + +enum { + /* + * These opcodes are distinguished only by bits 9..6; those bits are + * what are recorded below. + */ + SLL32 = 0x0, + SRL32 = 0x1, + SRA = 0x2, + ROTR = 0x3, + SELEQZ = 0x5, + SELNEZ = 0x6, + R6_RDHWR = 0x7, + + SLLV = 0x0, + SRLV = 0x1, + SRAV = 0x2, + ROTRV = 0x3, + ADD = 0x4, + ADDU32 = 0x5, + SUB = 0x6, + SUBU32 = 0x7, + MUL = 0x8, + AND = 0x9, + OR32 = 0xa, + NOR = 0xb, + XOR32 = 0xc, + SLT = 0xd, + SLTU = 0xe, + + MOVN = 0x0, + R6_MUL = 0x0, + MOVZ = 0x1, + MUH = 0x1, + MULU = 0x2, + MUHU = 0x3, + LWXS = 0x4, + R6_DIV = 0x4, + MOD = 0x5, + R6_DIVU = 0x6, + MODU = 0x7, + + /* The following can be distinguished by their lower 6 bits. */ + BREAK32 = 0x07, + INS = 0x0c, + LSA = 0x0f, + ALIGN = 0x1f, + EXT = 0x2c, + POOL32AXF = 0x3c, + SIGRIE = 0x3f +}; + +/* POOL32AXF encoding of minor opcode field extension */ + +/* + * 1. MIPS Architecture for Programmers Volume II-B: + * The microMIPS32 Instruction Set (Revision 3.05) + * + * Table 6.5 POOL32Axf Encoding of Minor Opcode Extension Field + * + * 2. MIPS Architecture for Programmers VolumeIV-e: + * The MIPS DSP Application-Specific Extension + * to the microMIPS32 Architecture (Revision 2.34) + * + * Table 5.5 POOL32Axf Encoding of Minor Opcode Extension Field + */ + +enum { + /* bits 11..6 */ + TEQ = 0x00, + TGE = 0x08, + TGEU = 0x10, + TLT = 0x20, + TLTU = 0x28, + TNE = 0x30, + + MFC0 = 0x03, + MTC0 = 0x0b, + + /* begin of microMIPS32 DSP */ + + /* bits 13..12 for 0x01 */ + MFHI_ACC = 0x0, + MFLO_ACC = 0x1, + MTHI_ACC = 0x2, + MTLO_ACC = 0x3, + + /* bits 13..12 for 0x2a */ + MADD_ACC = 0x0, + MADDU_ACC = 0x1, + MSUB_ACC = 0x2, + MSUBU_ACC = 0x3, + + /* bits 13..12 for 0x32 */ + MULT_ACC = 0x0, + MULTU_ACC = 0x1, + + /* end of microMIPS32 DSP */ + + /* bits 15..12 for 0x2c */ + BITSWAP = 0x0, + SEB = 0x2, + SEH = 0x3, + CLO = 0x4, + CLZ = 0x5, + RDHWR = 0x6, + WSBH = 0x7, + MULT = 0x8, + MULTU = 0x9, + DIV = 0xa, + DIVU = 0xb, + MADD = 0xc, + MADDU = 0xd, + MSUB = 0xe, + MSUBU = 0xf, + + /* bits 15..12 for 0x34 */ + MFC2 = 0x4, + MTC2 = 0x5, + MFHC2 = 0x8, + MTHC2 = 0x9, + CFC2 = 0xc, + CTC2 = 0xd, + + /* bits 15..12 for 0x3c */ + JALR = 0x0, + JR = 0x0, /* alias */ + JALRC = 0x0, + JRC = 0x0, + JALR_HB = 0x1, + JALRC_HB = 0x1, + JALRS = 0x4, + JALRS_HB = 0x5, + + /* bits 15..12 for 0x05 */ + RDPGPR = 0xe, + WRPGPR = 0xf, + + /* bits 15..12 for 0x0d */ + TLBP = 0x0, + TLBR = 0x1, + TLBWI = 0x2, + TLBWR = 0x3, + TLBINV = 0x4, + TLBINVF = 0x5, + WAIT = 0x9, + IRET = 0xd, + DERET = 0xe, + ERET = 0xf, + + /* bits 15..12 for 0x15 */ + DMT = 0x0, + DVPE = 0x1, + EMT = 0x2, + EVPE = 0x3, + + /* bits 15..12 for 0x1d */ + DI = 0x4, + EI = 0x5, + + /* bits 15..12 for 0x2d */ + SYNC = 0x6, + SYSCALL = 0x8, + SDBBP = 0xd, + + /* bits 15..12 for 0x35 */ + MFHI32 = 0x0, + MFLO32 = 0x1, + MTHI32 = 0x2, + MTLO32 = 0x3, +}; + +/* POOL32B encoding of minor opcode field (bits 15..12) */ + +enum { + LWC2 = 0x0, + LWP = 0x1, + LDP = 0x4, + LWM32 = 0x5, + CACHE = 0x6, + LDM = 0x7, + SWC2 = 0x8, + SWP = 0x9, + SDP = 0xc, + SWM32 = 0xd, + SDM = 0xf +}; + +/* POOL32C encoding of minor opcode field (bits 15..12) */ + +enum { + LWL = 0x0, + SWL = 0x8, + LWR = 0x1, + SWR = 0x9, + PREF = 0x2, + ST_EVA = 0xa, + LL = 0x3, + SC = 0xb, + LDL = 0x4, + SDL = 0xc, + LDR = 0x5, + SDR = 0xd, + LD_EVA = 0x6, + LWU = 0xe, + LLD = 0x7, + SCD = 0xf +}; + +/* POOL32C LD-EVA encoding of minor opcode field (bits 11..9) */ + +enum { + LBUE = 0x0, + LHUE = 0x1, + LWLE = 0x2, + LWRE = 0x3, + LBE = 0x4, + LHE = 0x5, + LLE = 0x6, + LWE = 0x7, +}; + +/* POOL32C ST-EVA encoding of minor opcode field (bits 11..9) */ + +enum { + SWLE = 0x0, + SWRE = 0x1, + PREFE = 0x2, + CACHEE = 0x3, + SBE = 0x4, + SHE = 0x5, + SCE = 0x6, + SWE = 0x7, +}; + +/* POOL32F encoding of minor opcode field (bits 5..0) */ + +enum { + /* These are the bit 7..6 values */ + ADD_FMT = 0x0, + + SUB_FMT = 0x1, + + MUL_FMT = 0x2, + + DIV_FMT = 0x3, + + /* These are the bit 8..6 values */ + MOVN_FMT = 0x0, + RSQRT2_FMT = 0x0, + MOVF_FMT = 0x0, + RINT_FMT = 0x0, + SELNEZ_FMT = 0x0, + + MOVZ_FMT = 0x1, + LWXC1 = 0x1, + MOVT_FMT = 0x1, + CLASS_FMT = 0x1, + SELEQZ_FMT = 0x1, + + PLL_PS = 0x2, + SWXC1 = 0x2, + SEL_FMT = 0x2, + + PLU_PS = 0x3, + LDXC1 = 0x3, + + MOVN_FMT_04 = 0x4, + PUL_PS = 0x4, + SDXC1 = 0x4, + RECIP2_FMT = 0x4, + + MOVZ_FMT_05 = 0x05, + PUU_PS = 0x5, + LUXC1 = 0x5, + + CVT_PS_S = 0x6, + SUXC1 = 0x6, + ADDR_PS = 0x6, + PREFX = 0x6, + MADDF_FMT = 0x6, + + MULR_PS = 0x7, + MSUBF_FMT = 0x7, + + MADD_S = 0x01, + MADD_D = 0x09, + MADD_PS = 0x11, + ALNV_PS = 0x19, + MSUB_S = 0x21, + MSUB_D = 0x29, + MSUB_PS = 0x31, + + NMADD_S = 0x02, + NMADD_D = 0x0a, + NMADD_PS = 0x12, + NMSUB_S = 0x22, + NMSUB_D = 0x2a, + NMSUB_PS = 0x32, + + MIN_FMT = 0x3, + MAX_FMT = 0xb, + MINA_FMT = 0x23, + MAXA_FMT = 0x2b, + POOL32FXF = 0x3b, + + CABS_COND_FMT = 0x1c, /* MIPS3D */ + C_COND_FMT = 0x3c, + + CMP_CONDN_S = 0x5, + CMP_CONDN_D = 0x15 +}; + +/* POOL32Fxf encoding of minor opcode extension field */ + +enum { + CVT_L = 0x04, + RSQRT_FMT = 0x08, + FLOOR_L = 0x0c, + CVT_PW_PS = 0x1c, + CVT_W = 0x24, + SQRT_FMT = 0x28, + FLOOR_W = 0x2c, + CVT_PS_PW = 0x3c, + CFC1 = 0x40, + RECIP_FMT = 0x48, + CEIL_L = 0x4c, + CTC1 = 0x60, + CEIL_W = 0x6c, + MFC1 = 0x80, + CVT_S_PL = 0x84, + TRUNC_L = 0x8c, + MTC1 = 0xa0, + CVT_S_PU = 0xa4, + TRUNC_W = 0xac, + MFHC1 = 0xc0, + ROUND_L = 0xcc, + MTHC1 = 0xe0, + ROUND_W = 0xec, + + MOV_FMT = 0x01, + MOVF = 0x05, + ABS_FMT = 0x0d, + RSQRT1_FMT = 0x1d, + MOVT = 0x25, + NEG_FMT = 0x2d, + CVT_D = 0x4d, + RECIP1_FMT = 0x5d, + CVT_S = 0x6d +}; + +/* POOL32I encoding of minor opcode field (bits 25..21) */ + +enum { + BLTZ = 0x00, + BLTZAL = 0x01, + BGEZ = 0x02, + BGEZAL = 0x03, + BLEZ = 0x04, + BNEZC = 0x05, + BGTZ = 0x06, + BEQZC = 0x07, + TLTI = 0x08, + BC1EQZC = 0x08, + TGEI = 0x09, + BC1NEZC = 0x09, + TLTIU = 0x0a, + BC2EQZC = 0x0a, + TGEIU = 0x0b, + BC2NEZC = 0x0a, + TNEI = 0x0c, + R6_SYNCI = 0x0c, + LUI = 0x0d, + TEQI = 0x0e, + SYNCI = 0x10, + BLTZALS = 0x11, + BGEZALS = 0x13, + BC2F = 0x14, + BC2T = 0x15, + /* These overlap and are distinguished by bit16 of the instruction */ + BC1F = 0x1c, + BC1T = 0x1d, + BC1ANY2F = 0x1c, + BC1ANY2T = 0x1d, + BC1ANY4F = 0x1e, + BC1ANY4T = 0x1f +}; + +/* POOL16A encoding of minor opcode field */ + +enum { + ADDU16 = 0x0, + SUBU16 = 0x1 +}; + +/* POOL16B encoding of minor opcode field */ + +enum { + SLL16 = 0x0, + SRL16 = 0x1 +}; + +/* POOL16C encoding of minor opcode field */ + +enum { + NOT16 = 0x00, + XOR16 = 0x04, + AND16 = 0x08, + OR16 = 0x0c, + LWM16 = 0x10, + SWM16 = 0x14, + JR16 = 0x18, + JRC16 = 0x1a, + JALR16 = 0x1c, + JALR16S = 0x1e, + MFHI16 = 0x20, + MFLO16 = 0x24, + BREAK16 = 0x28, + SDBBP16 = 0x2c, + JRADDIUSP = 0x30 +}; + +/* R6 POOL16C encoding of minor opcode field (bits 0..5) */ + +enum { + R6_NOT16 = 0x00, + R6_AND16 = 0x01, + R6_LWM16 = 0x02, + R6_JRC16 = 0x03, + MOVEP = 0x04, + MOVEP_05 = 0x05, + MOVEP_06 = 0x06, + MOVEP_07 = 0x07, + R6_XOR16 = 0x08, + R6_OR16 = 0x09, + R6_SWM16 = 0x0a, + JALRC16 = 0x0b, + MOVEP_0C = 0x0c, + MOVEP_0D = 0x0d, + MOVEP_0E = 0x0e, + MOVEP_0F = 0x0f, + JRCADDIUSP = 0x13, + R6_BREAK16 = 0x1b, + R6_SDBBP16 = 0x3b +}; + +/* POOL16D encoding of minor opcode field */ + +enum { + ADDIUS5 = 0x0, + ADDIUSP = 0x1 +}; + +/* POOL16E encoding of minor opcode field */ + +enum { + ADDIUR2 = 0x0, + ADDIUR1SP = 0x1 +}; + +static int mmreg(int r) +{ + static const int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 }; + + return map[r]; +} + +/* Used for 16-bit store instructions. */ +static int mmreg2(int r) +{ + static const int map[] = { 0, 17, 2, 3, 4, 5, 6, 7 }; + + return map[r]; +} + +#define uMIPS_RD(op) ((op >> 7) & 0x7) +#define uMIPS_RS(op) ((op >> 4) & 0x7) +#define uMIPS_RS2(op) uMIPS_RS(op) +#define uMIPS_RS1(op) ((op >> 1) & 0x7) +#define uMIPS_RD5(op) ((op >> 5) & 0x1f) +#define uMIPS_RS5(op) (op & 0x1f) + +/* Signed immediate */ +#define SIMM(op, start, width) \ + ((int32_t)(((op >> start) & ((~0U) >> (32 - width))) \ + << (32 - width)) \ + >> (32 - width)) +/* Zero-extended immediate */ +#define ZIMM(op, start, width) ((op >> start) & ((~0U) >> (32 - width))) + +static void gen_addiur1sp(DisasContext *ctx) +{ + int rd = mmreg(uMIPS_RD(ctx->opcode)); + + gen_arith_imm(ctx, OPC_ADDIU, rd, 29, ((ctx->opcode >> 1) & 0x3f) << 2); +} + +static void gen_addiur2(DisasContext *ctx) +{ + static const int decoded_imm[] = { 1, 4, 8, 12, 16, 20, 24, -1 }; + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rs = mmreg(uMIPS_RS(ctx->opcode)); + + gen_arith_imm(ctx, OPC_ADDIU, rd, rs, decoded_imm[ZIMM(ctx->opcode, 1, 3)]); +} + +static void gen_addiusp(DisasContext *ctx) +{ + int encoded = ZIMM(ctx->opcode, 1, 9); + int decoded; + + if (encoded <= 1) { + decoded = 256 + encoded; + } else if (encoded <= 255) { + decoded = encoded; + } else if (encoded <= 509) { + decoded = encoded - 512; + } else { + decoded = encoded - 768; + } + + gen_arith_imm(ctx, OPC_ADDIU, 29, 29, decoded << 2); +} + +static void gen_addius5(DisasContext *ctx) +{ + int imm = SIMM(ctx->opcode, 1, 4); + int rd = (ctx->opcode >> 5) & 0x1f; + + gen_arith_imm(ctx, OPC_ADDIU, rd, rd, imm); +} + +static void gen_andi16(DisasContext *ctx) +{ + static const int decoded_imm[] = { 128, 1, 2, 3, 4, 7, 8, 15, 16, + 31, 32, 63, 64, 255, 32768, 65535 }; + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rs = mmreg(uMIPS_RS(ctx->opcode)); + int encoded = ZIMM(ctx->opcode, 0, 4); + + gen_logic_imm(ctx, OPC_ANDI, rd, rs, decoded_imm[encoded]); +} + +static void gen_ldst_multiple(DisasContext *ctx, uint32_t opc, int reglist, + int base, int16_t offset) +{ + TCGv t0, t1; + TCGv_i32 t2; + + if (ctx->hflags & MIPS_HFLAG_BMASK) { + gen_reserved_instruction(ctx); + return; + } + + t0 = tcg_temp_new(); + + gen_base_offset_addr(ctx, t0, base, offset); + + t1 = tcg_const_tl(reglist); + t2 = tcg_const_i32(ctx->mem_idx); + + save_cpu_state(ctx, 1); + switch (opc) { + case LWM32: + gen_helper_lwm(cpu_env, t0, t1, t2); + break; + case SWM32: + gen_helper_swm(cpu_env, t0, t1, t2); + break; +#ifdef TARGET_MIPS64 + case LDM: + gen_helper_ldm(cpu_env, t0, t1, t2); + break; + case SDM: + gen_helper_sdm(cpu_env, t0, t1, t2); + break; +#endif + } + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free_i32(t2); +} + + +static void gen_pool16c_insn(DisasContext *ctx) +{ + int rd = mmreg((ctx->opcode >> 3) & 0x7); + int rs = mmreg(ctx->opcode & 0x7); + + switch (((ctx->opcode) >> 4) & 0x3f) { + case NOT16 + 0: + case NOT16 + 1: + case NOT16 + 2: + case NOT16 + 3: + gen_logic(ctx, OPC_NOR, rd, rs, 0); + break; + case XOR16 + 0: + case XOR16 + 1: + case XOR16 + 2: + case XOR16 + 3: + gen_logic(ctx, OPC_XOR, rd, rd, rs); + break; + case AND16 + 0: + case AND16 + 1: + case AND16 + 2: + case AND16 + 3: + gen_logic(ctx, OPC_AND, rd, rd, rs); + break; + case OR16 + 0: + case OR16 + 1: + case OR16 + 2: + case OR16 + 3: + gen_logic(ctx, OPC_OR, rd, rd, rs); + break; + case LWM16 + 0: + case LWM16 + 1: + case LWM16 + 2: + case LWM16 + 3: + { + static const int lwm_convert[] = { 0x11, 0x12, 0x13, 0x14 }; + int offset = ZIMM(ctx->opcode, 0, 4); + + gen_ldst_multiple(ctx, LWM32, lwm_convert[(ctx->opcode >> 4) & 0x3], + 29, offset << 2); + } + break; + case SWM16 + 0: + case SWM16 + 1: + case SWM16 + 2: + case SWM16 + 3: + { + static const int swm_convert[] = { 0x11, 0x12, 0x13, 0x14 }; + int offset = ZIMM(ctx->opcode, 0, 4); + + gen_ldst_multiple(ctx, SWM32, swm_convert[(ctx->opcode >> 4) & 0x3], + 29, offset << 2); + } + break; + case JR16 + 0: + case JR16 + 1: + { + int reg = ctx->opcode & 0x1f; + + gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 4); + } + break; + case JRC16 + 0: + case JRC16 + 1: + { + int reg = ctx->opcode & 0x1f; + gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 0); + /* + * Let normal delay slot handling in our caller take us + * to the branch target. + */ + } + break; + case JALR16 + 0: + case JALR16 + 1: + gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + case JALR16S + 0: + case JALR16S + 1: + gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + case MFHI16 + 0: + case MFHI16 + 1: + gen_HILO(ctx, OPC_MFHI, 0, uMIPS_RS5(ctx->opcode)); + break; + case MFLO16 + 0: + case MFLO16 + 1: + gen_HILO(ctx, OPC_MFLO, 0, uMIPS_RS5(ctx->opcode)); + break; + case BREAK16: + generate_exception_end(ctx, EXCP_BREAK); + break; + case SDBBP16: + if (is_uhi(extract32(ctx->opcode, 0, 4))) { + gen_helper_do_semihosting(cpu_env); + } else { + /* + * XXX: not clear which exception should be raised + * when in debug mode... + */ + check_insn(ctx, ISA_MIPS_R1); + generate_exception_end(ctx, EXCP_DBp); + } + break; + case JRADDIUSP + 0: + case JRADDIUSP + 1: + { + int imm = ZIMM(ctx->opcode, 0, 5); + gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0); + gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2); + /* + * Let normal delay slot handling in our caller take us + * to the branch target. + */ + } + break; + default: + gen_reserved_instruction(ctx); + break; + } +} + +static inline void gen_movep(DisasContext *ctx, int enc_dest, int enc_rt, + int enc_rs) +{ + int rd, re; + static const int rd_enc[] = { 5, 5, 6, 4, 4, 4, 4, 4 }; + static const int re_enc[] = { 6, 7, 7, 21, 22, 5, 6, 7 }; + static const int rs_rt_enc[] = { 0, 17, 2, 3, 16, 18, 19, 20 }; + + rd = rd_enc[enc_dest]; + re = re_enc[enc_dest]; + gen_load_gpr(cpu_gpr[rd], rs_rt_enc[enc_rs]); + gen_load_gpr(cpu_gpr[re], rs_rt_enc[enc_rt]); +} + +static void gen_pool16c_r6_insn(DisasContext *ctx) +{ + int rt = mmreg((ctx->opcode >> 7) & 0x7); + int rs = mmreg((ctx->opcode >> 4) & 0x7); + + switch (ctx->opcode & 0xf) { + case R6_NOT16: + gen_logic(ctx, OPC_NOR, rt, rs, 0); + break; + case R6_AND16: + gen_logic(ctx, OPC_AND, rt, rt, rs); + break; + case R6_LWM16: + { + int lwm_converted = 0x11 + extract32(ctx->opcode, 8, 2); + int offset = extract32(ctx->opcode, 4, 4); + gen_ldst_multiple(ctx, LWM32, lwm_converted, 29, offset << 2); + } + break; + case R6_JRC16: /* JRCADDIUSP */ + if ((ctx->opcode >> 4) & 1) { + /* JRCADDIUSP */ + int imm = extract32(ctx->opcode, 5, 5); + gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0); + gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2); + } else { + /* JRC16 */ + rs = extract32(ctx->opcode, 5, 5); + gen_compute_branch(ctx, OPC_JR, 2, rs, 0, 0, 0); + } + break; + case MOVEP: + case MOVEP_05: + case MOVEP_06: + case MOVEP_07: + case MOVEP_0C: + case MOVEP_0D: + case MOVEP_0E: + case MOVEP_0F: + { + int enc_dest = uMIPS_RD(ctx->opcode); + int enc_rt = uMIPS_RS2(ctx->opcode); + int enc_rs = (ctx->opcode & 3) | ((ctx->opcode >> 1) & 4); + gen_movep(ctx, enc_dest, enc_rt, enc_rs); + } + break; + case R6_XOR16: + gen_logic(ctx, OPC_XOR, rt, rt, rs); + break; + case R6_OR16: + gen_logic(ctx, OPC_OR, rt, rt, rs); + break; + case R6_SWM16: + { + int swm_converted = 0x11 + extract32(ctx->opcode, 8, 2); + int offset = extract32(ctx->opcode, 4, 4); + gen_ldst_multiple(ctx, SWM32, swm_converted, 29, offset << 2); + } + break; + case JALRC16: /* BREAK16, SDBBP16 */ + switch (ctx->opcode & 0x3f) { + case JALRC16: + case JALRC16 + 0x20: + /* JALRC16 */ + gen_compute_branch(ctx, OPC_JALR, 2, (ctx->opcode >> 5) & 0x1f, + 31, 0, 0); + break; + case R6_BREAK16: + /* BREAK16 */ + generate_exception(ctx, EXCP_BREAK); + break; + case R6_SDBBP16: + /* SDBBP16 */ + if (is_uhi(extract32(ctx->opcode, 6, 4))) { + gen_helper_do_semihosting(cpu_env); + } else { + if (ctx->hflags & MIPS_HFLAG_SBRI) { + generate_exception(ctx, EXCP_RI); + } else { + generate_exception(ctx, EXCP_DBp); + } + } + break; + } + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } +} + +static void gen_ldst_pair(DisasContext *ctx, uint32_t opc, int rd, + int base, int16_t offset) +{ + TCGv t0, t1; + + if (ctx->hflags & MIPS_HFLAG_BMASK || rd == 31) { + gen_reserved_instruction(ctx); + return; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + gen_base_offset_addr(ctx, t0, base, offset); + + switch (opc) { + case LWP: + if (rd == base) { + gen_reserved_instruction(ctx); + return; + } + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL); + gen_store_gpr(t1, rd); + tcg_gen_movi_tl(t1, 4); + gen_op_addr_add(ctx, t0, t0, t1); + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL); + gen_store_gpr(t1, rd + 1); + break; + case SWP: + gen_load_gpr(t1, rd); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); + tcg_gen_movi_tl(t1, 4); + gen_op_addr_add(ctx, t0, t0, t1); + gen_load_gpr(t1, rd + 1); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); + break; +#ifdef TARGET_MIPS64 + case LDP: + if (rd == base) { + gen_reserved_instruction(ctx); + return; + } + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ); + gen_store_gpr(t1, rd); + tcg_gen_movi_tl(t1, 8); + gen_op_addr_add(ctx, t0, t0, t1); + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ); + gen_store_gpr(t1, rd + 1); + break; + case SDP: + gen_load_gpr(t1, rd); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ); + tcg_gen_movi_tl(t1, 8); + gen_op_addr_add(ctx, t0, t0, t1); + gen_load_gpr(t1, rd + 1); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ); + break; +#endif + } + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_pool32axf(CPUMIPSState *env, DisasContext *ctx, int rt, int rs) +{ + int extension = (ctx->opcode >> 6) & 0x3f; + int minor = (ctx->opcode >> 12) & 0xf; + uint32_t mips32_op; + + switch (extension) { + case TEQ: + mips32_op = OPC_TEQ; + goto do_trap; + case TGE: + mips32_op = OPC_TGE; + goto do_trap; + case TGEU: + mips32_op = OPC_TGEU; + goto do_trap; + case TLT: + mips32_op = OPC_TLT; + goto do_trap; + case TLTU: + mips32_op = OPC_TLTU; + goto do_trap; + case TNE: + mips32_op = OPC_TNE; + do_trap: + gen_trap(ctx, mips32_op, rs, rt, -1); + break; +#ifndef CONFIG_USER_ONLY + case MFC0: + case MFC0 + 32: + check_cp0_enabled(ctx); + if (rt == 0) { + /* Treat as NOP. */ + break; + } + gen_mfc0(ctx, cpu_gpr[rt], rs, (ctx->opcode >> 11) & 0x7); + break; + case MTC0: + case MTC0 + 32: + check_cp0_enabled(ctx); + { + TCGv t0 = tcg_temp_new(); + + gen_load_gpr(t0, rt); + gen_mtc0(ctx, t0, rs, (ctx->opcode >> 11) & 0x7); + tcg_temp_free(t0); + } + break; +#endif + case 0x2a: + switch (minor & 3) { + case MADD_ACC: + gen_muldiv(ctx, OPC_MADD, (ctx->opcode >> 14) & 3, rs, rt); + break; + case MADDU_ACC: + gen_muldiv(ctx, OPC_MADDU, (ctx->opcode >> 14) & 3, rs, rt); + break; + case MSUB_ACC: + gen_muldiv(ctx, OPC_MSUB, (ctx->opcode >> 14) & 3, rs, rt); + break; + case MSUBU_ACC: + gen_muldiv(ctx, OPC_MSUBU, (ctx->opcode >> 14) & 3, rs, rt); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x32: + switch (minor & 3) { + case MULT_ACC: + gen_muldiv(ctx, OPC_MULT, (ctx->opcode >> 14) & 3, rs, rt); + break; + case MULTU_ACC: + gen_muldiv(ctx, OPC_MULTU, (ctx->opcode >> 14) & 3, rs, rt); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x2c: + switch (minor) { + case BITSWAP: + check_insn(ctx, ISA_MIPS_R6); + gen_bitswap(ctx, OPC_BITSWAP, rs, rt); + break; + case SEB: + gen_bshfl(ctx, OPC_SEB, rs, rt); + break; + case SEH: + gen_bshfl(ctx, OPC_SEH, rs, rt); + break; + case CLO: + mips32_op = OPC_CLO; + goto do_cl; + case CLZ: + mips32_op = OPC_CLZ; + do_cl: + check_insn(ctx, ISA_MIPS_R1); + gen_cl(ctx, mips32_op, rt, rs); + break; + case RDHWR: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_rdhwr(ctx, rt, rs, 0); + break; + case WSBH: + gen_bshfl(ctx, OPC_WSBH, rs, rt); + break; + case MULT: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MULT; + goto do_mul; + case MULTU: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MULTU; + goto do_mul; + case DIV: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_DIV; + goto do_div; + case DIVU: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_DIVU; + goto do_div; + do_div: + check_insn(ctx, ISA_MIPS_R1); + gen_muldiv(ctx, mips32_op, 0, rs, rt); + break; + case MADD: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MADD; + goto do_mul; + case MADDU: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MADDU; + goto do_mul; + case MSUB: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MSUB; + goto do_mul; + case MSUBU: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MSUBU; + do_mul: + check_insn(ctx, ISA_MIPS_R1); + gen_muldiv(ctx, mips32_op, 0, rs, rt); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x34: + switch (minor) { + case MFC2: + case MTC2: + case MFHC2: + case MTHC2: + case CFC2: + case CTC2: + generate_exception_err(ctx, EXCP_CpU, 2); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x3c: + switch (minor) { + case JALR: /* JALRC */ + case JALR_HB: /* JALRC_HB */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* JALRC, JALRC_HB */ + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 0); + } else { + /* JALR, JALR_HB */ + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + } + break; + case JALRS: + case JALRS_HB: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + default: + goto pool32axf_invalid; + } + break; + case 0x05: + switch (minor) { + case RDPGPR: + check_cp0_enabled(ctx); + check_insn(ctx, ISA_MIPS_R2); + gen_load_srsgpr(rs, rt); + break; + case WRPGPR: + check_cp0_enabled(ctx); + check_insn(ctx, ISA_MIPS_R2); + gen_store_srsgpr(rs, rt); + break; + default: + goto pool32axf_invalid; + } + break; +#ifndef CONFIG_USER_ONLY + case 0x0d: + switch (minor) { + case TLBP: + mips32_op = OPC_TLBP; + goto do_cp0; + case TLBR: + mips32_op = OPC_TLBR; + goto do_cp0; + case TLBWI: + mips32_op = OPC_TLBWI; + goto do_cp0; + case TLBWR: + mips32_op = OPC_TLBWR; + goto do_cp0; + case TLBINV: + mips32_op = OPC_TLBINV; + goto do_cp0; + case TLBINVF: + mips32_op = OPC_TLBINVF; + goto do_cp0; + case WAIT: + mips32_op = OPC_WAIT; + goto do_cp0; + case DERET: + mips32_op = OPC_DERET; + goto do_cp0; + case ERET: + mips32_op = OPC_ERET; + do_cp0: + gen_cp0(env, ctx, mips32_op, rt, rs); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x1d: + switch (minor) { + case DI: + check_cp0_enabled(ctx); + { + TCGv t0 = tcg_temp_new(); + + save_cpu_state(ctx, 1); + gen_helper_di(t0, cpu_env); + gen_store_gpr(t0, rs); + /* + * Stop translation as we may have switched the execution + * mode. + */ + ctx->base.is_jmp = DISAS_STOP; + tcg_temp_free(t0); + } + break; + case EI: + check_cp0_enabled(ctx); + { + TCGv t0 = tcg_temp_new(); + + save_cpu_state(ctx, 1); + gen_helper_ei(t0, cpu_env); + gen_store_gpr(t0, rs); + /* + * DISAS_STOP isn't sufficient, we need to ensure we break out + * of translated code to check for pending interrupts. + */ + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; + tcg_temp_free(t0); + } + break; + default: + goto pool32axf_invalid; + } + break; +#endif + case 0x2d: + switch (minor) { + case SYNC: + gen_sync(extract32(ctx->opcode, 16, 5)); + break; + case SYSCALL: + generate_exception_end(ctx, EXCP_SYSCALL); + break; + case SDBBP: + if (is_uhi(extract32(ctx->opcode, 16, 10))) { + gen_helper_do_semihosting(cpu_env); + } else { + check_insn(ctx, ISA_MIPS_R1); + if (ctx->hflags & MIPS_HFLAG_SBRI) { + gen_reserved_instruction(ctx); + } else { + generate_exception_end(ctx, EXCP_DBp); + } + } + break; + default: + goto pool32axf_invalid; + } + break; + case 0x01: + switch (minor & 3) { + case MFHI_ACC: + gen_HILO(ctx, OPC_MFHI, minor >> 2, rs); + break; + case MFLO_ACC: + gen_HILO(ctx, OPC_MFLO, minor >> 2, rs); + break; + case MTHI_ACC: + gen_HILO(ctx, OPC_MTHI, minor >> 2, rs); + break; + case MTLO_ACC: + gen_HILO(ctx, OPC_MTLO, minor >> 2, rs); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x35: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + switch (minor) { + case MFHI32: + gen_HILO(ctx, OPC_MFHI, 0, rs); + break; + case MFLO32: + gen_HILO(ctx, OPC_MFLO, 0, rs); + break; + case MTHI32: + gen_HILO(ctx, OPC_MTHI, 0, rs); + break; + case MTLO32: + gen_HILO(ctx, OPC_MTLO, 0, rs); + break; + default: + goto pool32axf_invalid; + } + break; + default: + pool32axf_invalid: + MIPS_INVAL("pool32axf"); + gen_reserved_instruction(ctx); + break; + } +} + +static void gen_pool32fxf(DisasContext *ctx, int rt, int rs) +{ + int extension = (ctx->opcode >> 6) & 0x3ff; + uint32_t mips32_op; + +#define FLOAT_1BIT_FMT(opc, fmt) ((fmt << 8) | opc) +#define FLOAT_2BIT_FMT(opc, fmt) ((fmt << 7) | opc) +#define COND_FLOAT_MOV(opc, cond) ((cond << 7) | opc) + + switch (extension) { + case FLOAT_1BIT_FMT(CFC1, 0): + mips32_op = OPC_CFC1; + goto do_cp1; + case FLOAT_1BIT_FMT(CTC1, 0): + mips32_op = OPC_CTC1; + goto do_cp1; + case FLOAT_1BIT_FMT(MFC1, 0): + mips32_op = OPC_MFC1; + goto do_cp1; + case FLOAT_1BIT_FMT(MTC1, 0): + mips32_op = OPC_MTC1; + goto do_cp1; + case FLOAT_1BIT_FMT(MFHC1, 0): + mips32_op = OPC_MFHC1; + goto do_cp1; + case FLOAT_1BIT_FMT(MTHC1, 0): + mips32_op = OPC_MTHC1; + do_cp1: + gen_cp1(ctx, mips32_op, rt, rs); + break; + + /* Reciprocal square root */ + case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_S): + mips32_op = OPC_RSQRT_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_D): + mips32_op = OPC_RSQRT_D; + goto do_unaryfp; + + /* Square root */ + case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_S): + mips32_op = OPC_SQRT_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_D): + mips32_op = OPC_SQRT_D; + goto do_unaryfp; + + /* Reciprocal */ + case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_S): + mips32_op = OPC_RECIP_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_D): + mips32_op = OPC_RECIP_D; + goto do_unaryfp; + + /* Floor */ + case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_S): + mips32_op = OPC_FLOOR_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_D): + mips32_op = OPC_FLOOR_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_S): + mips32_op = OPC_FLOOR_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_D): + mips32_op = OPC_FLOOR_W_D; + goto do_unaryfp; + + /* Ceiling */ + case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_S): + mips32_op = OPC_CEIL_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_D): + mips32_op = OPC_CEIL_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_S): + mips32_op = OPC_CEIL_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_D): + mips32_op = OPC_CEIL_W_D; + goto do_unaryfp; + + /* Truncation */ + case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_S): + mips32_op = OPC_TRUNC_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_D): + mips32_op = OPC_TRUNC_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_S): + mips32_op = OPC_TRUNC_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_D): + mips32_op = OPC_TRUNC_W_D; + goto do_unaryfp; + + /* Round */ + case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_S): + mips32_op = OPC_ROUND_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_D): + mips32_op = OPC_ROUND_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_S): + mips32_op = OPC_ROUND_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_D): + mips32_op = OPC_ROUND_W_D; + goto do_unaryfp; + + /* Integer to floating-point conversion */ + case FLOAT_1BIT_FMT(CVT_L, FMT_SD_S): + mips32_op = OPC_CVT_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_L, FMT_SD_D): + mips32_op = OPC_CVT_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_W, FMT_SD_S): + mips32_op = OPC_CVT_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_W, FMT_SD_D): + mips32_op = OPC_CVT_W_D; + goto do_unaryfp; + + /* Paired-foo conversions */ + case FLOAT_1BIT_FMT(CVT_S_PL, 0): + mips32_op = OPC_CVT_S_PL; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_S_PU, 0): + mips32_op = OPC_CVT_S_PU; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_PW_PS, 0): + mips32_op = OPC_CVT_PW_PS; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_PS_PW, 0): + mips32_op = OPC_CVT_PS_PW; + goto do_unaryfp; + + /* Floating-point moves */ + case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_S): + mips32_op = OPC_MOV_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_D): + mips32_op = OPC_MOV_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_PS): + mips32_op = OPC_MOV_PS; + goto do_unaryfp; + + /* Absolute value */ + case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_S): + mips32_op = OPC_ABS_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_D): + mips32_op = OPC_ABS_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_PS): + mips32_op = OPC_ABS_PS; + goto do_unaryfp; + + /* Negation */ + case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_S): + mips32_op = OPC_NEG_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_D): + mips32_op = OPC_NEG_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_PS): + mips32_op = OPC_NEG_PS; + goto do_unaryfp; + + /* Reciprocal square root step */ + case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_S): + mips32_op = OPC_RSQRT1_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_D): + mips32_op = OPC_RSQRT1_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_PS): + mips32_op = OPC_RSQRT1_PS; + goto do_unaryfp; + + /* Reciprocal step */ + case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_S): + mips32_op = OPC_RECIP1_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_D): + mips32_op = OPC_RECIP1_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_PS): + mips32_op = OPC_RECIP1_PS; + goto do_unaryfp; + + /* Conversions from double */ + case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_S): + mips32_op = OPC_CVT_D_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_W): + mips32_op = OPC_CVT_D_W; + goto do_unaryfp; + case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_L): + mips32_op = OPC_CVT_D_L; + goto do_unaryfp; + + /* Conversions from single */ + case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_D): + mips32_op = OPC_CVT_S_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_W): + mips32_op = OPC_CVT_S_W; + goto do_unaryfp; + case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_L): + mips32_op = OPC_CVT_S_L; + do_unaryfp: + gen_farith(ctx, mips32_op, -1, rs, rt, 0); + break; + + /* Conditional moves on floating-point codes */ + case COND_FLOAT_MOV(MOVT, 0): + case COND_FLOAT_MOV(MOVT, 1): + case COND_FLOAT_MOV(MOVT, 2): + case COND_FLOAT_MOV(MOVT, 3): + case COND_FLOAT_MOV(MOVT, 4): + case COND_FLOAT_MOV(MOVT, 5): + case COND_FLOAT_MOV(MOVT, 6): + case COND_FLOAT_MOV(MOVT, 7): + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 1); + break; + case COND_FLOAT_MOV(MOVF, 0): + case COND_FLOAT_MOV(MOVF, 1): + case COND_FLOAT_MOV(MOVF, 2): + case COND_FLOAT_MOV(MOVF, 3): + case COND_FLOAT_MOV(MOVF, 4): + case COND_FLOAT_MOV(MOVF, 5): + case COND_FLOAT_MOV(MOVF, 6): + case COND_FLOAT_MOV(MOVF, 7): + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 0); + break; + default: + MIPS_INVAL("pool32fxf"); + gen_reserved_instruction(ctx); + break; + } +} + +static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) +{ + int32_t offset; + uint16_t insn; + int rt, rs, rd, rr; + int16_t imm; + uint32_t op, minor, minor2, mips32_op; + uint32_t cond, fmt, cc; + + insn = translator_lduw(env, ctx->base.pc_next + 2); + ctx->opcode = (ctx->opcode << 16) | insn; + + rt = (ctx->opcode >> 21) & 0x1f; + rs = (ctx->opcode >> 16) & 0x1f; + rd = (ctx->opcode >> 11) & 0x1f; + rr = (ctx->opcode >> 6) & 0x1f; + imm = (int16_t) ctx->opcode; + + op = (ctx->opcode >> 26) & 0x3f; + switch (op) { + case POOL32A: + minor = ctx->opcode & 0x3f; + switch (minor) { + case 0x00: + minor = (ctx->opcode >> 6) & 0xf; + switch (minor) { + case SLL32: + mips32_op = OPC_SLL; + goto do_shifti; + case SRA: + mips32_op = OPC_SRA; + goto do_shifti; + case SRL32: + mips32_op = OPC_SRL; + goto do_shifti; + case ROTR: + mips32_op = OPC_ROTR; + do_shifti: + gen_shift_imm(ctx, mips32_op, rt, rs, rd); + break; + case SELEQZ: + check_insn(ctx, ISA_MIPS_R6); + gen_cond_move(ctx, OPC_SELEQZ, rd, rs, rt); + break; + case SELNEZ: + check_insn(ctx, ISA_MIPS_R6); + gen_cond_move(ctx, OPC_SELNEZ, rd, rs, rt); + break; + case R6_RDHWR: + check_insn(ctx, ISA_MIPS_R6); + gen_rdhwr(ctx, rt, rs, extract32(ctx->opcode, 11, 3)); + break; + default: + goto pool32a_invalid; + } + break; + case 0x10: + minor = (ctx->opcode >> 6) & 0xf; + switch (minor) { + /* Arithmetic */ + case ADD: + mips32_op = OPC_ADD; + goto do_arith; + case ADDU32: + mips32_op = OPC_ADDU; + goto do_arith; + case SUB: + mips32_op = OPC_SUB; + goto do_arith; + case SUBU32: + mips32_op = OPC_SUBU; + goto do_arith; + case MUL: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MUL; + do_arith: + gen_arith(ctx, mips32_op, rd, rs, rt); + break; + /* Shifts */ + case SLLV: + mips32_op = OPC_SLLV; + goto do_shift; + case SRLV: + mips32_op = OPC_SRLV; + goto do_shift; + case SRAV: + mips32_op = OPC_SRAV; + goto do_shift; + case ROTRV: + mips32_op = OPC_ROTRV; + do_shift: + gen_shift(ctx, mips32_op, rd, rs, rt); + break; + /* Logical operations */ + case AND: + mips32_op = OPC_AND; + goto do_logic; + case OR32: + mips32_op = OPC_OR; + goto do_logic; + case NOR: + mips32_op = OPC_NOR; + goto do_logic; + case XOR32: + mips32_op = OPC_XOR; + do_logic: + gen_logic(ctx, mips32_op, rd, rs, rt); + break; + /* Set less than */ + case SLT: + mips32_op = OPC_SLT; + goto do_slt; + case SLTU: + mips32_op = OPC_SLTU; + do_slt: + gen_slt(ctx, mips32_op, rd, rs, rt); + break; + default: + goto pool32a_invalid; + } + break; + case 0x18: + minor = (ctx->opcode >> 6) & 0xf; + switch (minor) { + /* Conditional moves */ + case MOVN: /* MUL */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* MUL */ + gen_r6_muldiv(ctx, R6_OPC_MUL, rd, rs, rt); + } else { + /* MOVN */ + gen_cond_move(ctx, OPC_MOVN, rd, rs, rt); + } + break; + case MOVZ: /* MUH */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* MUH */ + gen_r6_muldiv(ctx, R6_OPC_MUH, rd, rs, rt); + } else { + /* MOVZ */ + gen_cond_move(ctx, OPC_MOVZ, rd, rs, rt); + } + break; + case MULU: + check_insn(ctx, ISA_MIPS_R6); + gen_r6_muldiv(ctx, R6_OPC_MULU, rd, rs, rt); + break; + case MUHU: + check_insn(ctx, ISA_MIPS_R6); + gen_r6_muldiv(ctx, R6_OPC_MUHU, rd, rs, rt); + break; + case LWXS: /* DIV */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* DIV */ + gen_r6_muldiv(ctx, R6_OPC_DIV, rd, rs, rt); + } else { + /* LWXS */ + gen_ldxs(ctx, rs, rt, rd); + } + break; + case MOD: + check_insn(ctx, ISA_MIPS_R6); + gen_r6_muldiv(ctx, R6_OPC_MOD, rd, rs, rt); + break; + case R6_DIVU: + check_insn(ctx, ISA_MIPS_R6); + gen_r6_muldiv(ctx, R6_OPC_DIVU, rd, rs, rt); + break; + case MODU: + check_insn(ctx, ISA_MIPS_R6); + gen_r6_muldiv(ctx, R6_OPC_MODU, rd, rs, rt); + break; + default: + goto pool32a_invalid; + } + break; + case INS: + gen_bitops(ctx, OPC_INS, rt, rs, rr, rd); + return; + case LSA: + check_insn(ctx, ISA_MIPS_R6); + gen_lsa(ctx, rd, rt, rs, extract32(ctx->opcode, 9, 2)); + break; + case ALIGN: + check_insn(ctx, ISA_MIPS_R6); + gen_align(ctx, 32, rd, rs, rt, extract32(ctx->opcode, 9, 2)); + break; + case EXT: + gen_bitops(ctx, OPC_EXT, rt, rs, rr, rd); + return; + case POOL32AXF: + gen_pool32axf(env, ctx, rt, rs); + break; + case BREAK32: + generate_exception_end(ctx, EXCP_BREAK); + break; + case SIGRIE: + check_insn(ctx, ISA_MIPS_R6); + gen_reserved_instruction(ctx); + break; + default: + pool32a_invalid: + MIPS_INVAL("pool32a"); + gen_reserved_instruction(ctx); + break; + } + break; + case POOL32B: + minor = (ctx->opcode >> 12) & 0xf; + switch (minor) { + case CACHE: + check_cp0_enabled(ctx); + if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) { + gen_cache_operation(ctx, rt, rs, imm); + } + break; + case LWC2: + case SWC2: + /* COP2: Not implemented. */ + generate_exception_err(ctx, EXCP_CpU, 2); + break; +#ifdef TARGET_MIPS64 + case LDP: + case SDP: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); +#endif + /* fall through */ + case LWP: + case SWP: + gen_ldst_pair(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12)); + break; +#ifdef TARGET_MIPS64 + case LDM: + case SDM: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); +#endif + /* fall through */ + case LWM32: + case SWM32: + gen_ldst_multiple(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12)); + break; + default: + MIPS_INVAL("pool32b"); + gen_reserved_instruction(ctx); + break; + } + break; + case POOL32F: + if (ctx->CP0_Config1 & (1 << CP0C1_FP)) { + minor = ctx->opcode & 0x3f; + check_cp1_enabled(ctx); + switch (minor) { + case ALNV_PS: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_ALNV_PS; + goto do_madd; + case MADD_S: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MADD_S; + goto do_madd; + case MADD_D: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MADD_D; + goto do_madd; + case MADD_PS: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MADD_PS; + goto do_madd; + case MSUB_S: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MSUB_S; + goto do_madd; + case MSUB_D: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MSUB_D; + goto do_madd; + case MSUB_PS: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MSUB_PS; + goto do_madd; + case NMADD_S: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_NMADD_S; + goto do_madd; + case NMADD_D: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_NMADD_D; + goto do_madd; + case NMADD_PS: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_NMADD_PS; + goto do_madd; + case NMSUB_S: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_NMSUB_S; + goto do_madd; + case NMSUB_D: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_NMSUB_D; + goto do_madd; + case NMSUB_PS: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_NMSUB_PS; + do_madd: + gen_flt3_arith(ctx, mips32_op, rd, rr, rs, rt); + break; + case CABS_COND_FMT: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + cond = (ctx->opcode >> 6) & 0xf; + cc = (ctx->opcode >> 13) & 0x7; + fmt = (ctx->opcode >> 10) & 0x3; + switch (fmt) { + case 0x0: + gen_cmpabs_s(ctx, cond, rt, rs, cc); + break; + case 0x1: + gen_cmpabs_d(ctx, cond, rt, rs, cc); + break; + case 0x2: + gen_cmpabs_ps(ctx, cond, rt, rs, cc); + break; + default: + goto pool32f_invalid; + } + break; + case C_COND_FMT: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + cond = (ctx->opcode >> 6) & 0xf; + cc = (ctx->opcode >> 13) & 0x7; + fmt = (ctx->opcode >> 10) & 0x3; + switch (fmt) { + case 0x0: + gen_cmp_s(ctx, cond, rt, rs, cc); + break; + case 0x1: + gen_cmp_d(ctx, cond, rt, rs, cc); + break; + case 0x2: + gen_cmp_ps(ctx, cond, rt, rs, cc); + break; + default: + goto pool32f_invalid; + } + break; + case CMP_CONDN_S: + check_insn(ctx, ISA_MIPS_R6); + gen_r6_cmp_s(ctx, (ctx->opcode >> 6) & 0x1f, rt, rs, rd); + break; + case CMP_CONDN_D: + check_insn(ctx, ISA_MIPS_R6); + gen_r6_cmp_d(ctx, (ctx->opcode >> 6) & 0x1f, rt, rs, rd); + break; + case POOL32FXF: + gen_pool32fxf(ctx, rt, rs); + break; + case 0x00: + /* PLL foo */ + switch ((ctx->opcode >> 6) & 0x7) { + case PLL_PS: + mips32_op = OPC_PLL_PS; + goto do_ps; + case PLU_PS: + mips32_op = OPC_PLU_PS; + goto do_ps; + case PUL_PS: + mips32_op = OPC_PUL_PS; + goto do_ps; + case PUU_PS: + mips32_op = OPC_PUU_PS; + goto do_ps; + case CVT_PS_S: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_CVT_PS_S; + do_ps: + gen_farith(ctx, mips32_op, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case MIN_FMT: + check_insn(ctx, ISA_MIPS_R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MIN_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MIN_D, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case 0x08: + /* [LS][WDU]XC1 */ + switch ((ctx->opcode >> 6) & 0x7) { + case LWXC1: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LWXC1; + goto do_ldst_cp1; + case SWXC1: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SWXC1; + goto do_ldst_cp1; + case LDXC1: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LDXC1; + goto do_ldst_cp1; + case SDXC1: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SDXC1; + goto do_ldst_cp1; + case LUXC1: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LUXC1; + goto do_ldst_cp1; + case SUXC1: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SUXC1; + do_ldst_cp1: + gen_flt3_ldst(ctx, mips32_op, rd, rd, rt, rs); + break; + default: + goto pool32f_invalid; + } + break; + case MAX_FMT: + check_insn(ctx, ISA_MIPS_R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MAX_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MAX_D, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case 0x18: + /* 3D insns */ + check_insn_opc_removed(ctx, ISA_MIPS_R6); + fmt = (ctx->opcode >> 9) & 0x3; + switch ((ctx->opcode >> 6) & 0x7) { + case RSQRT2_FMT: + switch (fmt) { + case FMT_SDPS_S: + mips32_op = OPC_RSQRT2_S; + goto do_3d; + case FMT_SDPS_D: + mips32_op = OPC_RSQRT2_D; + goto do_3d; + case FMT_SDPS_PS: + mips32_op = OPC_RSQRT2_PS; + goto do_3d; + default: + goto pool32f_invalid; + } + break; + case RECIP2_FMT: + switch (fmt) { + case FMT_SDPS_S: + mips32_op = OPC_RECIP2_S; + goto do_3d; + case FMT_SDPS_D: + mips32_op = OPC_RECIP2_D; + goto do_3d; + case FMT_SDPS_PS: + mips32_op = OPC_RECIP2_PS; + goto do_3d; + default: + goto pool32f_invalid; + } + break; + case ADDR_PS: + mips32_op = OPC_ADDR_PS; + goto do_3d; + case MULR_PS: + mips32_op = OPC_MULR_PS; + do_3d: + gen_farith(ctx, mips32_op, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case 0x20: + /* MOV[FT].fmt, PREFX, RINT.fmt, CLASS.fmt*/ + cc = (ctx->opcode >> 13) & 0x7; + fmt = (ctx->opcode >> 9) & 0x3; + switch ((ctx->opcode >> 6) & 0x7) { + case MOVF_FMT: /* RINT_FMT */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* RINT_FMT */ + switch (fmt) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_RINT_S, 0, rt, rs, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_RINT_D, 0, rt, rs, 0); + break; + default: + goto pool32f_invalid; + } + } else { + /* MOVF_FMT */ + switch (fmt) { + case FMT_SDPS_S: + gen_movcf_s(ctx, rs, rt, cc, 0); + break; + case FMT_SDPS_D: + gen_movcf_d(ctx, rs, rt, cc, 0); + break; + case FMT_SDPS_PS: + check_ps(ctx); + gen_movcf_ps(ctx, rs, rt, cc, 0); + break; + default: + goto pool32f_invalid; + } + } + break; + case MOVT_FMT: /* CLASS_FMT */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* CLASS_FMT */ + switch (fmt) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_CLASS_S, 0, rt, rs, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_CLASS_D, 0, rt, rs, 0); + break; + default: + goto pool32f_invalid; + } + } else { + /* MOVT_FMT */ + switch (fmt) { + case FMT_SDPS_S: + gen_movcf_s(ctx, rs, rt, cc, 1); + break; + case FMT_SDPS_D: + gen_movcf_d(ctx, rs, rt, cc, 1); + break; + case FMT_SDPS_PS: + check_ps(ctx); + gen_movcf_ps(ctx, rs, rt, cc, 1); + break; + default: + goto pool32f_invalid; + } + } + break; + case PREFX: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + break; + default: + goto pool32f_invalid; + } + break; +#define FINSN_3ARG_SDPS(prfx) \ + switch ((ctx->opcode >> 8) & 0x3) { \ + case FMT_SDPS_S: \ + mips32_op = OPC_##prfx##_S; \ + goto do_fpop; \ + case FMT_SDPS_D: \ + mips32_op = OPC_##prfx##_D; \ + goto do_fpop; \ + case FMT_SDPS_PS: \ + check_ps(ctx); \ + mips32_op = OPC_##prfx##_PS; \ + goto do_fpop; \ + default: \ + goto pool32f_invalid; \ + } + case MINA_FMT: + check_insn(ctx, ISA_MIPS_R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MINA_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MINA_D, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case MAXA_FMT: + check_insn(ctx, ISA_MIPS_R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MAXA_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MAXA_D, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case 0x30: + /* regular FP ops */ + switch ((ctx->opcode >> 6) & 0x3) { + case ADD_FMT: + FINSN_3ARG_SDPS(ADD); + break; + case SUB_FMT: + FINSN_3ARG_SDPS(SUB); + break; + case MUL_FMT: + FINSN_3ARG_SDPS(MUL); + break; + case DIV_FMT: + fmt = (ctx->opcode >> 8) & 0x3; + if (fmt == 1) { + mips32_op = OPC_DIV_D; + } else if (fmt == 0) { + mips32_op = OPC_DIV_S; + } else { + goto pool32f_invalid; + } + goto do_fpop; + default: + goto pool32f_invalid; + } + break; + case 0x38: + /* cmovs */ + switch ((ctx->opcode >> 6) & 0x7) { + case MOVN_FMT: /* SELEQZ_FMT */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* SELEQZ_FMT */ + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_sel_s(ctx, OPC_SELEQZ_S, rd, rt, rs); + break; + case FMT_SDPS_D: + gen_sel_d(ctx, OPC_SELEQZ_D, rd, rt, rs); + break; + default: + goto pool32f_invalid; + } + } else { + /* MOVN_FMT */ + FINSN_3ARG_SDPS(MOVN); + } + break; + case MOVN_FMT_04: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + FINSN_3ARG_SDPS(MOVN); + break; + case MOVZ_FMT: /* SELNEZ_FMT */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* SELNEZ_FMT */ + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_sel_s(ctx, OPC_SELNEZ_S, rd, rt, rs); + break; + case FMT_SDPS_D: + gen_sel_d(ctx, OPC_SELNEZ_D, rd, rt, rs); + break; + default: + goto pool32f_invalid; + } + } else { + /* MOVZ_FMT */ + FINSN_3ARG_SDPS(MOVZ); + } + break; + case MOVZ_FMT_05: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + FINSN_3ARG_SDPS(MOVZ); + break; + case SEL_FMT: + check_insn(ctx, ISA_MIPS_R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_sel_s(ctx, OPC_SEL_S, rd, rt, rs); + break; + case FMT_SDPS_D: + gen_sel_d(ctx, OPC_SEL_D, rd, rt, rs); + break; + default: + goto pool32f_invalid; + } + break; + case MADDF_FMT: + check_insn(ctx, ISA_MIPS_R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + mips32_op = OPC_MADDF_S; + goto do_fpop; + case FMT_SDPS_D: + mips32_op = OPC_MADDF_D; + goto do_fpop; + default: + goto pool32f_invalid; + } + break; + case MSUBF_FMT: + check_insn(ctx, ISA_MIPS_R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + mips32_op = OPC_MSUBF_S; + goto do_fpop; + case FMT_SDPS_D: + mips32_op = OPC_MSUBF_D; + goto do_fpop; + default: + goto pool32f_invalid; + } + break; + default: + goto pool32f_invalid; + } + break; + do_fpop: + gen_farith(ctx, mips32_op, rt, rs, rd, 0); + break; + default: + pool32f_invalid: + MIPS_INVAL("pool32f"); + gen_reserved_instruction(ctx); + break; + } + } else { + generate_exception_err(ctx, EXCP_CpU, 1); + } + break; + case POOL32I: + minor = (ctx->opcode >> 21) & 0x1f; + switch (minor) { + case BLTZ: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BLTZ, 4, rs, -1, imm << 1, 4); + break; + case BLTZAL: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + case BLTZALS: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + case BGEZ: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BGEZ, 4, rs, -1, imm << 1, 4); + break; + case BGEZAL: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + case BGEZALS: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + case BLEZ: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BLEZ, 4, rs, -1, imm << 1, 4); + break; + case BGTZ: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BGTZ, 4, rs, -1, imm << 1, 4); + break; + + /* Traps */ + case TLTI: /* BC1EQZC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* BC1EQZC */ + check_cp1_enabled(ctx); + gen_compute_branch1_r6(ctx, OPC_BC1EQZ, rs, imm << 1, 0); + } else { + /* TLTI */ + mips32_op = OPC_TLTI; + goto do_trapi; + } + break; + case TGEI: /* BC1NEZC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* BC1NEZC */ + check_cp1_enabled(ctx); + gen_compute_branch1_r6(ctx, OPC_BC1NEZ, rs, imm << 1, 0); + } else { + /* TGEI */ + mips32_op = OPC_TGEI; + goto do_trapi; + } + break; + case TLTIU: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_TLTIU; + goto do_trapi; + case TGEIU: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_TGEIU; + goto do_trapi; + case TNEI: /* SYNCI */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* SYNCI */ + /* + * Break the TB to be able to sync copied instructions + * immediately. + */ + ctx->base.is_jmp = DISAS_STOP; + } else { + /* TNEI */ + mips32_op = OPC_TNEI; + goto do_trapi; + } + break; + case TEQI: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_TEQI; + do_trapi: + gen_trap(ctx, mips32_op, rs, -1, imm); + break; + + case BNEZC: + case BEQZC: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ, + 4, rs, 0, imm << 1, 0); + /* + * Compact branches don't have a delay slot, so just let + * the normal delay slot handling take us to the branch + * target. + */ + break; + case LUI: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_logic_imm(ctx, OPC_LUI, rs, 0, imm); + break; + case SYNCI: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + /* + * Break the TB to be able to sync copied instructions + * immediately. + */ + ctx->base.is_jmp = DISAS_STOP; + break; + case BC2F: + case BC2T: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + /* COP2: Not implemented. */ + generate_exception_err(ctx, EXCP_CpU, 2); + break; + case BC1F: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1FANY2 : OPC_BC1F; + goto do_cp1branch; + case BC1T: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1TANY2 : OPC_BC1T; + goto do_cp1branch; + case BC1ANY4F: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_BC1FANY4; + goto do_cp1mips3d; + case BC1ANY4T: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_BC1TANY4; + do_cp1mips3d: + check_cop1x(ctx); + check_insn(ctx, ASE_MIPS3D); + /* Fall through */ + do_cp1branch: + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + check_cp1_enabled(ctx); + gen_compute_branch1(ctx, mips32_op, + (ctx->opcode >> 18) & 0x7, imm << 1); + } else { + generate_exception_err(ctx, EXCP_CpU, 1); + } + break; + default: + MIPS_INVAL("pool32i"); + gen_reserved_instruction(ctx); + break; + } + break; + case POOL32C: + minor = (ctx->opcode >> 12) & 0xf; + offset = sextract32(ctx->opcode, 0, + (ctx->insn_flags & ISA_MIPS_R6) ? 9 : 12); + switch (minor) { + case LWL: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LWL; + goto do_ld_lr; + case SWL: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SWL; + goto do_st_lr; + case LWR: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LWR; + goto do_ld_lr; + case SWR: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SWR; + goto do_st_lr; +#if defined(TARGET_MIPS64) + case LDL: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LDL; + goto do_ld_lr; + case SDL: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SDL; + goto do_st_lr; + case LDR: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LDR; + goto do_ld_lr; + case SDR: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SDR; + goto do_st_lr; + case LWU: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + mips32_op = OPC_LWU; + goto do_ld_lr; + case LLD: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + mips32_op = OPC_LLD; + goto do_ld_lr; +#endif + case LL: + mips32_op = OPC_LL; + goto do_ld_lr; + do_ld_lr: + gen_ld(ctx, mips32_op, rt, rs, offset); + break; + do_st_lr: + gen_st(ctx, mips32_op, rt, rs, offset); + break; + case SC: + gen_st_cond(ctx, rt, rs, offset, MO_TESL, false); + break; +#if defined(TARGET_MIPS64) + case SCD: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_st_cond(ctx, rt, rs, offset, MO_TEQ, false); + break; +#endif + case LD_EVA: + if (!ctx->eva) { + MIPS_INVAL("pool32c ld-eva"); + gen_reserved_instruction(ctx); + break; + } + check_cp0_enabled(ctx); + + minor2 = (ctx->opcode >> 9) & 0x7; + offset = sextract32(ctx->opcode, 0, 9); + switch (minor2) { + case LBUE: + mips32_op = OPC_LBUE; + goto do_ld_lr; + case LHUE: + mips32_op = OPC_LHUE; + goto do_ld_lr; + case LWLE: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LWLE; + goto do_ld_lr; + case LWRE: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LWRE; + goto do_ld_lr; + case LBE: + mips32_op = OPC_LBE; + goto do_ld_lr; + case LHE: + mips32_op = OPC_LHE; + goto do_ld_lr; + case LLE: + mips32_op = OPC_LLE; + goto do_ld_lr; + case LWE: + mips32_op = OPC_LWE; + goto do_ld_lr; + }; + break; + case ST_EVA: + if (!ctx->eva) { + MIPS_INVAL("pool32c st-eva"); + gen_reserved_instruction(ctx); + break; + } + check_cp0_enabled(ctx); + + minor2 = (ctx->opcode >> 9) & 0x7; + offset = sextract32(ctx->opcode, 0, 9); + switch (minor2) { + case SWLE: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SWLE; + goto do_st_lr; + case SWRE: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SWRE; + goto do_st_lr; + case PREFE: + /* Treat as no-op */ + if ((ctx->insn_flags & ISA_MIPS_R6) && (rt >= 24)) { + /* hint codes 24-31 are reserved and signal RI */ + generate_exception(ctx, EXCP_RI); + } + break; + case CACHEE: + /* Treat as no-op */ + if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) { + gen_cache_operation(ctx, rt, rs, offset); + } + break; + case SBE: + mips32_op = OPC_SBE; + goto do_st_lr; + case SHE: + mips32_op = OPC_SHE; + goto do_st_lr; + case SCE: + gen_st_cond(ctx, rt, rs, offset, MO_TESL, true); + break; + case SWE: + mips32_op = OPC_SWE; + goto do_st_lr; + }; + break; + case PREF: + /* Treat as no-op */ + if ((ctx->insn_flags & ISA_MIPS_R6) && (rt >= 24)) { + /* hint codes 24-31 are reserved and signal RI */ + generate_exception(ctx, EXCP_RI); + } + break; + default: + MIPS_INVAL("pool32c"); + gen_reserved_instruction(ctx); + break; + } + break; + case ADDI32: /* AUI, LUI */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* AUI, LUI */ + gen_logic_imm(ctx, OPC_LUI, rt, rs, imm); + } else { + /* ADDI32 */ + mips32_op = OPC_ADDI; + goto do_addi; + } + break; + case ADDIU32: + mips32_op = OPC_ADDIU; + do_addi: + gen_arith_imm(ctx, mips32_op, rt, rs, imm); + break; + + /* Logical operations */ + case ORI32: + mips32_op = OPC_ORI; + goto do_logici; + case XORI32: + mips32_op = OPC_XORI; + goto do_logici; + case ANDI32: + mips32_op = OPC_ANDI; + do_logici: + gen_logic_imm(ctx, mips32_op, rt, rs, imm); + break; + + /* Set less than immediate */ + case SLTI32: + mips32_op = OPC_SLTI; + goto do_slti; + case SLTIU32: + mips32_op = OPC_SLTIU; + do_slti: + gen_slt_imm(ctx, mips32_op, rt, rs, imm); + break; + case JALX32: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; + gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + case JALS32: /* BOVC, BEQC, BEQZALC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + if (rs >= rt) { + /* BOVC */ + mips32_op = OPC_BOVC; + } else if (rs < rt && rs == 0) { + /* BEQZALC */ + mips32_op = OPC_BEQZALC; + } else { + /* BEQC */ + mips32_op = OPC_BEQC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + } else { + /* JALS32 */ + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1; + gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, offset, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + } + break; + case BEQ32: /* BC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* BC */ + gen_compute_compact_branch(ctx, OPC_BC, 0, 0, + sextract32(ctx->opcode << 1, 0, 27)); + } else { + /* BEQ32 */ + gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1, 4); + } + break; + case BNE32: /* BALC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* BALC */ + gen_compute_compact_branch(ctx, OPC_BALC, 0, 0, + sextract32(ctx->opcode << 1, 0, 27)); + } else { + /* BNE32 */ + gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1, 4); + } + break; + case J32: /* BGTZC, BLTZC, BLTC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + if (rs == 0 && rt != 0) { + /* BGTZC */ + mips32_op = OPC_BGTZC; + } else if (rs != 0 && rt != 0 && rs == rt) { + /* BLTZC */ + mips32_op = OPC_BLTZC; + } else { + /* BLTC */ + mips32_op = OPC_BLTC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + } else { + /* J32 */ + gen_compute_branch(ctx, OPC_J, 4, rt, rs, + (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); + } + break; + case JAL32: /* BLEZC, BGEZC, BGEC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + if (rs == 0 && rt != 0) { + /* BLEZC */ + mips32_op = OPC_BLEZC; + } else if (rs != 0 && rt != 0 && rs == rt) { + /* BGEZC */ + mips32_op = OPC_BGEZC; + } else { + /* BGEC */ + mips32_op = OPC_BGEC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + } else { + /* JAL32 */ + gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, + (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + } + break; + /* Floating point (COP1) */ + case LWC132: + mips32_op = OPC_LWC1; + goto do_cop1; + case LDC132: + mips32_op = OPC_LDC1; + goto do_cop1; + case SWC132: + mips32_op = OPC_SWC1; + goto do_cop1; + case SDC132: + mips32_op = OPC_SDC1; + do_cop1: + gen_cop1_ldst(ctx, mips32_op, rt, rs, imm); + break; + case ADDIUPC: /* PCREL: ADDIUPC, AUIPC, ALUIPC, LWPC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* PCREL: ADDIUPC, AUIPC, ALUIPC, LWPC */ + switch ((ctx->opcode >> 16) & 0x1f) { + case ADDIUPC_00: + case ADDIUPC_01: + case ADDIUPC_02: + case ADDIUPC_03: + case ADDIUPC_04: + case ADDIUPC_05: + case ADDIUPC_06: + case ADDIUPC_07: + gen_pcrel(ctx, OPC_ADDIUPC, ctx->base.pc_next & ~0x3, rt); + break; + case AUIPC: + gen_pcrel(ctx, OPC_AUIPC, ctx->base.pc_next, rt); + break; + case ALUIPC: + gen_pcrel(ctx, OPC_ALUIPC, ctx->base.pc_next, rt); + break; + case LWPC_08: + case LWPC_09: + case LWPC_0A: + case LWPC_0B: + case LWPC_0C: + case LWPC_0D: + case LWPC_0E: + case LWPC_0F: + gen_pcrel(ctx, R6_OPC_LWPC, ctx->base.pc_next & ~0x3, rt); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } + } else { + /* ADDIUPC */ + int reg = mmreg(ZIMM(ctx->opcode, 23, 3)); + offset = SIMM(ctx->opcode, 0, 23) << 2; + + gen_addiupc(ctx, reg, offset, 0, 0); + } + break; + case BNVC: /* BNEC, BNEZALC */ + check_insn(ctx, ISA_MIPS_R6); + if (rs >= rt) { + /* BNVC */ + mips32_op = OPC_BNVC; + } else if (rs < rt && rs == 0) { + /* BNEZALC */ + mips32_op = OPC_BNEZALC; + } else { + /* BNEC */ + mips32_op = OPC_BNEC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + break; + case R6_BNEZC: /* JIALC */ + check_insn(ctx, ISA_MIPS_R6); + if (rt != 0) { + /* BNEZC */ + gen_compute_compact_branch(ctx, OPC_BNEZC, rt, 0, + sextract32(ctx->opcode << 1, 0, 22)); + } else { + /* JIALC */ + gen_compute_compact_branch(ctx, OPC_JIALC, 0, rs, imm); + } + break; + case R6_BEQZC: /* JIC */ + check_insn(ctx, ISA_MIPS_R6); + if (rt != 0) { + /* BEQZC */ + gen_compute_compact_branch(ctx, OPC_BEQZC, rt, 0, + sextract32(ctx->opcode << 1, 0, 22)); + } else { + /* JIC */ + gen_compute_compact_branch(ctx, OPC_JIC, 0, rs, imm); + } + break; + case BLEZALC: /* BGEZALC, BGEUC */ + check_insn(ctx, ISA_MIPS_R6); + if (rs == 0 && rt != 0) { + /* BLEZALC */ + mips32_op = OPC_BLEZALC; + } else if (rs != 0 && rt != 0 && rs == rt) { + /* BGEZALC */ + mips32_op = OPC_BGEZALC; + } else { + /* BGEUC */ + mips32_op = OPC_BGEUC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + break; + case BGTZALC: /* BLTZALC, BLTUC */ + check_insn(ctx, ISA_MIPS_R6); + if (rs == 0 && rt != 0) { + /* BGTZALC */ + mips32_op = OPC_BGTZALC; + } else if (rs != 0 && rt != 0 && rs == rt) { + /* BLTZALC */ + mips32_op = OPC_BLTZALC; + } else { + /* BLTUC */ + mips32_op = OPC_BLTUC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + break; + /* Loads and stores */ + case LB32: + mips32_op = OPC_LB; + goto do_ld; + case LBU32: + mips32_op = OPC_LBU; + goto do_ld; + case LH32: + mips32_op = OPC_LH; + goto do_ld; + case LHU32: + mips32_op = OPC_LHU; + goto do_ld; + case LW32: + mips32_op = OPC_LW; + goto do_ld; +#ifdef TARGET_MIPS64 + case LD32: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + mips32_op = OPC_LD; + goto do_ld; + case SD32: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + mips32_op = OPC_SD; + goto do_st; +#endif + case SB32: + mips32_op = OPC_SB; + goto do_st; + case SH32: + mips32_op = OPC_SH; + goto do_st; + case SW32: + mips32_op = OPC_SW; + goto do_st; + do_ld: + gen_ld(ctx, mips32_op, rt, rs, imm); + break; + do_st: + gen_st(ctx, mips32_op, rt, rs, imm); + break; + default: + gen_reserved_instruction(ctx); + break; + } +} + +static int decode_isa_micromips(CPUMIPSState *env, DisasContext *ctx) +{ + uint32_t op; + + /* make sure instructions are on a halfword boundary */ + if (ctx->base.pc_next & 0x1) { + env->CP0_BadVAddr = ctx->base.pc_next; + generate_exception_end(ctx, EXCP_AdEL); + return 2; + } + + op = (ctx->opcode >> 10) & 0x3f; + /* Enforce properly-sized instructions in a delay slot */ + if (ctx->hflags & MIPS_HFLAG_BDS_STRICT) { + switch (op & 0x7) { /* MSB-3..MSB-5 */ + case 0: + /* POOL32A, POOL32B, POOL32I, POOL32C */ + case 4: + /* ADDI32, ADDIU32, ORI32, XORI32, SLTI32, SLTIU32, ANDI32, JALX32 */ + case 5: + /* LBU32, LHU32, POOL32F, JALS32, BEQ32, BNE32, J32, JAL32 */ + case 6: + /* SB32, SH32, ADDIUPC, SWC132, SDC132, SW32 */ + case 7: + /* LB32, LH32, LWC132, LDC132, LW32 */ + if (ctx->hflags & MIPS_HFLAG_BDS16) { + gen_reserved_instruction(ctx); + return 2; + } + break; + case 1: + /* POOL16A, POOL16B, POOL16C, LWGP16, POOL16F */ + case 2: + /* LBU16, LHU16, LWSP16, LW16, SB16, SH16, SWSP16, SW16 */ + case 3: + /* MOVE16, ANDI16, POOL16D, POOL16E, BEQZ16, BNEZ16, B16, LI16 */ + if (ctx->hflags & MIPS_HFLAG_BDS32) { + gen_reserved_instruction(ctx); + return 2; + } + break; + } + } + + switch (op) { + case POOL16A: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rs1 = mmreg(uMIPS_RS1(ctx->opcode)); + int rs2 = mmreg(uMIPS_RS2(ctx->opcode)); + uint32_t opc = 0; + + switch (ctx->opcode & 0x1) { + case ADDU16: + opc = OPC_ADDU; + break; + case SUBU16: + opc = OPC_SUBU; + break; + } + if (ctx->insn_flags & ISA_MIPS_R6) { + /* + * In the Release 6, the register number location in + * the instruction encoding has changed. + */ + gen_arith(ctx, opc, rs1, rd, rs2); + } else { + gen_arith(ctx, opc, rd, rs1, rs2); + } + } + break; + case POOL16B: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rs = mmreg(uMIPS_RS(ctx->opcode)); + int amount = (ctx->opcode >> 1) & 0x7; + uint32_t opc = 0; + amount = amount == 0 ? 8 : amount; + + switch (ctx->opcode & 0x1) { + case SLL16: + opc = OPC_SLL; + break; + case SRL16: + opc = OPC_SRL; + break; + } + + gen_shift_imm(ctx, opc, rd, rs, amount); + } + break; + case POOL16C: + if (ctx->insn_flags & ISA_MIPS_R6) { + gen_pool16c_r6_insn(ctx); + } else { + gen_pool16c_insn(ctx); + } + break; + case LWGP16: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rb = 28; /* GP */ + int16_t offset = SIMM(ctx->opcode, 0, 7) << 2; + + gen_ld(ctx, OPC_LW, rd, rb, offset); + } + break; + case POOL16F: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + if (ctx->opcode & 1) { + gen_reserved_instruction(ctx); + } else { + /* MOVEP */ + int enc_dest = uMIPS_RD(ctx->opcode); + int enc_rt = uMIPS_RS2(ctx->opcode); + int enc_rs = uMIPS_RS1(ctx->opcode); + gen_movep(ctx, enc_dest, enc_rt, enc_rs); + } + break; + case LBU16: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4); + offset = (offset == 0xf ? -1 : offset); + + gen_ld(ctx, OPC_LBU, rd, rb, offset); + } + break; + case LHU16: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1; + + gen_ld(ctx, OPC_LHU, rd, rb, offset); + } + break; + case LWSP16: + { + int rd = (ctx->opcode >> 5) & 0x1f; + int rb = 29; /* SP */ + int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2; + + gen_ld(ctx, OPC_LW, rd, rb, offset); + } + break; + case LW16: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2; + + gen_ld(ctx, OPC_LW, rd, rb, offset); + } + break; + case SB16: + { + int rd = mmreg2(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4); + + gen_st(ctx, OPC_SB, rd, rb, offset); + } + break; + case SH16: + { + int rd = mmreg2(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1; + + gen_st(ctx, OPC_SH, rd, rb, offset); + } + break; + case SWSP16: + { + int rd = (ctx->opcode >> 5) & 0x1f; + int rb = 29; /* SP */ + int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2; + + gen_st(ctx, OPC_SW, rd, rb, offset); + } + break; + case SW16: + { + int rd = mmreg2(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2; + + gen_st(ctx, OPC_SW, rd, rb, offset); + } + break; + case MOVE16: + { + int rd = uMIPS_RD5(ctx->opcode); + int rs = uMIPS_RS5(ctx->opcode); + + gen_arith(ctx, OPC_ADDU, rd, rs, 0); + } + break; + case ANDI16: + gen_andi16(ctx); + break; + case POOL16D: + switch (ctx->opcode & 0x1) { + case ADDIUS5: + gen_addius5(ctx); + break; + case ADDIUSP: + gen_addiusp(ctx); + break; + } + break; + case POOL16E: + switch (ctx->opcode & 0x1) { + case ADDIUR2: + gen_addiur2(ctx); + break; + case ADDIUR1SP: + gen_addiur1sp(ctx); + break; + } + break; + case B16: /* BC16 */ + gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, + sextract32(ctx->opcode, 0, 10) << 1, + (ctx->insn_flags & ISA_MIPS_R6) ? 0 : 4); + break; + case BNEZ16: /* BNEZC16 */ + case BEQZ16: /* BEQZC16 */ + gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2, + mmreg(uMIPS_RD(ctx->opcode)), + 0, sextract32(ctx->opcode, 0, 7) << 1, + (ctx->insn_flags & ISA_MIPS_R6) ? 0 : 4); + + break; + case LI16: + { + int reg = mmreg(uMIPS_RD(ctx->opcode)); + int imm = ZIMM(ctx->opcode, 0, 7); + + imm = (imm == 0x7f ? -1 : imm); + tcg_gen_movi_tl(cpu_gpr[reg], imm); + } + break; + case RES_29: + case RES_31: + case RES_39: + gen_reserved_instruction(ctx); + break; + default: + decode_micromips32_opc(env, ctx); + return 4; + } + + return 2; +} diff --git a/target/mips/tcg/mips16e_translate.c.inc b/target/mips/tcg/mips16e_translate.c.inc new file mode 100644 index 0000000..5407181 --- /dev/null +++ b/target/mips/tcg/mips16e_translate.c.inc @@ -0,0 +1,1123 @@ +/* + * MIPS16 extension (Code Compaction) ASE translation routines + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * Copyright (c) 2006 Marius Groeger (FPU operations) + * Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support) + * Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support) + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +/* MIPS16 major opcodes */ +enum { + M16_OPC_ADDIUSP = 0x00, + M16_OPC_ADDIUPC = 0x01, + M16_OPC_B = 0x02, + M16_OPC_JAL = 0x03, + M16_OPC_BEQZ = 0x04, + M16_OPC_BNEQZ = 0x05, + M16_OPC_SHIFT = 0x06, + M16_OPC_LD = 0x07, + M16_OPC_RRIA = 0x08, + M16_OPC_ADDIU8 = 0x09, + M16_OPC_SLTI = 0x0a, + M16_OPC_SLTIU = 0x0b, + M16_OPC_I8 = 0x0c, + M16_OPC_LI = 0x0d, + M16_OPC_CMPI = 0x0e, + M16_OPC_SD = 0x0f, + M16_OPC_LB = 0x10, + M16_OPC_LH = 0x11, + M16_OPC_LWSP = 0x12, + M16_OPC_LW = 0x13, + M16_OPC_LBU = 0x14, + M16_OPC_LHU = 0x15, + M16_OPC_LWPC = 0x16, + M16_OPC_LWU = 0x17, + M16_OPC_SB = 0x18, + M16_OPC_SH = 0x19, + M16_OPC_SWSP = 0x1a, + M16_OPC_SW = 0x1b, + M16_OPC_RRR = 0x1c, + M16_OPC_RR = 0x1d, + M16_OPC_EXTEND = 0x1e, + M16_OPC_I64 = 0x1f +}; + +/* I8 funct field */ +enum { + I8_BTEQZ = 0x0, + I8_BTNEZ = 0x1, + I8_SWRASP = 0x2, + I8_ADJSP = 0x3, + I8_SVRS = 0x4, + I8_MOV32R = 0x5, + I8_MOVR32 = 0x7 +}; + +/* RRR f field */ +enum { + RRR_DADDU = 0x0, + RRR_ADDU = 0x1, + RRR_DSUBU = 0x2, + RRR_SUBU = 0x3 +}; + +/* RR funct field */ +enum { + RR_JR = 0x00, + RR_SDBBP = 0x01, + RR_SLT = 0x02, + RR_SLTU = 0x03, + RR_SLLV = 0x04, + RR_BREAK = 0x05, + RR_SRLV = 0x06, + RR_SRAV = 0x07, + RR_DSRL = 0x08, + RR_CMP = 0x0a, + RR_NEG = 0x0b, + RR_AND = 0x0c, + RR_OR = 0x0d, + RR_XOR = 0x0e, + RR_NOT = 0x0f, + RR_MFHI = 0x10, + RR_CNVT = 0x11, + RR_MFLO = 0x12, + RR_DSRA = 0x13, + RR_DSLLV = 0x14, + RR_DSRLV = 0x16, + RR_DSRAV = 0x17, + RR_MULT = 0x18, + RR_MULTU = 0x19, + RR_DIV = 0x1a, + RR_DIVU = 0x1b, + RR_DMULT = 0x1c, + RR_DMULTU = 0x1d, + RR_DDIV = 0x1e, + RR_DDIVU = 0x1f +}; + +/* I64 funct field */ +enum { + I64_LDSP = 0x0, + I64_SDSP = 0x1, + I64_SDRASP = 0x2, + I64_DADJSP = 0x3, + I64_LDPC = 0x4, + I64_DADDIU5 = 0x5, + I64_DADDIUPC = 0x6, + I64_DADDIUSP = 0x7 +}; + +/* RR ry field for CNVT */ +enum { + RR_RY_CNVT_ZEB = 0x0, + RR_RY_CNVT_ZEH = 0x1, + RR_RY_CNVT_ZEW = 0x2, + RR_RY_CNVT_SEB = 0x4, + RR_RY_CNVT_SEH = 0x5, + RR_RY_CNVT_SEW = 0x6, +}; + +static int xlat(int r) +{ + static int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 }; + + return map[r]; +} + +static void gen_mips16_save(DisasContext *ctx, + int xsregs, int aregs, + int do_ra, int do_s0, int do_s1, + int framesize) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + int args, astatic; + + switch (aregs) { + case 0: + case 1: + case 2: + case 3: + case 11: + args = 0; + break; + case 4: + case 5: + case 6: + case 7: + args = 1; + break; + case 8: + case 9: + case 10: + args = 2; + break; + case 12: + case 13: + args = 3; + break; + case 14: + args = 4; + break; + default: + gen_reserved_instruction(ctx); + return; + } + + switch (args) { + case 4: + gen_base_offset_addr(ctx, t0, 29, 12); + gen_load_gpr(t1, 7); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); + /* Fall through */ + case 3: + gen_base_offset_addr(ctx, t0, 29, 8); + gen_load_gpr(t1, 6); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); + /* Fall through */ + case 2: + gen_base_offset_addr(ctx, t0, 29, 4); + gen_load_gpr(t1, 5); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); + /* Fall through */ + case 1: + gen_base_offset_addr(ctx, t0, 29, 0); + gen_load_gpr(t1, 4); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); + } + + gen_load_gpr(t0, 29); + +#define DECR_AND_STORE(reg) do { \ + tcg_gen_movi_tl(t2, -4); \ + gen_op_addr_add(ctx, t0, t0, t2); \ + gen_load_gpr(t1, reg); \ + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); \ + } while (0) + + if (do_ra) { + DECR_AND_STORE(31); + } + + switch (xsregs) { + case 7: + DECR_AND_STORE(30); + /* Fall through */ + case 6: + DECR_AND_STORE(23); + /* Fall through */ + case 5: + DECR_AND_STORE(22); + /* Fall through */ + case 4: + DECR_AND_STORE(21); + /* Fall through */ + case 3: + DECR_AND_STORE(20); + /* Fall through */ + case 2: + DECR_AND_STORE(19); + /* Fall through */ + case 1: + DECR_AND_STORE(18); + } + + if (do_s1) { + DECR_AND_STORE(17); + } + if (do_s0) { + DECR_AND_STORE(16); + } + + switch (aregs) { + case 0: + case 4: + case 8: + case 12: + case 14: + astatic = 0; + break; + case 1: + case 5: + case 9: + case 13: + astatic = 1; + break; + case 2: + case 6: + case 10: + astatic = 2; + break; + case 3: + case 7: + astatic = 3; + break; + case 11: + astatic = 4; + break; + default: + gen_reserved_instruction(ctx); + return; + } + + if (astatic > 0) { + DECR_AND_STORE(7); + if (astatic > 1) { + DECR_AND_STORE(6); + if (astatic > 2) { + DECR_AND_STORE(5); + if (astatic > 3) { + DECR_AND_STORE(4); + } + } + } + } +#undef DECR_AND_STORE + + tcg_gen_movi_tl(t2, -framesize); + gen_op_addr_add(ctx, cpu_gpr[29], cpu_gpr[29], t2); + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); +} + +static void gen_mips16_restore(DisasContext *ctx, + int xsregs, int aregs, + int do_ra, int do_s0, int do_s1, + int framesize) +{ + int astatic; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + + tcg_gen_movi_tl(t2, framesize); + gen_op_addr_add(ctx, t0, cpu_gpr[29], t2); + +#define DECR_AND_LOAD(reg) do { \ + tcg_gen_movi_tl(t2, -4); \ + gen_op_addr_add(ctx, t0, t0, t2); \ + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL); \ + gen_store_gpr(t1, reg); \ + } while (0) + + if (do_ra) { + DECR_AND_LOAD(31); + } + + switch (xsregs) { + case 7: + DECR_AND_LOAD(30); + /* Fall through */ + case 6: + DECR_AND_LOAD(23); + /* Fall through */ + case 5: + DECR_AND_LOAD(22); + /* Fall through */ + case 4: + DECR_AND_LOAD(21); + /* Fall through */ + case 3: + DECR_AND_LOAD(20); + /* Fall through */ + case 2: + DECR_AND_LOAD(19); + /* Fall through */ + case 1: + DECR_AND_LOAD(18); + } + + if (do_s1) { + DECR_AND_LOAD(17); + } + if (do_s0) { + DECR_AND_LOAD(16); + } + + switch (aregs) { + case 0: + case 4: + case 8: + case 12: + case 14: + astatic = 0; + break; + case 1: + case 5: + case 9: + case 13: + astatic = 1; + break; + case 2: + case 6: + case 10: + astatic = 2; + break; + case 3: + case 7: + astatic = 3; + break; + case 11: + astatic = 4; + break; + default: + gen_reserved_instruction(ctx); + return; + } + + if (astatic > 0) { + DECR_AND_LOAD(7); + if (astatic > 1) { + DECR_AND_LOAD(6); + if (astatic > 2) { + DECR_AND_LOAD(5); + if (astatic > 3) { + DECR_AND_LOAD(4); + } + } + } + } +#undef DECR_AND_LOAD + + tcg_gen_movi_tl(t2, framesize); + gen_op_addr_add(ctx, cpu_gpr[29], cpu_gpr[29], t2); + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); +} + +#if defined(TARGET_MIPS64) +static void decode_i64_mips16(DisasContext *ctx, + int ry, int funct, int16_t offset, + int extended) +{ + switch (funct) { + case I64_LDSP: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + offset = extended ? offset : offset << 3; + gen_ld(ctx, OPC_LD, ry, 29, offset); + break; + case I64_SDSP: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + offset = extended ? offset : offset << 3; + gen_st(ctx, OPC_SD, ry, 29, offset); + break; + case I64_SDRASP: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + offset = extended ? offset : (ctx->opcode & 0xff) << 3; + gen_st(ctx, OPC_SD, 31, 29, offset); + break; + case I64_DADJSP: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + offset = extended ? offset : ((int8_t)ctx->opcode) << 3; + gen_arith_imm(ctx, OPC_DADDIU, 29, 29, offset); + break; + case I64_LDPC: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + if (extended && (ctx->hflags & MIPS_HFLAG_BMASK)) { + gen_reserved_instruction(ctx); + } else { + offset = extended ? offset : offset << 3; + gen_ld(ctx, OPC_LDPC, ry, 0, offset); + } + break; + case I64_DADDIU5: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + offset = extended ? offset : ((int8_t)(offset << 3)) >> 3; + gen_arith_imm(ctx, OPC_DADDIU, ry, ry, offset); + break; + case I64_DADDIUPC: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + offset = extended ? offset : offset << 2; + gen_addiupc(ctx, ry, offset, 1, extended); + break; + case I64_DADDIUSP: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + offset = extended ? offset : offset << 2; + gen_arith_imm(ctx, OPC_DADDIU, ry, 29, offset); + break; + } +} +#endif + +static int decode_extended_mips16_opc(CPUMIPSState *env, DisasContext *ctx) +{ + int extend = translator_lduw(env, ctx->base.pc_next + 2); + int op, rx, ry, funct, sa; + int16_t imm, offset; + + ctx->opcode = (ctx->opcode << 16) | extend; + op = (ctx->opcode >> 11) & 0x1f; + sa = (ctx->opcode >> 22) & 0x1f; + funct = (ctx->opcode >> 8) & 0x7; + rx = xlat((ctx->opcode >> 8) & 0x7); + ry = xlat((ctx->opcode >> 5) & 0x7); + offset = imm = (int16_t) (((ctx->opcode >> 16) & 0x1f) << 11 + | ((ctx->opcode >> 21) & 0x3f) << 5 + | (ctx->opcode & 0x1f)); + + /* + * The extended opcodes cleverly reuse the opcodes from their 16-bit + * counterparts. + */ + switch (op) { + case M16_OPC_ADDIUSP: + gen_arith_imm(ctx, OPC_ADDIU, rx, 29, imm); + break; + case M16_OPC_ADDIUPC: + gen_addiupc(ctx, rx, imm, 0, 1); + break; + case M16_OPC_B: + gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1, 0); + /* No delay slot, so just process as a normal instruction */ + break; + case M16_OPC_BEQZ: + gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1, 0); + /* No delay slot, so just process as a normal instruction */ + break; + case M16_OPC_BNEQZ: + gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1, 0); + /* No delay slot, so just process as a normal instruction */ + break; + case M16_OPC_SHIFT: + switch (ctx->opcode & 0x3) { + case 0x0: + gen_shift_imm(ctx, OPC_SLL, rx, ry, sa); + break; + case 0x1: +#if defined(TARGET_MIPS64) + check_mips_64(ctx); + gen_shift_imm(ctx, OPC_DSLL, rx, ry, sa); +#else + gen_reserved_instruction(ctx); +#endif + break; + case 0x2: + gen_shift_imm(ctx, OPC_SRL, rx, ry, sa); + break; + case 0x3: + gen_shift_imm(ctx, OPC_SRA, rx, ry, sa); + break; + } + break; +#if defined(TARGET_MIPS64) + case M16_OPC_LD: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_ld(ctx, OPC_LD, ry, rx, offset); + break; +#endif + case M16_OPC_RRIA: + imm = ctx->opcode & 0xf; + imm = imm | ((ctx->opcode >> 20) & 0x7f) << 4; + imm = imm | ((ctx->opcode >> 16) & 0xf) << 11; + imm = (int16_t) (imm << 1) >> 1; + if ((ctx->opcode >> 4) & 0x1) { +#if defined(TARGET_MIPS64) + check_mips_64(ctx); + gen_arith_imm(ctx, OPC_DADDIU, ry, rx, imm); +#else + gen_reserved_instruction(ctx); +#endif + } else { + gen_arith_imm(ctx, OPC_ADDIU, ry, rx, imm); + } + break; + case M16_OPC_ADDIU8: + gen_arith_imm(ctx, OPC_ADDIU, rx, rx, imm); + break; + case M16_OPC_SLTI: + gen_slt_imm(ctx, OPC_SLTI, 24, rx, imm); + break; + case M16_OPC_SLTIU: + gen_slt_imm(ctx, OPC_SLTIU, 24, rx, imm); + break; + case M16_OPC_I8: + switch (funct) { + case I8_BTEQZ: + gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1, 0); + break; + case I8_BTNEZ: + gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1, 0); + break; + case I8_SWRASP: + gen_st(ctx, OPC_SW, 31, 29, imm); + break; + case I8_ADJSP: + gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm); + break; + case I8_SVRS: + check_insn(ctx, ISA_MIPS_R1); + { + int xsregs = (ctx->opcode >> 24) & 0x7; + int aregs = (ctx->opcode >> 16) & 0xf; + int do_ra = (ctx->opcode >> 6) & 0x1; + int do_s0 = (ctx->opcode >> 5) & 0x1; + int do_s1 = (ctx->opcode >> 4) & 0x1; + int framesize = (((ctx->opcode >> 20) & 0xf) << 4 + | (ctx->opcode & 0xf)) << 3; + + if (ctx->opcode & (1 << 7)) { + gen_mips16_save(ctx, xsregs, aregs, + do_ra, do_s0, do_s1, + framesize); + } else { + gen_mips16_restore(ctx, xsregs, aregs, + do_ra, do_s0, do_s1, + framesize); + } + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case M16_OPC_LI: + tcg_gen_movi_tl(cpu_gpr[rx], (uint16_t) imm); + break; + case M16_OPC_CMPI: + tcg_gen_xori_tl(cpu_gpr[24], cpu_gpr[rx], (uint16_t) imm); + break; +#if defined(TARGET_MIPS64) + case M16_OPC_SD: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_st(ctx, OPC_SD, ry, rx, offset); + break; +#endif + case M16_OPC_LB: + gen_ld(ctx, OPC_LB, ry, rx, offset); + break; + case M16_OPC_LH: + gen_ld(ctx, OPC_LH, ry, rx, offset); + break; + case M16_OPC_LWSP: + gen_ld(ctx, OPC_LW, rx, 29, offset); + break; + case M16_OPC_LW: + gen_ld(ctx, OPC_LW, ry, rx, offset); + break; + case M16_OPC_LBU: + gen_ld(ctx, OPC_LBU, ry, rx, offset); + break; + case M16_OPC_LHU: + gen_ld(ctx, OPC_LHU, ry, rx, offset); + break; + case M16_OPC_LWPC: + gen_ld(ctx, OPC_LWPC, rx, 0, offset); + break; +#if defined(TARGET_MIPS64) + case M16_OPC_LWU: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_ld(ctx, OPC_LWU, ry, rx, offset); + break; +#endif + case M16_OPC_SB: + gen_st(ctx, OPC_SB, ry, rx, offset); + break; + case M16_OPC_SH: + gen_st(ctx, OPC_SH, ry, rx, offset); + break; + case M16_OPC_SWSP: + gen_st(ctx, OPC_SW, rx, 29, offset); + break; + case M16_OPC_SW: + gen_st(ctx, OPC_SW, ry, rx, offset); + break; +#if defined(TARGET_MIPS64) + case M16_OPC_I64: + decode_i64_mips16(ctx, ry, funct, offset, 1); + break; +#endif + default: + gen_reserved_instruction(ctx); + break; + } + + return 4; +} + +static int decode_ase_mips16e(CPUMIPSState *env, DisasContext *ctx) +{ + int rx, ry; + int sa; + int op, cnvt_op, op1, offset; + int funct; + int n_bytes; + + op = (ctx->opcode >> 11) & 0x1f; + sa = (ctx->opcode >> 2) & 0x7; + sa = sa == 0 ? 8 : sa; + rx = xlat((ctx->opcode >> 8) & 0x7); + cnvt_op = (ctx->opcode >> 5) & 0x7; + ry = xlat((ctx->opcode >> 5) & 0x7); + op1 = offset = ctx->opcode & 0x1f; + + n_bytes = 2; + + switch (op) { + case M16_OPC_ADDIUSP: + { + int16_t imm = ((uint8_t) ctx->opcode) << 2; + + gen_arith_imm(ctx, OPC_ADDIU, rx, 29, imm); + } + break; + case M16_OPC_ADDIUPC: + gen_addiupc(ctx, rx, ((uint8_t) ctx->opcode) << 2, 0, 0); + break; + case M16_OPC_B: + offset = (ctx->opcode & 0x7ff) << 1; + offset = (int16_t)(offset << 4) >> 4; + gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset, 0); + /* No delay slot, so just process as a normal instruction */ + break; + case M16_OPC_JAL: + offset = translator_lduw(env, ctx->base.pc_next + 2); + offset = (((ctx->opcode & 0x1f) << 21) + | ((ctx->opcode >> 5) & 0x1f) << 16 + | offset) << 2; + op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALX : OPC_JAL; + gen_compute_branch(ctx, op, 4, rx, ry, offset, 2); + n_bytes = 4; + break; + case M16_OPC_BEQZ: + gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, + ((int8_t)ctx->opcode) << 1, 0); + /* No delay slot, so just process as a normal instruction */ + break; + case M16_OPC_BNEQZ: + gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, + ((int8_t)ctx->opcode) << 1, 0); + /* No delay slot, so just process as a normal instruction */ + break; + case M16_OPC_SHIFT: + switch (ctx->opcode & 0x3) { + case 0x0: + gen_shift_imm(ctx, OPC_SLL, rx, ry, sa); + break; + case 0x1: +#if defined(TARGET_MIPS64) + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift_imm(ctx, OPC_DSLL, rx, ry, sa); +#else + gen_reserved_instruction(ctx); +#endif + break; + case 0x2: + gen_shift_imm(ctx, OPC_SRL, rx, ry, sa); + break; + case 0x3: + gen_shift_imm(ctx, OPC_SRA, rx, ry, sa); + break; + } + break; +#if defined(TARGET_MIPS64) + case M16_OPC_LD: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_ld(ctx, OPC_LD, ry, rx, offset << 3); + break; +#endif + case M16_OPC_RRIA: + { + int16_t imm = (int8_t)((ctx->opcode & 0xf) << 4) >> 4; + + if ((ctx->opcode >> 4) & 1) { +#if defined(TARGET_MIPS64) + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_arith_imm(ctx, OPC_DADDIU, ry, rx, imm); +#else + gen_reserved_instruction(ctx); +#endif + } else { + gen_arith_imm(ctx, OPC_ADDIU, ry, rx, imm); + } + } + break; + case M16_OPC_ADDIU8: + { + int16_t imm = (int8_t) ctx->opcode; + + gen_arith_imm(ctx, OPC_ADDIU, rx, rx, imm); + } + break; + case M16_OPC_SLTI: + { + int16_t imm = (uint8_t) ctx->opcode; + gen_slt_imm(ctx, OPC_SLTI, 24, rx, imm); + } + break; + case M16_OPC_SLTIU: + { + int16_t imm = (uint8_t) ctx->opcode; + gen_slt_imm(ctx, OPC_SLTIU, 24, rx, imm); + } + break; + case M16_OPC_I8: + { + int reg32; + + funct = (ctx->opcode >> 8) & 0x7; + switch (funct) { + case I8_BTEQZ: + gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0, + ((int8_t)ctx->opcode) << 1, 0); + break; + case I8_BTNEZ: + gen_compute_branch(ctx, OPC_BNE, 2, 24, 0, + ((int8_t)ctx->opcode) << 1, 0); + break; + case I8_SWRASP: + gen_st(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2); + break; + case I8_ADJSP: + gen_arith_imm(ctx, OPC_ADDIU, 29, 29, + ((int8_t)ctx->opcode) << 3); + break; + case I8_SVRS: + check_insn(ctx, ISA_MIPS_R1); + { + int do_ra = ctx->opcode & (1 << 6); + int do_s0 = ctx->opcode & (1 << 5); + int do_s1 = ctx->opcode & (1 << 4); + int framesize = ctx->opcode & 0xf; + + if (framesize == 0) { + framesize = 128; + } else { + framesize = framesize << 3; + } + + if (ctx->opcode & (1 << 7)) { + gen_mips16_save(ctx, 0, 0, + do_ra, do_s0, do_s1, framesize); + } else { + gen_mips16_restore(ctx, 0, 0, + do_ra, do_s0, do_s1, framesize); + } + } + break; + case I8_MOV32R: + { + int rz = xlat(ctx->opcode & 0x7); + + reg32 = (((ctx->opcode >> 3) & 0x3) << 3) | + ((ctx->opcode >> 5) & 0x7); + gen_arith(ctx, OPC_ADDU, reg32, rz, 0); + } + break; + case I8_MOVR32: + reg32 = ctx->opcode & 0x1f; + gen_arith(ctx, OPC_ADDU, ry, reg32, 0); + break; + default: + gen_reserved_instruction(ctx); + break; + } + } + break; + case M16_OPC_LI: + { + int16_t imm = (uint8_t) ctx->opcode; + + gen_arith_imm(ctx, OPC_ADDIU, rx, 0, imm); + } + break; + case M16_OPC_CMPI: + { + int16_t imm = (uint8_t) ctx->opcode; + gen_logic_imm(ctx, OPC_XORI, 24, rx, imm); + } + break; +#if defined(TARGET_MIPS64) + case M16_OPC_SD: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_st(ctx, OPC_SD, ry, rx, offset << 3); + break; +#endif + case M16_OPC_LB: + gen_ld(ctx, OPC_LB, ry, rx, offset); + break; + case M16_OPC_LH: + gen_ld(ctx, OPC_LH, ry, rx, offset << 1); + break; + case M16_OPC_LWSP: + gen_ld(ctx, OPC_LW, rx, 29, ((uint8_t)ctx->opcode) << 2); + break; + case M16_OPC_LW: + gen_ld(ctx, OPC_LW, ry, rx, offset << 2); + break; + case M16_OPC_LBU: + gen_ld(ctx, OPC_LBU, ry, rx, offset); + break; + case M16_OPC_LHU: + gen_ld(ctx, OPC_LHU, ry, rx, offset << 1); + break; + case M16_OPC_LWPC: + gen_ld(ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2); + break; +#if defined(TARGET_MIPS64) + case M16_OPC_LWU: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_ld(ctx, OPC_LWU, ry, rx, offset << 2); + break; +#endif + case M16_OPC_SB: + gen_st(ctx, OPC_SB, ry, rx, offset); + break; + case M16_OPC_SH: + gen_st(ctx, OPC_SH, ry, rx, offset << 1); + break; + case M16_OPC_SWSP: + gen_st(ctx, OPC_SW, rx, 29, ((uint8_t)ctx->opcode) << 2); + break; + case M16_OPC_SW: + gen_st(ctx, OPC_SW, ry, rx, offset << 2); + break; + case M16_OPC_RRR: + { + int rz = xlat((ctx->opcode >> 2) & 0x7); + int mips32_op; + + switch (ctx->opcode & 0x3) { + case RRR_ADDU: + mips32_op = OPC_ADDU; + break; + case RRR_SUBU: + mips32_op = OPC_SUBU; + break; +#if defined(TARGET_MIPS64) + case RRR_DADDU: + mips32_op = OPC_DADDU; + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + break; + case RRR_DSUBU: + mips32_op = OPC_DSUBU; + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + break; +#endif + default: + gen_reserved_instruction(ctx); + goto done; + } + + gen_arith(ctx, mips32_op, rz, rx, ry); + done: + ; + } + break; + case M16_OPC_RR: + switch (op1) { + case RR_JR: + { + int nd = (ctx->opcode >> 7) & 0x1; + int link = (ctx->opcode >> 6) & 0x1; + int ra = (ctx->opcode >> 5) & 0x1; + + if (nd) { + check_insn(ctx, ISA_MIPS_R1); + } + + if (link) { + op = OPC_JALR; + } else { + op = OPC_JR; + } + + gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0, + (nd ? 0 : 2)); + } + break; + case RR_SDBBP: + if (is_uhi(extract32(ctx->opcode, 5, 6))) { + gen_helper_do_semihosting(cpu_env); + } else { + /* + * XXX: not clear which exception should be raised + * when in debug mode... + */ + check_insn(ctx, ISA_MIPS_R1); + generate_exception_end(ctx, EXCP_DBp); + } + break; + case RR_SLT: + gen_slt(ctx, OPC_SLT, 24, rx, ry); + break; + case RR_SLTU: + gen_slt(ctx, OPC_SLTU, 24, rx, ry); + break; + case RR_BREAK: + generate_exception_end(ctx, EXCP_BREAK); + break; + case RR_SLLV: + gen_shift(ctx, OPC_SLLV, ry, rx, ry); + break; + case RR_SRLV: + gen_shift(ctx, OPC_SRLV, ry, rx, ry); + break; + case RR_SRAV: + gen_shift(ctx, OPC_SRAV, ry, rx, ry); + break; +#if defined(TARGET_MIPS64) + case RR_DSRL: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift_imm(ctx, OPC_DSRL, ry, ry, sa); + break; +#endif + case RR_CMP: + gen_logic(ctx, OPC_XOR, 24, rx, ry); + break; + case RR_NEG: + gen_arith(ctx, OPC_SUBU, rx, 0, ry); + break; + case RR_AND: + gen_logic(ctx, OPC_AND, rx, rx, ry); + break; + case RR_OR: + gen_logic(ctx, OPC_OR, rx, rx, ry); + break; + case RR_XOR: + gen_logic(ctx, OPC_XOR, rx, rx, ry); + break; + case RR_NOT: + gen_logic(ctx, OPC_NOR, rx, ry, 0); + break; + case RR_MFHI: + gen_HILO(ctx, OPC_MFHI, 0, rx); + break; + case RR_CNVT: + check_insn(ctx, ISA_MIPS_R1); + switch (cnvt_op) { + case RR_RY_CNVT_ZEB: + tcg_gen_ext8u_tl(cpu_gpr[rx], cpu_gpr[rx]); + break; + case RR_RY_CNVT_ZEH: + tcg_gen_ext16u_tl(cpu_gpr[rx], cpu_gpr[rx]); + break; + case RR_RY_CNVT_SEB: + tcg_gen_ext8s_tl(cpu_gpr[rx], cpu_gpr[rx]); + break; + case RR_RY_CNVT_SEH: + tcg_gen_ext16s_tl(cpu_gpr[rx], cpu_gpr[rx]); + break; +#if defined(TARGET_MIPS64) + case RR_RY_CNVT_ZEW: + check_insn(ctx, ISA_MIPS_R1); + check_mips_64(ctx); + tcg_gen_ext32u_tl(cpu_gpr[rx], cpu_gpr[rx]); + break; + case RR_RY_CNVT_SEW: + check_insn(ctx, ISA_MIPS_R1); + check_mips_64(ctx); + tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]); + break; +#endif + default: + gen_reserved_instruction(ctx); + break; + } + break; + case RR_MFLO: + gen_HILO(ctx, OPC_MFLO, 0, rx); + break; +#if defined(TARGET_MIPS64) + case RR_DSRA: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift_imm(ctx, OPC_DSRA, ry, ry, sa); + break; + case RR_DSLLV: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift(ctx, OPC_DSLLV, ry, rx, ry); + break; + case RR_DSRLV: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift(ctx, OPC_DSRLV, ry, rx, ry); + break; + case RR_DSRAV: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_shift(ctx, OPC_DSRAV, ry, rx, ry); + break; +#endif + case RR_MULT: + gen_muldiv(ctx, OPC_MULT, 0, rx, ry); + break; + case RR_MULTU: + gen_muldiv(ctx, OPC_MULTU, 0, rx, ry); + break; + case RR_DIV: + gen_muldiv(ctx, OPC_DIV, 0, rx, ry); + break; + case RR_DIVU: + gen_muldiv(ctx, OPC_DIVU, 0, rx, ry); + break; +#if defined(TARGET_MIPS64) + case RR_DMULT: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_muldiv(ctx, OPC_DMULT, 0, rx, ry); + break; + case RR_DMULTU: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_muldiv(ctx, OPC_DMULTU, 0, rx, ry); + break; + case RR_DDIV: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_muldiv(ctx, OPC_DDIV, 0, rx, ry); + break; + case RR_DDIVU: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_muldiv(ctx, OPC_DDIVU, 0, rx, ry); + break; +#endif + default: + gen_reserved_instruction(ctx); + break; + } + break; + case M16_OPC_EXTEND: + decode_extended_mips16_opc(env, ctx); + n_bytes = 4; + break; +#if defined(TARGET_MIPS64) + case M16_OPC_I64: + funct = (ctx->opcode >> 8) & 0x7; + decode_i64_mips16(ctx, ry, funct, offset, 0); + break; +#endif + default: + gen_reserved_instruction(ctx); + break; + } + + return n_bytes; +} diff --git a/target/mips/tcg/nanomips_translate.c.inc b/target/mips/tcg/nanomips_translate.c.inc new file mode 100644 index 0000000..09e64a6 --- /dev/null +++ b/target/mips/tcg/nanomips_translate.c.inc @@ -0,0 +1,4922 @@ +/* + * MIPS emulation for QEMU - nanoMIPS translation routines + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * Copyright (c) 2006 Marius Groeger (FPU operations) + * Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support) + * Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support) + * Copyright (c) 2012 Jia Liu & Dongxue Zhang (MIPS ASE DSP support) + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +/* MAJOR, P16, and P32 pools opcodes */ +enum { + NM_P_ADDIU = 0x00, + NM_ADDIUPC = 0x01, + NM_MOVE_BALC = 0x02, + NM_P16_MV = 0x04, + NM_LW16 = 0x05, + NM_BC16 = 0x06, + NM_P16_SR = 0x07, + + NM_POOL32A = 0x08, + NM_P_BAL = 0x0a, + NM_P16_SHIFT = 0x0c, + NM_LWSP16 = 0x0d, + NM_BALC16 = 0x0e, + NM_P16_4X4 = 0x0f, + + NM_P_GP_W = 0x10, + NM_P_GP_BH = 0x11, + NM_P_J = 0x12, + NM_P16C = 0x14, + NM_LWGP16 = 0x15, + NM_P16_LB = 0x17, + + NM_P48I = 0x18, + NM_P16_A1 = 0x1c, + NM_LW4X4 = 0x1d, + NM_P16_LH = 0x1f, + + NM_P_U12 = 0x20, + NM_P_LS_U12 = 0x21, + NM_P_BR1 = 0x22, + NM_P16_A2 = 0x24, + NM_SW16 = 0x25, + NM_BEQZC16 = 0x26, + + NM_POOL32F = 0x28, + NM_P_LS_S9 = 0x29, + NM_P_BR2 = 0x2a, + + NM_P16_ADDU = 0x2c, + NM_SWSP16 = 0x2d, + NM_BNEZC16 = 0x2e, + NM_MOVEP = 0x2f, + + NM_POOL32S = 0x30, + NM_P_BRI = 0x32, + NM_LI16 = 0x34, + NM_SWGP16 = 0x35, + NM_P16_BR = 0x36, + + NM_P_LUI = 0x38, + NM_ANDI16 = 0x3c, + NM_SW4X4 = 0x3d, + NM_MOVEPREV = 0x3f, +}; + +/* POOL32A instruction pool */ +enum { + NM_POOL32A0 = 0x00, + NM_SPECIAL2 = 0x01, + NM_COP2_1 = 0x02, + NM_UDI = 0x03, + NM_POOL32A5 = 0x05, + NM_POOL32A7 = 0x07, +}; + +/* P.GP.W instruction pool */ +enum { + NM_ADDIUGP_W = 0x00, + NM_LWGP = 0x02, + NM_SWGP = 0x03, +}; + +/* P48I instruction pool */ +enum { + NM_LI48 = 0x00, + NM_ADDIU48 = 0x01, + NM_ADDIUGP48 = 0x02, + NM_ADDIUPC48 = 0x03, + NM_LWPC48 = 0x0b, + NM_SWPC48 = 0x0f, +}; + +/* P.U12 instruction pool */ +enum { + NM_ORI = 0x00, + NM_XORI = 0x01, + NM_ANDI = 0x02, + NM_P_SR = 0x03, + NM_SLTI = 0x04, + NM_SLTIU = 0x05, + NM_SEQI = 0x06, + NM_ADDIUNEG = 0x08, + NM_P_SHIFT = 0x0c, + NM_P_ROTX = 0x0d, + NM_P_INS = 0x0e, + NM_P_EXT = 0x0f, +}; + +/* POOL32F instruction pool */ +enum { + NM_POOL32F_0 = 0x00, + NM_POOL32F_3 = 0x03, + NM_POOL32F_5 = 0x05, +}; + +/* POOL32S instruction pool */ +enum { + NM_POOL32S_0 = 0x00, + NM_POOL32S_4 = 0x04, +}; + +/* P.LUI instruction pool */ +enum { + NM_LUI = 0x00, + NM_ALUIPC = 0x01, +}; + +/* P.GP.BH instruction pool */ +enum { + NM_LBGP = 0x00, + NM_SBGP = 0x01, + NM_LBUGP = 0x02, + NM_ADDIUGP_B = 0x03, + NM_P_GP_LH = 0x04, + NM_P_GP_SH = 0x05, + NM_P_GP_CP1 = 0x06, +}; + +/* P.LS.U12 instruction pool */ +enum { + NM_LB = 0x00, + NM_SB = 0x01, + NM_LBU = 0x02, + NM_P_PREFU12 = 0x03, + NM_LH = 0x04, + NM_SH = 0x05, + NM_LHU = 0x06, + NM_LWU = 0x07, + NM_LW = 0x08, + NM_SW = 0x09, + NM_LWC1 = 0x0a, + NM_SWC1 = 0x0b, + NM_LDC1 = 0x0e, + NM_SDC1 = 0x0f, +}; + +/* P.LS.S9 instruction pool */ +enum { + NM_P_LS_S0 = 0x00, + NM_P_LS_S1 = 0x01, + NM_P_LS_E0 = 0x02, + NM_P_LS_WM = 0x04, + NM_P_LS_UAWM = 0x05, +}; + +/* P.BAL instruction pool */ +enum { + NM_BC = 0x00, + NM_BALC = 0x01, +}; + +/* P.J instruction pool */ +enum { + NM_JALRC = 0x00, + NM_JALRC_HB = 0x01, + NM_P_BALRSC = 0x08, +}; + +/* P.BR1 instruction pool */ +enum { + NM_BEQC = 0x00, + NM_P_BR3A = 0x01, + NM_BGEC = 0x02, + NM_BGEUC = 0x03, +}; + +/* P.BR2 instruction pool */ +enum { + NM_BNEC = 0x00, + NM_BLTC = 0x02, + NM_BLTUC = 0x03, +}; + +/* P.BRI instruction pool */ +enum { + NM_BEQIC = 0x00, + NM_BBEQZC = 0x01, + NM_BGEIC = 0x02, + NM_BGEIUC = 0x03, + NM_BNEIC = 0x04, + NM_BBNEZC = 0x05, + NM_BLTIC = 0x06, + NM_BLTIUC = 0x07, +}; + +/* P16.SHIFT instruction pool */ +enum { + NM_SLL16 = 0x00, + NM_SRL16 = 0x01, +}; + +/* POOL16C instruction pool */ +enum { + NM_POOL16C_0 = 0x00, + NM_LWXS16 = 0x01, +}; + +/* P16.A1 instruction pool */ +enum { + NM_ADDIUR1SP = 0x01, +}; + +/* P16.A2 instruction pool */ +enum { + NM_ADDIUR2 = 0x00, + NM_P_ADDIURS5 = 0x01, +}; + +/* P16.ADDU instruction pool */ +enum { + NM_ADDU16 = 0x00, + NM_SUBU16 = 0x01, +}; + +/* P16.SR instruction pool */ +enum { + NM_SAVE16 = 0x00, + NM_RESTORE_JRC16 = 0x01, +}; + +/* P16.4X4 instruction pool */ +enum { + NM_ADDU4X4 = 0x00, + NM_MUL4X4 = 0x01, +}; + +/* P16.LB instruction pool */ +enum { + NM_LB16 = 0x00, + NM_SB16 = 0x01, + NM_LBU16 = 0x02, +}; + +/* P16.LH instruction pool */ +enum { + NM_LH16 = 0x00, + NM_SH16 = 0x01, + NM_LHU16 = 0x02, +}; + +/* P.RI instruction pool */ +enum { + NM_SIGRIE = 0x00, + NM_P_SYSCALL = 0x01, + NM_BREAK = 0x02, + NM_SDBBP = 0x03, +}; + +/* POOL32A0 instruction pool */ +enum { + NM_P_TRAP = 0x00, + NM_SEB = 0x01, + NM_SLLV = 0x02, + NM_MUL = 0x03, + NM_MFC0 = 0x06, + NM_MFHC0 = 0x07, + NM_SEH = 0x09, + NM_SRLV = 0x0a, + NM_MUH = 0x0b, + NM_MTC0 = 0x0e, + NM_MTHC0 = 0x0f, + NM_SRAV = 0x12, + NM_MULU = 0x13, + NM_ROTRV = 0x1a, + NM_MUHU = 0x1b, + NM_ADD = 0x22, + NM_DIV = 0x23, + NM_ADDU = 0x2a, + NM_MOD = 0x2b, + NM_SUB = 0x32, + NM_DIVU = 0x33, + NM_RDHWR = 0x38, + NM_SUBU = 0x3a, + NM_MODU = 0x3b, + NM_P_CMOVE = 0x42, + NM_FORK = 0x45, + NM_MFTR = 0x46, + NM_MFHTR = 0x47, + NM_AND = 0x4a, + NM_YIELD = 0x4d, + NM_MTTR = 0x4e, + NM_MTHTR = 0x4f, + NM_OR = 0x52, + NM_D_E_MT_VPE = 0x56, + NM_NOR = 0x5a, + NM_XOR = 0x62, + NM_SLT = 0x6a, + NM_P_SLTU = 0x72, + NM_SOV = 0x7a, +}; + +/* CRC32 instruction pool */ +enum { + NM_CRC32B = 0x00, + NM_CRC32H = 0x01, + NM_CRC32W = 0x02, + NM_CRC32CB = 0x04, + NM_CRC32CH = 0x05, + NM_CRC32CW = 0x06, +}; + +/* POOL32A5 instruction pool */ +enum { + NM_CMP_EQ_PH = 0x00, + NM_CMP_LT_PH = 0x08, + NM_CMP_LE_PH = 0x10, + NM_CMPGU_EQ_QB = 0x18, + NM_CMPGU_LT_QB = 0x20, + NM_CMPGU_LE_QB = 0x28, + NM_CMPGDU_EQ_QB = 0x30, + NM_CMPGDU_LT_QB = 0x38, + NM_CMPGDU_LE_QB = 0x40, + NM_CMPU_EQ_QB = 0x48, + NM_CMPU_LT_QB = 0x50, + NM_CMPU_LE_QB = 0x58, + NM_ADDQ_S_W = 0x60, + NM_SUBQ_S_W = 0x68, + NM_ADDSC = 0x70, + NM_ADDWC = 0x78, + + NM_ADDQ_S_PH = 0x01, + NM_ADDQH_R_PH = 0x09, + NM_ADDQH_R_W = 0x11, + NM_ADDU_S_QB = 0x19, + NM_ADDU_S_PH = 0x21, + NM_ADDUH_R_QB = 0x29, + NM_SHRAV_R_PH = 0x31, + NM_SHRAV_R_QB = 0x39, + NM_SUBQ_S_PH = 0x41, + NM_SUBQH_R_PH = 0x49, + NM_SUBQH_R_W = 0x51, + NM_SUBU_S_QB = 0x59, + NM_SUBU_S_PH = 0x61, + NM_SUBUH_R_QB = 0x69, + NM_SHLLV_S_PH = 0x71, + NM_PRECR_SRA_R_PH_W = 0x79, + + NM_MULEU_S_PH_QBL = 0x12, + NM_MULEU_S_PH_QBR = 0x1a, + NM_MULQ_RS_PH = 0x22, + NM_MULQ_S_PH = 0x2a, + NM_MULQ_RS_W = 0x32, + NM_MULQ_S_W = 0x3a, + NM_APPEND = 0x42, + NM_MODSUB = 0x52, + NM_SHRAV_R_W = 0x5a, + NM_SHRLV_PH = 0x62, + NM_SHRLV_QB = 0x6a, + NM_SHLLV_QB = 0x72, + NM_SHLLV_S_W = 0x7a, + + NM_SHILO = 0x03, + + NM_MULEQ_S_W_PHL = 0x04, + NM_MULEQ_S_W_PHR = 0x0c, + + NM_MUL_S_PH = 0x05, + NM_PRECR_QB_PH = 0x0d, + NM_PRECRQ_QB_PH = 0x15, + NM_PRECRQ_PH_W = 0x1d, + NM_PRECRQ_RS_PH_W = 0x25, + NM_PRECRQU_S_QB_PH = 0x2d, + NM_PACKRL_PH = 0x35, + NM_PICK_QB = 0x3d, + NM_PICK_PH = 0x45, + + NM_SHRA_R_W = 0x5e, + NM_SHRA_R_PH = 0x66, + NM_SHLL_S_PH = 0x76, + NM_SHLL_S_W = 0x7e, + + NM_REPL_PH = 0x07 +}; + +/* POOL32A7 instruction pool */ +enum { + NM_P_LSX = 0x00, + NM_LSA = 0x01, + NM_EXTW = 0x03, + NM_POOL32AXF = 0x07, +}; + +/* P.SR instruction pool */ +enum { + NM_PP_SR = 0x00, + NM_P_SR_F = 0x01, +}; + +/* P.SHIFT instruction pool */ +enum { + NM_P_SLL = 0x00, + NM_SRL = 0x02, + NM_SRA = 0x04, + NM_ROTR = 0x06, +}; + +/* P.ROTX instruction pool */ +enum { + NM_ROTX = 0x00, +}; + +/* P.INS instruction pool */ +enum { + NM_INS = 0x00, +}; + +/* P.EXT instruction pool */ +enum { + NM_EXT = 0x00, +}; + +/* POOL32F_0 (fmt) instruction pool */ +enum { + NM_RINT_S = 0x04, + NM_RINT_D = 0x44, + NM_ADD_S = 0x06, + NM_SELEQZ_S = 0x07, + NM_SELEQZ_D = 0x47, + NM_CLASS_S = 0x0c, + NM_CLASS_D = 0x4c, + NM_SUB_S = 0x0e, + NM_SELNEZ_S = 0x0f, + NM_SELNEZ_D = 0x4f, + NM_MUL_S = 0x16, + NM_SEL_S = 0x17, + NM_SEL_D = 0x57, + NM_DIV_S = 0x1e, + NM_ADD_D = 0x26, + NM_SUB_D = 0x2e, + NM_MUL_D = 0x36, + NM_MADDF_S = 0x37, + NM_MADDF_D = 0x77, + NM_DIV_D = 0x3e, + NM_MSUBF_S = 0x3f, + NM_MSUBF_D = 0x7f, +}; + +/* POOL32F_3 instruction pool */ +enum { + NM_MIN_FMT = 0x00, + NM_MAX_FMT = 0x01, + NM_MINA_FMT = 0x04, + NM_MAXA_FMT = 0x05, + NM_POOL32FXF = 0x07, +}; + +/* POOL32F_5 instruction pool */ +enum { + NM_CMP_CONDN_S = 0x00, + NM_CMP_CONDN_D = 0x02, +}; + +/* P.GP.LH instruction pool */ +enum { + NM_LHGP = 0x00, + NM_LHUGP = 0x01, +}; + +/* P.GP.SH instruction pool */ +enum { + NM_SHGP = 0x00, +}; + +/* P.GP.CP1 instruction pool */ +enum { + NM_LWC1GP = 0x00, + NM_SWC1GP = 0x01, + NM_LDC1GP = 0x02, + NM_SDC1GP = 0x03, +}; + +/* P.LS.S0 instruction pool */ +enum { + NM_LBS9 = 0x00, + NM_LHS9 = 0x04, + NM_LWS9 = 0x08, + NM_LDS9 = 0x0c, + + NM_SBS9 = 0x01, + NM_SHS9 = 0x05, + NM_SWS9 = 0x09, + NM_SDS9 = 0x0d, + + NM_LBUS9 = 0x02, + NM_LHUS9 = 0x06, + NM_LWC1S9 = 0x0a, + NM_LDC1S9 = 0x0e, + + NM_P_PREFS9 = 0x03, + NM_LWUS9 = 0x07, + NM_SWC1S9 = 0x0b, + NM_SDC1S9 = 0x0f, +}; + +/* P.LS.S1 instruction pool */ +enum { + NM_ASET_ACLR = 0x02, + NM_UALH = 0x04, + NM_UASH = 0x05, + NM_CACHE = 0x07, + NM_P_LL = 0x0a, + NM_P_SC = 0x0b, +}; + +/* P.LS.E0 instruction pool */ +enum { + NM_LBE = 0x00, + NM_SBE = 0x01, + NM_LBUE = 0x02, + NM_P_PREFE = 0x03, + NM_LHE = 0x04, + NM_SHE = 0x05, + NM_LHUE = 0x06, + NM_CACHEE = 0x07, + NM_LWE = 0x08, + NM_SWE = 0x09, + NM_P_LLE = 0x0a, + NM_P_SCE = 0x0b, +}; + +/* P.PREFE instruction pool */ +enum { + NM_SYNCIE = 0x00, + NM_PREFE = 0x01, +}; + +/* P.LLE instruction pool */ +enum { + NM_LLE = 0x00, + NM_LLWPE = 0x01, +}; + +/* P.SCE instruction pool */ +enum { + NM_SCE = 0x00, + NM_SCWPE = 0x01, +}; + +/* P.LS.WM instruction pool */ +enum { + NM_LWM = 0x00, + NM_SWM = 0x01, +}; + +/* P.LS.UAWM instruction pool */ +enum { + NM_UALWM = 0x00, + NM_UASWM = 0x01, +}; + +/* P.BR3A instruction pool */ +enum { + NM_BC1EQZC = 0x00, + NM_BC1NEZC = 0x01, + NM_BC2EQZC = 0x02, + NM_BC2NEZC = 0x03, + NM_BPOSGE32C = 0x04, +}; + +/* P16.RI instruction pool */ +enum { + NM_P16_SYSCALL = 0x01, + NM_BREAK16 = 0x02, + NM_SDBBP16 = 0x03, +}; + +/* POOL16C_0 instruction pool */ +enum { + NM_POOL16C_00 = 0x00, +}; + +/* P16.JRC instruction pool */ +enum { + NM_JRC = 0x00, + NM_JALRC16 = 0x01, +}; + +/* P.SYSCALL instruction pool */ +enum { + NM_SYSCALL = 0x00, + NM_HYPCALL = 0x01, +}; + +/* P.TRAP instruction pool */ +enum { + NM_TEQ = 0x00, + NM_TNE = 0x01, +}; + +/* P.CMOVE instruction pool */ +enum { + NM_MOVZ = 0x00, + NM_MOVN = 0x01, +}; + +/* POOL32Axf instruction pool */ +enum { + NM_POOL32AXF_1 = 0x01, + NM_POOL32AXF_2 = 0x02, + NM_POOL32AXF_4 = 0x04, + NM_POOL32AXF_5 = 0x05, + NM_POOL32AXF_7 = 0x07, +}; + +/* POOL32Axf_1 instruction pool */ +enum { + NM_POOL32AXF_1_0 = 0x00, + NM_POOL32AXF_1_1 = 0x01, + NM_POOL32AXF_1_3 = 0x03, + NM_POOL32AXF_1_4 = 0x04, + NM_POOL32AXF_1_5 = 0x05, + NM_POOL32AXF_1_7 = 0x07, +}; + +/* POOL32Axf_2 instruction pool */ +enum { + NM_POOL32AXF_2_0_7 = 0x00, + NM_POOL32AXF_2_8_15 = 0x01, + NM_POOL32AXF_2_16_23 = 0x02, + NM_POOL32AXF_2_24_31 = 0x03, +}; + +/* POOL32Axf_7 instruction pool */ +enum { + NM_SHRA_R_QB = 0x0, + NM_SHRL_PH = 0x1, + NM_REPL_QB = 0x2, +}; + +/* POOL32Axf_1_0 instruction pool */ +enum { + NM_MFHI = 0x0, + NM_MFLO = 0x1, + NM_MTHI = 0x2, + NM_MTLO = 0x3, +}; + +/* POOL32Axf_1_1 instruction pool */ +enum { + NM_MTHLIP = 0x0, + NM_SHILOV = 0x1, +}; + +/* POOL32Axf_1_3 instruction pool */ +enum { + NM_RDDSP = 0x0, + NM_WRDSP = 0x1, + NM_EXTP = 0x2, + NM_EXTPDP = 0x3, +}; + +/* POOL32Axf_1_4 instruction pool */ +enum { + NM_SHLL_QB = 0x0, + NM_SHRL_QB = 0x1, +}; + +/* POOL32Axf_1_5 instruction pool */ +enum { + NM_MAQ_S_W_PHR = 0x0, + NM_MAQ_S_W_PHL = 0x1, + NM_MAQ_SA_W_PHR = 0x2, + NM_MAQ_SA_W_PHL = 0x3, +}; + +/* POOL32Axf_1_7 instruction pool */ +enum { + NM_EXTR_W = 0x0, + NM_EXTR_R_W = 0x1, + NM_EXTR_RS_W = 0x2, + NM_EXTR_S_H = 0x3, +}; + +/* POOL32Axf_2_0_7 instruction pool */ +enum { + NM_DPA_W_PH = 0x0, + NM_DPAQ_S_W_PH = 0x1, + NM_DPS_W_PH = 0x2, + NM_DPSQ_S_W_PH = 0x3, + NM_BALIGN = 0x4, + NM_MADD = 0x5, + NM_MULT = 0x6, + NM_EXTRV_W = 0x7, +}; + +/* POOL32Axf_2_8_15 instruction pool */ +enum { + NM_DPAX_W_PH = 0x0, + NM_DPAQ_SA_L_W = 0x1, + NM_DPSX_W_PH = 0x2, + NM_DPSQ_SA_L_W = 0x3, + NM_MADDU = 0x5, + NM_MULTU = 0x6, + NM_EXTRV_R_W = 0x7, +}; + +/* POOL32Axf_2_16_23 instruction pool */ +enum { + NM_DPAU_H_QBL = 0x0, + NM_DPAQX_S_W_PH = 0x1, + NM_DPSU_H_QBL = 0x2, + NM_DPSQX_S_W_PH = 0x3, + NM_EXTPV = 0x4, + NM_MSUB = 0x5, + NM_MULSA_W_PH = 0x6, + NM_EXTRV_RS_W = 0x7, +}; + +/* POOL32Axf_2_24_31 instruction pool */ +enum { + NM_DPAU_H_QBR = 0x0, + NM_DPAQX_SA_W_PH = 0x1, + NM_DPSU_H_QBR = 0x2, + NM_DPSQX_SA_W_PH = 0x3, + NM_EXTPDPV = 0x4, + NM_MSUBU = 0x5, + NM_MULSAQ_S_W_PH = 0x6, + NM_EXTRV_S_H = 0x7, +}; + +/* POOL32Axf_{4, 5} instruction pool */ +enum { + NM_CLO = 0x25, + NM_CLZ = 0x2d, + + NM_TLBP = 0x01, + NM_TLBR = 0x09, + NM_TLBWI = 0x11, + NM_TLBWR = 0x19, + NM_TLBINV = 0x03, + NM_TLBINVF = 0x0b, + NM_DI = 0x23, + NM_EI = 0x2b, + NM_RDPGPR = 0x70, + NM_WRPGPR = 0x78, + NM_WAIT = 0x61, + NM_DERET = 0x71, + NM_ERETX = 0x79, + + /* nanoMIPS DSP instructions */ + NM_ABSQ_S_QB = 0x00, + NM_ABSQ_S_PH = 0x08, + NM_ABSQ_S_W = 0x10, + NM_PRECEQ_W_PHL = 0x28, + NM_PRECEQ_W_PHR = 0x30, + NM_PRECEQU_PH_QBL = 0x38, + NM_PRECEQU_PH_QBR = 0x48, + NM_PRECEU_PH_QBL = 0x58, + NM_PRECEU_PH_QBR = 0x68, + NM_PRECEQU_PH_QBLA = 0x39, + NM_PRECEQU_PH_QBRA = 0x49, + NM_PRECEU_PH_QBLA = 0x59, + NM_PRECEU_PH_QBRA = 0x69, + NM_REPLV_PH = 0x01, + NM_REPLV_QB = 0x09, + NM_BITREV = 0x18, + NM_INSV = 0x20, + NM_RADDU_W_QB = 0x78, + + NM_BITSWAP = 0x05, + NM_WSBH = 0x3d, +}; + +/* PP.SR instruction pool */ +enum { + NM_SAVE = 0x00, + NM_RESTORE = 0x02, + NM_RESTORE_JRC = 0x03, +}; + +/* P.SR.F instruction pool */ +enum { + NM_SAVEF = 0x00, + NM_RESTOREF = 0x01, +}; + +/* P16.SYSCALL instruction pool */ +enum { + NM_SYSCALL16 = 0x00, + NM_HYPCALL16 = 0x01, +}; + +/* POOL16C_00 instruction pool */ +enum { + NM_NOT16 = 0x00, + NM_XOR16 = 0x01, + NM_AND16 = 0x02, + NM_OR16 = 0x03, +}; + +/* PP.LSX and PP.LSXS instruction pool */ +enum { + NM_LBX = 0x00, + NM_LHX = 0x04, + NM_LWX = 0x08, + NM_LDX = 0x0c, + + NM_SBX = 0x01, + NM_SHX = 0x05, + NM_SWX = 0x09, + NM_SDX = 0x0d, + + NM_LBUX = 0x02, + NM_LHUX = 0x06, + NM_LWC1X = 0x0a, + NM_LDC1X = 0x0e, + + NM_LWUX = 0x07, + NM_SWC1X = 0x0b, + NM_SDC1X = 0x0f, + + NM_LHXS = 0x04, + NM_LWXS = 0x08, + NM_LDXS = 0x0c, + + NM_SHXS = 0x05, + NM_SWXS = 0x09, + NM_SDXS = 0x0d, + + NM_LHUXS = 0x06, + NM_LWC1XS = 0x0a, + NM_LDC1XS = 0x0e, + + NM_LWUXS = 0x07, + NM_SWC1XS = 0x0b, + NM_SDC1XS = 0x0f, +}; + +/* ERETx instruction pool */ +enum { + NM_ERET = 0x00, + NM_ERETNC = 0x01, +}; + +/* POOL32FxF_{0, 1} insturction pool */ +enum { + NM_CFC1 = 0x40, + NM_CTC1 = 0x60, + NM_MFC1 = 0x80, + NM_MTC1 = 0xa0, + NM_MFHC1 = 0xc0, + NM_MTHC1 = 0xe0, + + NM_CVT_S_PL = 0x84, + NM_CVT_S_PU = 0xa4, + + NM_CVT_L_S = 0x004, + NM_CVT_L_D = 0x104, + NM_CVT_W_S = 0x024, + NM_CVT_W_D = 0x124, + + NM_RSQRT_S = 0x008, + NM_RSQRT_D = 0x108, + + NM_SQRT_S = 0x028, + NM_SQRT_D = 0x128, + + NM_RECIP_S = 0x048, + NM_RECIP_D = 0x148, + + NM_FLOOR_L_S = 0x00c, + NM_FLOOR_L_D = 0x10c, + + NM_FLOOR_W_S = 0x02c, + NM_FLOOR_W_D = 0x12c, + + NM_CEIL_L_S = 0x04c, + NM_CEIL_L_D = 0x14c, + NM_CEIL_W_S = 0x06c, + NM_CEIL_W_D = 0x16c, + NM_TRUNC_L_S = 0x08c, + NM_TRUNC_L_D = 0x18c, + NM_TRUNC_W_S = 0x0ac, + NM_TRUNC_W_D = 0x1ac, + NM_ROUND_L_S = 0x0cc, + NM_ROUND_L_D = 0x1cc, + NM_ROUND_W_S = 0x0ec, + NM_ROUND_W_D = 0x1ec, + + NM_MOV_S = 0x01, + NM_MOV_D = 0x81, + NM_ABS_S = 0x0d, + NM_ABS_D = 0x8d, + NM_NEG_S = 0x2d, + NM_NEG_D = 0xad, + NM_CVT_D_S = 0x04d, + NM_CVT_D_W = 0x0cd, + NM_CVT_D_L = 0x14d, + NM_CVT_S_D = 0x06d, + NM_CVT_S_W = 0x0ed, + NM_CVT_S_L = 0x16d, +}; + +/* P.LL instruction pool */ +enum { + NM_LL = 0x00, + NM_LLWP = 0x01, +}; + +/* P.SC instruction pool */ +enum { + NM_SC = 0x00, + NM_SCWP = 0x01, +}; + +/* P.DVP instruction pool */ +enum { + NM_DVP = 0x00, + NM_EVP = 0x01, +}; + + +/* + * + * nanoMIPS decoding engine + * + */ + + +/* extraction utilities */ + +#define NANOMIPS_EXTRACT_RT3(op) ((op >> 7) & 0x7) +#define NANOMIPS_EXTRACT_RS3(op) ((op >> 4) & 0x7) +#define NANOMIPS_EXTRACT_RD3(op) ((op >> 1) & 0x7) +#define NANOMIPS_EXTRACT_RD5(op) ((op >> 5) & 0x1f) +#define NANOMIPS_EXTRACT_RS5(op) (op & 0x1f) + +/* Implement nanoMIPS pseudocode decode_gpr(encoded_gpr, 'gpr3'). */ +static inline int decode_gpr_gpr3(int r) +{ + static const int map[] = { 16, 17, 18, 19, 4, 5, 6, 7 }; + + return map[r & 0x7]; +} + +/* Implement nanoMIPS pseudocode decode_gpr(encoded_gpr, 'gpr3.src.store'). */ +static inline int decode_gpr_gpr3_src_store(int r) +{ + static const int map[] = { 0, 17, 18, 19, 4, 5, 6, 7 }; + + return map[r & 0x7]; +} + +/* Implement nanoMIPS pseudocode decode_gpr(encoded_gpr, 'gpr4'). */ +static inline int decode_gpr_gpr4(int r) +{ + static const int map[] = { 8, 9, 10, 11, 4, 5, 6, 7, + 16, 17, 18, 19, 20, 21, 22, 23 }; + + return map[r & 0xf]; +} + +/* Implement nanoMIPS pseudocode decode_gpr(encoded_gpr, 'gpr4.zero'). */ +static inline int decode_gpr_gpr4_zero(int r) +{ + static const int map[] = { 8, 9, 10, 0, 4, 5, 6, 7, + 16, 17, 18, 19, 20, 21, 22, 23 }; + + return map[r & 0xf]; +} + +static void gen_ext(DisasContext *ctx, int wordsz, int rd, int rs, int rt, + int shift) +{ + gen_align_bits(ctx, wordsz, rd, rs, rt, wordsz - shift); +} + +static void gen_llwp(DisasContext *ctx, uint32_t base, int16_t offset, + uint32_t reg1, uint32_t reg2) +{ + TCGv taddr = tcg_temp_new(); + TCGv_i64 tval = tcg_temp_new_i64(); + TCGv tmp1 = tcg_temp_new(); + TCGv tmp2 = tcg_temp_new(); + + gen_base_offset_addr(ctx, taddr, base, offset); + tcg_gen_qemu_ld64(tval, taddr, ctx->mem_idx); +#ifdef TARGET_WORDS_BIGENDIAN + tcg_gen_extr_i64_tl(tmp2, tmp1, tval); +#else + tcg_gen_extr_i64_tl(tmp1, tmp2, tval); +#endif + gen_store_gpr(tmp1, reg1); + tcg_temp_free(tmp1); + gen_store_gpr(tmp2, reg2); + tcg_temp_free(tmp2); + tcg_gen_st_i64(tval, cpu_env, offsetof(CPUMIPSState, llval_wp)); + tcg_temp_free_i64(tval); + tcg_gen_st_tl(taddr, cpu_env, offsetof(CPUMIPSState, lladdr)); + tcg_temp_free(taddr); +} + +static void gen_scwp(DisasContext *ctx, uint32_t base, int16_t offset, + uint32_t reg1, uint32_t reg2, bool eva) +{ + TCGv taddr = tcg_temp_local_new(); + TCGv lladdr = tcg_temp_local_new(); + TCGv_i64 tval = tcg_temp_new_i64(); + TCGv_i64 llval = tcg_temp_new_i64(); + TCGv_i64 val = tcg_temp_new_i64(); + TCGv tmp1 = tcg_temp_new(); + TCGv tmp2 = tcg_temp_new(); + TCGLabel *lab_fail = gen_new_label(); + TCGLabel *lab_done = gen_new_label(); + + gen_base_offset_addr(ctx, taddr, base, offset); + + tcg_gen_ld_tl(lladdr, cpu_env, offsetof(CPUMIPSState, lladdr)); + tcg_gen_brcond_tl(TCG_COND_NE, taddr, lladdr, lab_fail); + + gen_load_gpr(tmp1, reg1); + gen_load_gpr(tmp2, reg2); + +#ifdef TARGET_WORDS_BIGENDIAN + tcg_gen_concat_tl_i64(tval, tmp2, tmp1); +#else + tcg_gen_concat_tl_i64(tval, tmp1, tmp2); +#endif + + tcg_gen_ld_i64(llval, cpu_env, offsetof(CPUMIPSState, llval_wp)); + tcg_gen_atomic_cmpxchg_i64(val, taddr, llval, tval, + eva ? MIPS_HFLAG_UM : ctx->mem_idx, MO_64); + if (reg1 != 0) { + tcg_gen_movi_tl(cpu_gpr[reg1], 1); + } + tcg_gen_brcond_i64(TCG_COND_EQ, val, llval, lab_done); + + gen_set_label(lab_fail); + + if (reg1 != 0) { + tcg_gen_movi_tl(cpu_gpr[reg1], 0); + } + gen_set_label(lab_done); + tcg_gen_movi_tl(lladdr, -1); + tcg_gen_st_tl(lladdr, cpu_env, offsetof(CPUMIPSState, lladdr)); +} + +static void gen_adjust_sp(DisasContext *ctx, int u) +{ + gen_op_addr_addi(ctx, cpu_gpr[29], cpu_gpr[29], u); +} + +static void gen_save(DisasContext *ctx, uint8_t rt, uint8_t count, + uint8_t gp, uint16_t u) +{ + int counter = 0; + TCGv va = tcg_temp_new(); + TCGv t0 = tcg_temp_new(); + + while (counter != count) { + bool use_gp = gp && (counter == count - 1); + int this_rt = use_gp ? 28 : (rt & 0x10) | ((rt + counter) & 0x1f); + int this_offset = -((counter + 1) << 2); + gen_base_offset_addr(ctx, va, 29, this_offset); + gen_load_gpr(t0, this_rt); + tcg_gen_qemu_st_tl(t0, va, ctx->mem_idx, + (MO_TEUL | ctx->default_tcg_memop_mask)); + counter++; + } + + /* adjust stack pointer */ + gen_adjust_sp(ctx, -u); + + tcg_temp_free(t0); + tcg_temp_free(va); +} + +static void gen_restore(DisasContext *ctx, uint8_t rt, uint8_t count, + uint8_t gp, uint16_t u) +{ + int counter = 0; + TCGv va = tcg_temp_new(); + TCGv t0 = tcg_temp_new(); + + while (counter != count) { + bool use_gp = gp && (counter == count - 1); + int this_rt = use_gp ? 28 : (rt & 0x10) | ((rt + counter) & 0x1f); + int this_offset = u - ((counter + 1) << 2); + gen_base_offset_addr(ctx, va, 29, this_offset); + tcg_gen_qemu_ld_tl(t0, va, ctx->mem_idx, MO_TESL | + ctx->default_tcg_memop_mask); + tcg_gen_ext32s_tl(t0, t0); + gen_store_gpr(t0, this_rt); + counter++; + } + + /* adjust stack pointer */ + gen_adjust_sp(ctx, u); + + tcg_temp_free(t0); + tcg_temp_free(va); +} + +static void gen_compute_branch_nm(DisasContext *ctx, uint32_t opc, + int insn_bytes, + int rs, int rt, int32_t offset) +{ + target_ulong btgt = -1; + int bcond_compute = 0; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + /* Load needed operands */ + switch (opc) { + case OPC_BEQ: + case OPC_BNE: + /* Compare two registers */ + if (rs != rt) { + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + bcond_compute = 1; + } + btgt = ctx->base.pc_next + insn_bytes + offset; + break; + case OPC_BGEZAL: + /* Compare to zero */ + if (rs != 0) { + gen_load_gpr(t0, rs); + bcond_compute = 1; + } + btgt = ctx->base.pc_next + insn_bytes + offset; + break; + case OPC_BPOSGE32: + tcg_gen_andi_tl(t0, cpu_dspctrl, 0x3F); + bcond_compute = 1; + btgt = ctx->base.pc_next + insn_bytes + offset; + break; + case OPC_JR: + case OPC_JALR: + /* Jump to register */ + if (offset != 0 && offset != 16) { + /* + * Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the + * others are reserved. + */ + MIPS_INVAL("jump hint"); + gen_reserved_instruction(ctx); + goto out; + } + gen_load_gpr(btarget, rs); + break; + default: + MIPS_INVAL("branch/jump"); + gen_reserved_instruction(ctx); + goto out; + } + if (bcond_compute == 0) { + /* No condition to be computed */ + switch (opc) { + case OPC_BEQ: /* rx == rx */ + /* Always take */ + ctx->hflags |= MIPS_HFLAG_B; + break; + case OPC_BGEZAL: /* 0 >= 0 */ + /* Always take and link */ + tcg_gen_movi_tl(cpu_gpr[31], + ctx->base.pc_next + insn_bytes); + ctx->hflags |= MIPS_HFLAG_B; + break; + case OPC_BNE: /* rx != rx */ + tcg_gen_movi_tl(cpu_gpr[31], ctx->base.pc_next + 8); + /* Skip the instruction in the delay slot */ + ctx->base.pc_next += 4; + goto out; + case OPC_JR: + ctx->hflags |= MIPS_HFLAG_BR; + break; + case OPC_JALR: + if (rt > 0) { + tcg_gen_movi_tl(cpu_gpr[rt], + ctx->base.pc_next + insn_bytes); + } + ctx->hflags |= MIPS_HFLAG_BR; + break; + default: + MIPS_INVAL("branch/jump"); + gen_reserved_instruction(ctx); + goto out; + } + } else { + switch (opc) { + case OPC_BEQ: + tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); + goto not_likely; + case OPC_BNE: + tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); + goto not_likely; + case OPC_BGEZAL: + tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); + tcg_gen_movi_tl(cpu_gpr[31], + ctx->base.pc_next + insn_bytes); + goto not_likely; + case OPC_BPOSGE32: + tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 32); + not_likely: + ctx->hflags |= MIPS_HFLAG_BC; + break; + default: + MIPS_INVAL("conditional branch/jump"); + gen_reserved_instruction(ctx); + goto out; + } + } + + ctx->btarget = btgt; + + out: + if (insn_bytes == 2) { + ctx->hflags |= MIPS_HFLAG_B16; + } + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_pool16c_nanomips_insn(DisasContext *ctx) +{ + int rt = decode_gpr_gpr3(NANOMIPS_EXTRACT_RT3(ctx->opcode)); + int rs = decode_gpr_gpr3(NANOMIPS_EXTRACT_RS3(ctx->opcode)); + + switch (extract32(ctx->opcode, 2, 2)) { + case NM_NOT16: + gen_logic(ctx, OPC_NOR, rt, rs, 0); + break; + case NM_AND16: + gen_logic(ctx, OPC_AND, rt, rt, rs); + break; + case NM_XOR16: + gen_logic(ctx, OPC_XOR, rt, rt, rs); + break; + case NM_OR16: + gen_logic(ctx, OPC_OR, rt, rt, rs); + break; + } +} + +static void gen_pool32a0_nanomips_insn(CPUMIPSState *env, DisasContext *ctx) +{ + int rt = extract32(ctx->opcode, 21, 5); + int rs = extract32(ctx->opcode, 16, 5); + int rd = extract32(ctx->opcode, 11, 5); + + switch (extract32(ctx->opcode, 3, 7)) { + case NM_P_TRAP: + switch (extract32(ctx->opcode, 10, 1)) { + case NM_TEQ: + check_nms(ctx); + gen_trap(ctx, OPC_TEQ, rs, rt, -1); + break; + case NM_TNE: + check_nms(ctx); + gen_trap(ctx, OPC_TNE, rs, rt, -1); + break; + } + break; + case NM_RDHWR: + check_nms(ctx); + gen_rdhwr(ctx, rt, rs, extract32(ctx->opcode, 11, 3)); + break; + case NM_SEB: + check_nms(ctx); + gen_bshfl(ctx, OPC_SEB, rs, rt); + break; + case NM_SEH: + gen_bshfl(ctx, OPC_SEH, rs, rt); + break; + case NM_SLLV: + gen_shift(ctx, OPC_SLLV, rd, rt, rs); + break; + case NM_SRLV: + gen_shift(ctx, OPC_SRLV, rd, rt, rs); + break; + case NM_SRAV: + gen_shift(ctx, OPC_SRAV, rd, rt, rs); + break; + case NM_ROTRV: + gen_shift(ctx, OPC_ROTRV, rd, rt, rs); + break; + case NM_ADD: + gen_arith(ctx, OPC_ADD, rd, rs, rt); + break; + case NM_ADDU: + gen_arith(ctx, OPC_ADDU, rd, rs, rt); + break; + case NM_SUB: + check_nms(ctx); + gen_arith(ctx, OPC_SUB, rd, rs, rt); + break; + case NM_SUBU: + gen_arith(ctx, OPC_SUBU, rd, rs, rt); + break; + case NM_P_CMOVE: + switch (extract32(ctx->opcode, 10, 1)) { + case NM_MOVZ: + gen_cond_move(ctx, OPC_MOVZ, rd, rs, rt); + break; + case NM_MOVN: + gen_cond_move(ctx, OPC_MOVN, rd, rs, rt); + break; + } + break; + case NM_AND: + gen_logic(ctx, OPC_AND, rd, rs, rt); + break; + case NM_OR: + gen_logic(ctx, OPC_OR, rd, rs, rt); + break; + case NM_NOR: + gen_logic(ctx, OPC_NOR, rd, rs, rt); + break; + case NM_XOR: + gen_logic(ctx, OPC_XOR, rd, rs, rt); + break; + case NM_SLT: + gen_slt(ctx, OPC_SLT, rd, rs, rt); + break; + case NM_P_SLTU: + if (rd == 0) { + /* P_DVP */ +#ifndef CONFIG_USER_ONLY + TCGv t0 = tcg_temp_new(); + switch (extract32(ctx->opcode, 10, 1)) { + case NM_DVP: + if (ctx->vp) { + check_cp0_enabled(ctx); + gen_helper_dvp(t0, cpu_env); + gen_store_gpr(t0, rt); + } + break; + case NM_EVP: + if (ctx->vp) { + check_cp0_enabled(ctx); + gen_helper_evp(t0, cpu_env); + gen_store_gpr(t0, rt); + } + break; + } + tcg_temp_free(t0); +#endif + } else { + gen_slt(ctx, OPC_SLTU, rd, rs, rt); + } + break; + case NM_SOV: + { + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + + gen_load_gpr(t1, rs); + gen_load_gpr(t2, rt); + tcg_gen_add_tl(t0, t1, t2); + tcg_gen_ext32s_tl(t0, t0); + tcg_gen_xor_tl(t1, t1, t2); + tcg_gen_xor_tl(t2, t0, t2); + tcg_gen_andc_tl(t1, t2, t1); + + /* operands of same sign, result different sign */ + tcg_gen_setcondi_tl(TCG_COND_LT, t0, t1, 0); + gen_store_gpr(t0, rd); + + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); + } + break; + case NM_MUL: + gen_r6_muldiv(ctx, R6_OPC_MUL, rd, rs, rt); + break; + case NM_MUH: + gen_r6_muldiv(ctx, R6_OPC_MUH, rd, rs, rt); + break; + case NM_MULU: + gen_r6_muldiv(ctx, R6_OPC_MULU, rd, rs, rt); + break; + case NM_MUHU: + gen_r6_muldiv(ctx, R6_OPC_MUHU, rd, rs, rt); + break; + case NM_DIV: + gen_r6_muldiv(ctx, R6_OPC_DIV, rd, rs, rt); + break; + case NM_MOD: + gen_r6_muldiv(ctx, R6_OPC_MOD, rd, rs, rt); + break; + case NM_DIVU: + gen_r6_muldiv(ctx, R6_OPC_DIVU, rd, rs, rt); + break; + case NM_MODU: + gen_r6_muldiv(ctx, R6_OPC_MODU, rd, rs, rt); + break; +#ifndef CONFIG_USER_ONLY + case NM_MFC0: + check_cp0_enabled(ctx); + if (rt == 0) { + /* Treat as NOP. */ + break; + } + gen_mfc0(ctx, cpu_gpr[rt], rs, extract32(ctx->opcode, 11, 3)); + break; + case NM_MTC0: + check_cp0_enabled(ctx); + { + TCGv t0 = tcg_temp_new(); + + gen_load_gpr(t0, rt); + gen_mtc0(ctx, t0, rs, extract32(ctx->opcode, 11, 3)); + tcg_temp_free(t0); + } + break; + case NM_D_E_MT_VPE: + { + uint8_t sc = extract32(ctx->opcode, 10, 1); + TCGv t0 = tcg_temp_new(); + + switch (sc) { + case 0: + if (rs == 1) { + /* DMT */ + check_cp0_mt(ctx); + gen_helper_dmt(t0); + gen_store_gpr(t0, rt); + } else if (rs == 0) { + /* DVPE */ + check_cp0_mt(ctx); + gen_helper_dvpe(t0, cpu_env); + gen_store_gpr(t0, rt); + } else { + gen_reserved_instruction(ctx); + } + break; + case 1: + if (rs == 1) { + /* EMT */ + check_cp0_mt(ctx); + gen_helper_emt(t0); + gen_store_gpr(t0, rt); + } else if (rs == 0) { + /* EVPE */ + check_cp0_mt(ctx); + gen_helper_evpe(t0, cpu_env); + gen_store_gpr(t0, rt); + } else { + gen_reserved_instruction(ctx); + } + break; + } + + tcg_temp_free(t0); + } + break; + case NM_FORK: + check_mt(ctx); + { + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + gen_load_gpr(t0, rt); + gen_load_gpr(t1, rs); + gen_helper_fork(t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); + } + break; + case NM_MFTR: + case NM_MFHTR: + check_cp0_enabled(ctx); + if (rd == 0) { + /* Treat as NOP. */ + return; + } + gen_mftr(env, ctx, rs, rt, extract32(ctx->opcode, 10, 1), + extract32(ctx->opcode, 11, 5), extract32(ctx->opcode, 3, 1)); + break; + case NM_MTTR: + case NM_MTHTR: + check_cp0_enabled(ctx); + gen_mttr(env, ctx, rs, rt, extract32(ctx->opcode, 10, 1), + extract32(ctx->opcode, 11, 5), extract32(ctx->opcode, 3, 1)); + break; + case NM_YIELD: + check_mt(ctx); + { + TCGv t0 = tcg_temp_new(); + + gen_load_gpr(t0, rs); + gen_helper_yield(t0, cpu_env, t0); + gen_store_gpr(t0, rt); + tcg_temp_free(t0); + } + break; +#endif + default: + gen_reserved_instruction(ctx); + break; + } +} + +/* dsp */ +static void gen_pool32axf_1_5_nanomips_insn(DisasContext *ctx, uint32_t opc, + int ret, int v1, int v2) +{ + TCGv_i32 t0; + TCGv v0_t; + TCGv v1_t; + + t0 = tcg_temp_new_i32(); + + v0_t = tcg_temp_new(); + v1_t = tcg_temp_new(); + + tcg_gen_movi_i32(t0, v2 >> 3); + + gen_load_gpr(v0_t, ret); + gen_load_gpr(v1_t, v1); + + switch (opc) { + case NM_MAQ_S_W_PHR: + check_dsp(ctx); + gen_helper_maq_s_w_phr(t0, v1_t, v0_t, cpu_env); + break; + case NM_MAQ_S_W_PHL: + check_dsp(ctx); + gen_helper_maq_s_w_phl(t0, v1_t, v0_t, cpu_env); + break; + case NM_MAQ_SA_W_PHR: + check_dsp(ctx); + gen_helper_maq_sa_w_phr(t0, v1_t, v0_t, cpu_env); + break; + case NM_MAQ_SA_W_PHL: + check_dsp(ctx); + gen_helper_maq_sa_w_phl(t0, v1_t, v0_t, cpu_env); + break; + default: + gen_reserved_instruction(ctx); + break; + } + + tcg_temp_free_i32(t0); + + tcg_temp_free(v0_t); + tcg_temp_free(v1_t); +} + + +static void gen_pool32axf_1_nanomips_insn(DisasContext *ctx, uint32_t opc, + int ret, int v1, int v2) +{ + int16_t imm; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv v0_t = tcg_temp_new(); + + gen_load_gpr(v0_t, v1); + + switch (opc) { + case NM_POOL32AXF_1_0: + check_dsp(ctx); + switch (extract32(ctx->opcode, 12, 2)) { + case NM_MFHI: + gen_HILO(ctx, OPC_MFHI, v2 >> 3, ret); + break; + case NM_MFLO: + gen_HILO(ctx, OPC_MFLO, v2 >> 3, ret); + break; + case NM_MTHI: + gen_HILO(ctx, OPC_MTHI, v2 >> 3, v1); + break; + case NM_MTLO: + gen_HILO(ctx, OPC_MTLO, v2 >> 3, v1); + break; + } + break; + case NM_POOL32AXF_1_1: + check_dsp(ctx); + switch (extract32(ctx->opcode, 12, 2)) { + case NM_MTHLIP: + tcg_gen_movi_tl(t0, v2); + gen_helper_mthlip(t0, v0_t, cpu_env); + break; + case NM_SHILOV: + tcg_gen_movi_tl(t0, v2 >> 3); + gen_helper_shilo(t0, v0_t, cpu_env); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_POOL32AXF_1_3: + check_dsp(ctx); + imm = extract32(ctx->opcode, 14, 7); + switch (extract32(ctx->opcode, 12, 2)) { + case NM_RDDSP: + tcg_gen_movi_tl(t0, imm); + gen_helper_rddsp(t0, t0, cpu_env); + gen_store_gpr(t0, ret); + break; + case NM_WRDSP: + gen_load_gpr(t0, ret); + tcg_gen_movi_tl(t1, imm); + gen_helper_wrdsp(t0, t1, cpu_env); + break; + case NM_EXTP: + tcg_gen_movi_tl(t0, v2 >> 3); + tcg_gen_movi_tl(t1, v1); + gen_helper_extp(t0, t0, t1, cpu_env); + gen_store_gpr(t0, ret); + break; + case NM_EXTPDP: + tcg_gen_movi_tl(t0, v2 >> 3); + tcg_gen_movi_tl(t1, v1); + gen_helper_extpdp(t0, t0, t1, cpu_env); + gen_store_gpr(t0, ret); + break; + } + break; + case NM_POOL32AXF_1_4: + check_dsp(ctx); + tcg_gen_movi_tl(t0, v2 >> 2); + switch (extract32(ctx->opcode, 12, 1)) { + case NM_SHLL_QB: + gen_helper_shll_qb(t0, t0, v0_t, cpu_env); + gen_store_gpr(t0, ret); + break; + case NM_SHRL_QB: + gen_helper_shrl_qb(t0, t0, v0_t); + gen_store_gpr(t0, ret); + break; + } + break; + case NM_POOL32AXF_1_5: + opc = extract32(ctx->opcode, 12, 2); + gen_pool32axf_1_5_nanomips_insn(ctx, opc, ret, v1, v2); + break; + case NM_POOL32AXF_1_7: + check_dsp(ctx); + tcg_gen_movi_tl(t0, v2 >> 3); + tcg_gen_movi_tl(t1, v1); + switch (extract32(ctx->opcode, 12, 2)) { + case NM_EXTR_W: + gen_helper_extr_w(t0, t0, t1, cpu_env); + gen_store_gpr(t0, ret); + break; + case NM_EXTR_R_W: + gen_helper_extr_r_w(t0, t0, t1, cpu_env); + gen_store_gpr(t0, ret); + break; + case NM_EXTR_RS_W: + gen_helper_extr_rs_w(t0, t0, t1, cpu_env); + gen_store_gpr(t0, ret); + break; + case NM_EXTR_S_H: + gen_helper_extr_s_h(t0, t0, t1, cpu_env); + gen_store_gpr(t0, ret); + break; + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(v0_t); +} + +static void gen_pool32axf_2_multiply(DisasContext *ctx, uint32_t opc, + TCGv v0, TCGv v1, int rd) +{ + TCGv_i32 t0; + + t0 = tcg_temp_new_i32(); + + tcg_gen_movi_i32(t0, rd >> 3); + + switch (opc) { + case NM_POOL32AXF_2_0_7: + switch (extract32(ctx->opcode, 9, 3)) { + case NM_DPA_W_PH: + check_dsp_r2(ctx); + gen_helper_dpa_w_ph(t0, v1, v0, cpu_env); + break; + case NM_DPAQ_S_W_PH: + check_dsp(ctx); + gen_helper_dpaq_s_w_ph(t0, v1, v0, cpu_env); + break; + case NM_DPS_W_PH: + check_dsp_r2(ctx); + gen_helper_dps_w_ph(t0, v1, v0, cpu_env); + break; + case NM_DPSQ_S_W_PH: + check_dsp(ctx); + gen_helper_dpsq_s_w_ph(t0, v1, v0, cpu_env); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_POOL32AXF_2_8_15: + switch (extract32(ctx->opcode, 9, 3)) { + case NM_DPAX_W_PH: + check_dsp_r2(ctx); + gen_helper_dpax_w_ph(t0, v0, v1, cpu_env); + break; + case NM_DPAQ_SA_L_W: + check_dsp(ctx); + gen_helper_dpaq_sa_l_w(t0, v0, v1, cpu_env); + break; + case NM_DPSX_W_PH: + check_dsp_r2(ctx); + gen_helper_dpsx_w_ph(t0, v0, v1, cpu_env); + break; + case NM_DPSQ_SA_L_W: + check_dsp(ctx); + gen_helper_dpsq_sa_l_w(t0, v0, v1, cpu_env); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_POOL32AXF_2_16_23: + switch (extract32(ctx->opcode, 9, 3)) { + case NM_DPAU_H_QBL: + check_dsp(ctx); + gen_helper_dpau_h_qbl(t0, v0, v1, cpu_env); + break; + case NM_DPAQX_S_W_PH: + check_dsp_r2(ctx); + gen_helper_dpaqx_s_w_ph(t0, v0, v1, cpu_env); + break; + case NM_DPSU_H_QBL: + check_dsp(ctx); + gen_helper_dpsu_h_qbl(t0, v0, v1, cpu_env); + break; + case NM_DPSQX_S_W_PH: + check_dsp_r2(ctx); + gen_helper_dpsqx_s_w_ph(t0, v0, v1, cpu_env); + break; + case NM_MULSA_W_PH: + check_dsp_r2(ctx); + gen_helper_mulsa_w_ph(t0, v0, v1, cpu_env); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_POOL32AXF_2_24_31: + switch (extract32(ctx->opcode, 9, 3)) { + case NM_DPAU_H_QBR: + check_dsp(ctx); + gen_helper_dpau_h_qbr(t0, v1, v0, cpu_env); + break; + case NM_DPAQX_SA_W_PH: + check_dsp_r2(ctx); + gen_helper_dpaqx_sa_w_ph(t0, v1, v0, cpu_env); + break; + case NM_DPSU_H_QBR: + check_dsp(ctx); + gen_helper_dpsu_h_qbr(t0, v1, v0, cpu_env); + break; + case NM_DPSQX_SA_W_PH: + check_dsp_r2(ctx); + gen_helper_dpsqx_sa_w_ph(t0, v1, v0, cpu_env); + break; + case NM_MULSAQ_S_W_PH: + check_dsp(ctx); + gen_helper_mulsaq_s_w_ph(t0, v1, v0, cpu_env); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + + tcg_temp_free_i32(t0); +} + +static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc, + int rt, int rs, int rd) +{ + int ret = rt; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv v0_t = tcg_temp_new(); + TCGv v1_t = tcg_temp_new(); + + gen_load_gpr(v0_t, rt); + gen_load_gpr(v1_t, rs); + + switch (opc) { + case NM_POOL32AXF_2_0_7: + switch (extract32(ctx->opcode, 9, 3)) { + case NM_DPA_W_PH: + case NM_DPAQ_S_W_PH: + case NM_DPS_W_PH: + case NM_DPSQ_S_W_PH: + gen_pool32axf_2_multiply(ctx, opc, v0_t, v1_t, rd); + break; + case NM_BALIGN: + check_dsp_r2(ctx); + if (rt != 0) { + gen_load_gpr(t0, rs); + rd &= 3; + if (rd != 0 && rd != 2) { + tcg_gen_shli_tl(cpu_gpr[ret], cpu_gpr[ret], 8 * rd); + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_shri_tl(t0, t0, 8 * (4 - rd)); + tcg_gen_or_tl(cpu_gpr[ret], cpu_gpr[ret], t0); + } + tcg_gen_ext32s_tl(cpu_gpr[ret], cpu_gpr[ret]); + } + break; + case NM_MADD: + check_dsp(ctx); + { + int acc = extract32(ctx->opcode, 14, 2); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + gen_load_gpr(t0, rt); + gen_load_gpr(t1, rs); + tcg_gen_ext_tl_i64(t2, t0); + tcg_gen_ext_tl_i64(t3, t1); + tcg_gen_mul_i64(t2, t2, t3); + tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]); + tcg_gen_add_i64(t2, t2, t3); + tcg_temp_free_i64(t3); + gen_move_low32(cpu_LO[acc], t2); + gen_move_high32(cpu_HI[acc], t2); + tcg_temp_free_i64(t2); + } + break; + case NM_MULT: + check_dsp(ctx); + { + int acc = extract32(ctx->opcode, 14, 2); + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_muls2_i32(t2, t3, t2, t3); + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } + break; + case NM_EXTRV_W: + check_dsp(ctx); + gen_load_gpr(v1_t, rs); + tcg_gen_movi_tl(t0, rd >> 3); + gen_helper_extr_w(t0, t0, v1_t, cpu_env); + gen_store_gpr(t0, ret); + break; + } + break; + case NM_POOL32AXF_2_8_15: + switch (extract32(ctx->opcode, 9, 3)) { + case NM_DPAX_W_PH: + case NM_DPAQ_SA_L_W: + case NM_DPSX_W_PH: + case NM_DPSQ_SA_L_W: + gen_pool32axf_2_multiply(ctx, opc, v0_t, v1_t, rd); + break; + case NM_MADDU: + check_dsp(ctx); + { + int acc = extract32(ctx->opcode, 14, 2); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_extu_tl_i64(t2, t0); + tcg_gen_extu_tl_i64(t3, t1); + tcg_gen_mul_i64(t2, t2, t3); + tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]); + tcg_gen_add_i64(t2, t2, t3); + tcg_temp_free_i64(t3); + gen_move_low32(cpu_LO[acc], t2); + gen_move_high32(cpu_HI[acc], t2); + tcg_temp_free_i64(t2); + } + break; + case NM_MULTU: + check_dsp(ctx); + { + int acc = extract32(ctx->opcode, 14, 2); + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_mulu2_i32(t2, t3, t2, t3); + tcg_gen_ext_i32_tl(cpu_LO[acc], t2); + tcg_gen_ext_i32_tl(cpu_HI[acc], t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } + break; + case NM_EXTRV_R_W: + check_dsp(ctx); + tcg_gen_movi_tl(t0, rd >> 3); + gen_helper_extr_r_w(t0, t0, v1_t, cpu_env); + gen_store_gpr(t0, ret); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_POOL32AXF_2_16_23: + switch (extract32(ctx->opcode, 9, 3)) { + case NM_DPAU_H_QBL: + case NM_DPAQX_S_W_PH: + case NM_DPSU_H_QBL: + case NM_DPSQX_S_W_PH: + case NM_MULSA_W_PH: + gen_pool32axf_2_multiply(ctx, opc, v0_t, v1_t, rd); + break; + case NM_EXTPV: + check_dsp(ctx); + tcg_gen_movi_tl(t0, rd >> 3); + gen_helper_extp(t0, t0, v1_t, cpu_env); + gen_store_gpr(t0, ret); + break; + case NM_MSUB: + check_dsp(ctx); + { + int acc = extract32(ctx->opcode, 14, 2); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_ext_tl_i64(t2, t0); + tcg_gen_ext_tl_i64(t3, t1); + tcg_gen_mul_i64(t2, t2, t3); + tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]); + tcg_gen_sub_i64(t2, t3, t2); + tcg_temp_free_i64(t3); + gen_move_low32(cpu_LO[acc], t2); + gen_move_high32(cpu_HI[acc], t2); + tcg_temp_free_i64(t2); + } + break; + case NM_EXTRV_RS_W: + check_dsp(ctx); + tcg_gen_movi_tl(t0, rd >> 3); + gen_helper_extr_rs_w(t0, t0, v1_t, cpu_env); + gen_store_gpr(t0, ret); + break; + } + break; + case NM_POOL32AXF_2_24_31: + switch (extract32(ctx->opcode, 9, 3)) { + case NM_DPAU_H_QBR: + case NM_DPAQX_SA_W_PH: + case NM_DPSU_H_QBR: + case NM_DPSQX_SA_W_PH: + case NM_MULSAQ_S_W_PH: + gen_pool32axf_2_multiply(ctx, opc, v0_t, v1_t, rd); + break; + case NM_EXTPDPV: + check_dsp(ctx); + tcg_gen_movi_tl(t0, rd >> 3); + gen_helper_extpdp(t0, t0, v1_t, cpu_env); + gen_store_gpr(t0, ret); + break; + case NM_MSUBU: + check_dsp(ctx); + { + int acc = extract32(ctx->opcode, 14, 2); + TCGv_i64 t2 = tcg_temp_new_i64(); + TCGv_i64 t3 = tcg_temp_new_i64(); + + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_extu_tl_i64(t2, t0); + tcg_gen_extu_tl_i64(t3, t1); + tcg_gen_mul_i64(t2, t2, t3); + tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]); + tcg_gen_sub_i64(t2, t3, t2); + tcg_temp_free_i64(t3); + gen_move_low32(cpu_LO[acc], t2); + gen_move_high32(cpu_HI[acc], t2); + tcg_temp_free_i64(t2); + } + break; + case NM_EXTRV_S_H: + check_dsp(ctx); + tcg_gen_movi_tl(t0, rd >> 3); + gen_helper_extr_s_h(t0, t0, v0_t, cpu_env); + gen_store_gpr(t0, ret); + break; + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + + tcg_temp_free(t0); + tcg_temp_free(t1); + + tcg_temp_free(v0_t); + tcg_temp_free(v1_t); +} + +static void gen_pool32axf_4_nanomips_insn(DisasContext *ctx, uint32_t opc, + int rt, int rs) +{ + int ret = rt; + TCGv t0 = tcg_temp_new(); + TCGv v0_t = tcg_temp_new(); + + gen_load_gpr(v0_t, rs); + + switch (opc) { + case NM_ABSQ_S_QB: + check_dsp_r2(ctx); + gen_helper_absq_s_qb(v0_t, v0_t, cpu_env); + gen_store_gpr(v0_t, ret); + break; + case NM_ABSQ_S_PH: + check_dsp(ctx); + gen_helper_absq_s_ph(v0_t, v0_t, cpu_env); + gen_store_gpr(v0_t, ret); + break; + case NM_ABSQ_S_W: + check_dsp(ctx); + gen_helper_absq_s_w(v0_t, v0_t, cpu_env); + gen_store_gpr(v0_t, ret); + break; + case NM_PRECEQ_W_PHL: + check_dsp(ctx); + tcg_gen_andi_tl(v0_t, v0_t, 0xFFFF0000); + tcg_gen_ext32s_tl(v0_t, v0_t); + gen_store_gpr(v0_t, ret); + break; + case NM_PRECEQ_W_PHR: + check_dsp(ctx); + tcg_gen_andi_tl(v0_t, v0_t, 0x0000FFFF); + tcg_gen_shli_tl(v0_t, v0_t, 16); + tcg_gen_ext32s_tl(v0_t, v0_t); + gen_store_gpr(v0_t, ret); + break; + case NM_PRECEQU_PH_QBL: + check_dsp(ctx); + gen_helper_precequ_ph_qbl(v0_t, v0_t); + gen_store_gpr(v0_t, ret); + break; + case NM_PRECEQU_PH_QBR: + check_dsp(ctx); + gen_helper_precequ_ph_qbr(v0_t, v0_t); + gen_store_gpr(v0_t, ret); + break; + case NM_PRECEQU_PH_QBLA: + check_dsp(ctx); + gen_helper_precequ_ph_qbla(v0_t, v0_t); + gen_store_gpr(v0_t, ret); + break; + case NM_PRECEQU_PH_QBRA: + check_dsp(ctx); + gen_helper_precequ_ph_qbra(v0_t, v0_t); + gen_store_gpr(v0_t, ret); + break; + case NM_PRECEU_PH_QBL: + check_dsp(ctx); + gen_helper_preceu_ph_qbl(v0_t, v0_t); + gen_store_gpr(v0_t, ret); + break; + case NM_PRECEU_PH_QBR: + check_dsp(ctx); + gen_helper_preceu_ph_qbr(v0_t, v0_t); + gen_store_gpr(v0_t, ret); + break; + case NM_PRECEU_PH_QBLA: + check_dsp(ctx); + gen_helper_preceu_ph_qbla(v0_t, v0_t); + gen_store_gpr(v0_t, ret); + break; + case NM_PRECEU_PH_QBRA: + check_dsp(ctx); + gen_helper_preceu_ph_qbra(v0_t, v0_t); + gen_store_gpr(v0_t, ret); + break; + case NM_REPLV_PH: + check_dsp(ctx); + tcg_gen_ext16u_tl(v0_t, v0_t); + tcg_gen_shli_tl(t0, v0_t, 16); + tcg_gen_or_tl(v0_t, v0_t, t0); + tcg_gen_ext32s_tl(v0_t, v0_t); + gen_store_gpr(v0_t, ret); + break; + case NM_REPLV_QB: + check_dsp(ctx); + tcg_gen_ext8u_tl(v0_t, v0_t); + tcg_gen_shli_tl(t0, v0_t, 8); + tcg_gen_or_tl(v0_t, v0_t, t0); + tcg_gen_shli_tl(t0, v0_t, 16); + tcg_gen_or_tl(v0_t, v0_t, t0); + tcg_gen_ext32s_tl(v0_t, v0_t); + gen_store_gpr(v0_t, ret); + break; + case NM_BITREV: + check_dsp(ctx); + gen_helper_bitrev(v0_t, v0_t); + gen_store_gpr(v0_t, ret); + break; + case NM_INSV: + check_dsp(ctx); + { + TCGv tv0 = tcg_temp_new(); + + gen_load_gpr(tv0, rt); + gen_helper_insv(v0_t, cpu_env, v0_t, tv0); + gen_store_gpr(v0_t, ret); + tcg_temp_free(tv0); + } + break; + case NM_RADDU_W_QB: + check_dsp(ctx); + gen_helper_raddu_w_qb(v0_t, v0_t); + gen_store_gpr(v0_t, ret); + break; + case NM_BITSWAP: + gen_bitswap(ctx, OPC_BITSWAP, ret, rs); + break; + case NM_CLO: + check_nms(ctx); + gen_cl(ctx, OPC_CLO, ret, rs); + break; + case NM_CLZ: + check_nms(ctx); + gen_cl(ctx, OPC_CLZ, ret, rs); + break; + case NM_WSBH: + gen_bshfl(ctx, OPC_WSBH, ret, rs); + break; + default: + gen_reserved_instruction(ctx); + break; + } + + tcg_temp_free(v0_t); + tcg_temp_free(t0); +} + +static void gen_pool32axf_7_nanomips_insn(DisasContext *ctx, uint32_t opc, + int rt, int rs, int rd) +{ + TCGv t0 = tcg_temp_new(); + TCGv rs_t = tcg_temp_new(); + + gen_load_gpr(rs_t, rs); + + switch (opc) { + case NM_SHRA_R_QB: + check_dsp_r2(ctx); + tcg_gen_movi_tl(t0, rd >> 2); + switch (extract32(ctx->opcode, 12, 1)) { + case 0: + /* NM_SHRA_QB */ + gen_helper_shra_qb(t0, t0, rs_t); + gen_store_gpr(t0, rt); + break; + case 1: + /* NM_SHRA_R_QB */ + gen_helper_shra_r_qb(t0, t0, rs_t); + gen_store_gpr(t0, rt); + break; + } + break; + case NM_SHRL_PH: + check_dsp_r2(ctx); + tcg_gen_movi_tl(t0, rd >> 1); + gen_helper_shrl_ph(t0, t0, rs_t); + gen_store_gpr(t0, rt); + break; + case NM_REPL_QB: + check_dsp(ctx); + { + int16_t imm; + target_long result; + imm = extract32(ctx->opcode, 13, 8); + result = (uint32_t)imm << 24 | + (uint32_t)imm << 16 | + (uint32_t)imm << 8 | + (uint32_t)imm; + result = (int32_t)result; + tcg_gen_movi_tl(t0, result); + gen_store_gpr(t0, rt); + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + tcg_temp_free(t0); + tcg_temp_free(rs_t); +} + + +static void gen_pool32axf_nanomips_insn(CPUMIPSState *env, DisasContext *ctx) +{ + int rt = extract32(ctx->opcode, 21, 5); + int rs = extract32(ctx->opcode, 16, 5); + int rd = extract32(ctx->opcode, 11, 5); + + switch (extract32(ctx->opcode, 6, 3)) { + case NM_POOL32AXF_1: + { + int32_t op1 = extract32(ctx->opcode, 9, 3); + gen_pool32axf_1_nanomips_insn(ctx, op1, rt, rs, rd); + } + break; + case NM_POOL32AXF_2: + { + int32_t op1 = extract32(ctx->opcode, 12, 2); + gen_pool32axf_2_nanomips_insn(ctx, op1, rt, rs, rd); + } + break; + case NM_POOL32AXF_4: + { + int32_t op1 = extract32(ctx->opcode, 9, 7); + gen_pool32axf_4_nanomips_insn(ctx, op1, rt, rs); + } + break; + case NM_POOL32AXF_5: + switch (extract32(ctx->opcode, 9, 7)) { +#ifndef CONFIG_USER_ONLY + case NM_TLBP: + gen_cp0(env, ctx, OPC_TLBP, 0, 0); + break; + case NM_TLBR: + gen_cp0(env, ctx, OPC_TLBR, 0, 0); + break; + case NM_TLBWI: + gen_cp0(env, ctx, OPC_TLBWI, 0, 0); + break; + case NM_TLBWR: + gen_cp0(env, ctx, OPC_TLBWR, 0, 0); + break; + case NM_TLBINV: + gen_cp0(env, ctx, OPC_TLBINV, 0, 0); + break; + case NM_TLBINVF: + gen_cp0(env, ctx, OPC_TLBINVF, 0, 0); + break; + case NM_DI: + check_cp0_enabled(ctx); + { + TCGv t0 = tcg_temp_new(); + + save_cpu_state(ctx, 1); + gen_helper_di(t0, cpu_env); + gen_store_gpr(t0, rt); + /* Stop translation as we may have switched the execution mode */ + ctx->base.is_jmp = DISAS_STOP; + tcg_temp_free(t0); + } + break; + case NM_EI: + check_cp0_enabled(ctx); + { + TCGv t0 = tcg_temp_new(); + + save_cpu_state(ctx, 1); + gen_helper_ei(t0, cpu_env); + gen_store_gpr(t0, rt); + /* Stop translation as we may have switched the execution mode */ + ctx->base.is_jmp = DISAS_STOP; + tcg_temp_free(t0); + } + break; + case NM_RDPGPR: + check_cp0_enabled(ctx); + gen_load_srsgpr(rs, rt); + break; + case NM_WRPGPR: + check_cp0_enabled(ctx); + gen_store_srsgpr(rs, rt); + break; + case NM_WAIT: + gen_cp0(env, ctx, OPC_WAIT, 0, 0); + break; + case NM_DERET: + gen_cp0(env, ctx, OPC_DERET, 0, 0); + break; + case NM_ERETX: + gen_cp0(env, ctx, OPC_ERET, 0, 0); + break; +#endif + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_POOL32AXF_7: + { + int32_t op1 = extract32(ctx->opcode, 9, 3); + gen_pool32axf_7_nanomips_insn(ctx, op1, rt, rs, rd); + } + break; + default: + gen_reserved_instruction(ctx); + break; + } +} + +/* Immediate Value Compact Branches */ +static void gen_compute_imm_branch(DisasContext *ctx, uint32_t opc, + int rt, int32_t imm, int32_t offset) +{ + TCGCond cond = TCG_COND_ALWAYS; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + gen_load_gpr(t0, rt); + tcg_gen_movi_tl(t1, imm); + ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); + + /* Load needed operands and calculate btarget */ + switch (opc) { + case NM_BEQIC: + if (rt == 0 && imm == 0) { + /* Unconditional branch */ + } else if (rt == 0 && imm != 0) { + /* Treat as NOP */ + goto out; + } else { + cond = TCG_COND_EQ; + } + break; + case NM_BBEQZC: + case NM_BBNEZC: + check_nms(ctx); + if (imm >= 32 && !(ctx->hflags & MIPS_HFLAG_64)) { + gen_reserved_instruction(ctx); + goto out; + } else if (rt == 0 && opc == NM_BBEQZC) { + /* Unconditional branch */ + } else if (rt == 0 && opc == NM_BBNEZC) { + /* Treat as NOP */ + goto out; + } else { + tcg_gen_shri_tl(t0, t0, imm); + tcg_gen_andi_tl(t0, t0, 1); + tcg_gen_movi_tl(t1, 0); + if (opc == NM_BBEQZC) { + cond = TCG_COND_EQ; + } else { + cond = TCG_COND_NE; + } + } + break; + case NM_BNEIC: + if (rt == 0 && imm == 0) { + /* Treat as NOP */ + goto out; + } else if (rt == 0 && imm != 0) { + /* Unconditional branch */ + } else { + cond = TCG_COND_NE; + } + break; + case NM_BGEIC: + if (rt == 0 && imm == 0) { + /* Unconditional branch */ + } else { + cond = TCG_COND_GE; + } + break; + case NM_BLTIC: + cond = TCG_COND_LT; + break; + case NM_BGEIUC: + if (rt == 0 && imm == 0) { + /* Unconditional branch */ + } else { + cond = TCG_COND_GEU; + } + break; + case NM_BLTIUC: + cond = TCG_COND_LTU; + break; + default: + MIPS_INVAL("Immediate Value Compact branch"); + gen_reserved_instruction(ctx); + goto out; + } + + /* branch completion */ + clear_branch_hflags(ctx); + ctx->base.is_jmp = DISAS_NORETURN; + + if (cond == TCG_COND_ALWAYS) { + /* Uncoditional compact branch */ + gen_goto_tb(ctx, 0, ctx->btarget); + } else { + /* Conditional compact branch */ + TCGLabel *fs = gen_new_label(); + + tcg_gen_brcond_tl(tcg_invert_cond(cond), t0, t1, fs); + + gen_goto_tb(ctx, 1, ctx->btarget); + gen_set_label(fs); + + gen_goto_tb(ctx, 0, ctx->base.pc_next + 4); + } + +out: + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +/* P.BALRSC type nanoMIPS R6 branches: BALRSC and BRSC */ +static void gen_compute_nanomips_pbalrsc_branch(DisasContext *ctx, int rs, + int rt) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + /* load rs */ + gen_load_gpr(t0, rs); + + /* link */ + if (rt != 0) { + tcg_gen_movi_tl(cpu_gpr[rt], ctx->base.pc_next + 4); + } + + /* calculate btarget */ + tcg_gen_shli_tl(t0, t0, 1); + tcg_gen_movi_tl(t1, ctx->base.pc_next + 4); + gen_op_addr_add(ctx, btarget, t1, t0); + + /* branch completion */ + clear_branch_hflags(ctx); + ctx->base.is_jmp = DISAS_NORETURN; + + /* unconditional branch to register */ + tcg_gen_mov_tl(cpu_PC, btarget); + tcg_gen_lookup_and_goto_ptr(); + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +/* nanoMIPS Branches */ +static void gen_compute_compact_branch_nm(DisasContext *ctx, uint32_t opc, + int rs, int rt, int32_t offset) +{ + int bcond_compute = 0; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + /* Load needed operands and calculate btarget */ + switch (opc) { + /* compact branch */ + case OPC_BGEC: + case OPC_BLTC: + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + bcond_compute = 1; + ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); + break; + case OPC_BGEUC: + case OPC_BLTUC: + if (rs == 0 || rs == rt) { + /* OPC_BLEZALC, OPC_BGEZALC */ + /* OPC_BGTZALC, OPC_BLTZALC */ + tcg_gen_movi_tl(cpu_gpr[31], ctx->base.pc_next + 4); + } + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + bcond_compute = 1; + ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); + break; + case OPC_BC: + ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); + break; + case OPC_BEQZC: + if (rs != 0) { + /* OPC_BEQZC, OPC_BNEZC */ + gen_load_gpr(t0, rs); + bcond_compute = 1; + ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); + } else { + /* OPC_JIC, OPC_JIALC */ + TCGv tbase = tcg_temp_new(); + TCGv toffset = tcg_temp_new(); + + gen_load_gpr(tbase, rt); + tcg_gen_movi_tl(toffset, offset); + gen_op_addr_add(ctx, btarget, tbase, toffset); + tcg_temp_free(tbase); + tcg_temp_free(toffset); + } + break; + default: + MIPS_INVAL("Compact branch/jump"); + gen_reserved_instruction(ctx); + goto out; + } + + if (bcond_compute == 0) { + /* Uncoditional compact branch */ + switch (opc) { + case OPC_BC: + gen_goto_tb(ctx, 0, ctx->btarget); + break; + default: + MIPS_INVAL("Compact branch/jump"); + gen_reserved_instruction(ctx); + goto out; + } + } else { + /* Conditional compact branch */ + TCGLabel *fs = gen_new_label(); + + switch (opc) { + case OPC_BGEUC: + if (rs == 0 && rt != 0) { + /* OPC_BLEZALC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LE), t1, 0, fs); + } else if (rs != 0 && rt != 0 && rs == rt) { + /* OPC_BGEZALC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GE), t1, 0, fs); + } else { + /* OPC_BGEUC */ + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_GEU), t0, t1, fs); + } + break; + case OPC_BLTUC: + if (rs == 0 && rt != 0) { + /* OPC_BGTZALC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GT), t1, 0, fs); + } else if (rs != 0 && rt != 0 && rs == rt) { + /* OPC_BLTZALC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LT), t1, 0, fs); + } else { + /* OPC_BLTUC */ + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_LTU), t0, t1, fs); + } + break; + case OPC_BGEC: + if (rs == 0 && rt != 0) { + /* OPC_BLEZC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LE), t1, 0, fs); + } else if (rs != 0 && rt != 0 && rs == rt) { + /* OPC_BGEZC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GE), t1, 0, fs); + } else { + /* OPC_BGEC */ + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_GE), t0, t1, fs); + } + break; + case OPC_BLTC: + if (rs == 0 && rt != 0) { + /* OPC_BGTZC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GT), t1, 0, fs); + } else if (rs != 0 && rt != 0 && rs == rt) { + /* OPC_BLTZC */ + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LT), t1, 0, fs); + } else { + /* OPC_BLTC */ + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_LT), t0, t1, fs); + } + break; + case OPC_BEQZC: + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_EQ), t0, 0, fs); + break; + default: + MIPS_INVAL("Compact conditional branch/jump"); + gen_reserved_instruction(ctx); + goto out; + } + + /* branch completion */ + clear_branch_hflags(ctx); + ctx->base.is_jmp = DISAS_NORETURN; + + /* Generating branch here as compact branches don't have delay slot */ + gen_goto_tb(ctx, 1, ctx->btarget); + gen_set_label(fs); + + gen_goto_tb(ctx, 0, ctx->base.pc_next + 4); + } + +out: + tcg_temp_free(t0); + tcg_temp_free(t1); +} + + +/* nanoMIPS CP1 Branches */ +static void gen_compute_branch_cp1_nm(DisasContext *ctx, uint32_t op, + int32_t ft, int32_t offset) +{ + target_ulong btarget; + TCGv_i64 t0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, t0, ft); + tcg_gen_andi_i64(t0, t0, 1); + + btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); + + switch (op) { + case NM_BC1EQZC: + tcg_gen_xori_i64(t0, t0, 1); + ctx->hflags |= MIPS_HFLAG_BC; + break; + case NM_BC1NEZC: + /* t0 already set */ + ctx->hflags |= MIPS_HFLAG_BC; + break; + default: + MIPS_INVAL("cp1 cond branch"); + gen_reserved_instruction(ctx); + goto out; + } + + tcg_gen_trunc_i64_tl(bcond, t0); + + ctx->btarget = btarget; + +out: + tcg_temp_free_i64(t0); +} + + +static void gen_p_lsx(DisasContext *ctx, int rd, int rs, int rt) +{ + TCGv t0, t1; + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + + if ((extract32(ctx->opcode, 6, 1)) == 1) { + /* PP.LSXS instructions require shifting */ + switch (extract32(ctx->opcode, 7, 4)) { + case NM_SHXS: + check_nms(ctx); + /* fall through */ + case NM_LHXS: + case NM_LHUXS: + tcg_gen_shli_tl(t0, t0, 1); + break; + case NM_SWXS: + check_nms(ctx); + /* fall through */ + case NM_LWXS: + case NM_LWC1XS: + case NM_SWC1XS: + tcg_gen_shli_tl(t0, t0, 2); + break; + case NM_LDC1XS: + case NM_SDC1XS: + tcg_gen_shli_tl(t0, t0, 3); + break; + } + } + gen_op_addr_add(ctx, t0, t0, t1); + + switch (extract32(ctx->opcode, 7, 4)) { + case NM_LBX: + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, + MO_SB); + gen_store_gpr(t0, rd); + break; + case NM_LHX: + /*case NM_LHXS:*/ + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, + MO_TESW); + gen_store_gpr(t0, rd); + break; + case NM_LWX: + /*case NM_LWXS:*/ + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, + MO_TESL); + gen_store_gpr(t0, rd); + break; + case NM_LBUX: + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, + MO_UB); + gen_store_gpr(t0, rd); + break; + case NM_LHUX: + /*case NM_LHUXS:*/ + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, + MO_TEUW); + gen_store_gpr(t0, rd); + break; + case NM_SBX: + check_nms(ctx); + gen_load_gpr(t1, rd); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, + MO_8); + break; + case NM_SHX: + /*case NM_SHXS:*/ + check_nms(ctx); + gen_load_gpr(t1, rd); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, + MO_TEUW); + break; + case NM_SWX: + /*case NM_SWXS:*/ + check_nms(ctx); + gen_load_gpr(t1, rd); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, + MO_TEUL); + break; + case NM_LWC1X: + /*case NM_LWC1XS:*/ + case NM_LDC1X: + /*case NM_LDC1XS:*/ + case NM_SWC1X: + /*case NM_SWC1XS:*/ + case NM_SDC1X: + /*case NM_SDC1XS:*/ + if (ctx->CP0_Config1 & (1 << CP0C1_FP)) { + check_cp1_enabled(ctx); + switch (extract32(ctx->opcode, 7, 4)) { + case NM_LWC1X: + /*case NM_LWC1XS:*/ + gen_flt_ldst(ctx, OPC_LWC1, rd, t0); + break; + case NM_LDC1X: + /*case NM_LDC1XS:*/ + gen_flt_ldst(ctx, OPC_LDC1, rd, t0); + break; + case NM_SWC1X: + /*case NM_SWC1XS:*/ + gen_flt_ldst(ctx, OPC_SWC1, rd, t0); + break; + case NM_SDC1X: + /*case NM_SDC1XS:*/ + gen_flt_ldst(ctx, OPC_SDC1, rd, t0); + break; + } + } else { + generate_exception_err(ctx, EXCP_CpU, 1); + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_pool32f_nanomips_insn(DisasContext *ctx) +{ + int rt, rs, rd; + + rt = extract32(ctx->opcode, 21, 5); + rs = extract32(ctx->opcode, 16, 5); + rd = extract32(ctx->opcode, 11, 5); + + if (!(ctx->CP0_Config1 & (1 << CP0C1_FP))) { + gen_reserved_instruction(ctx); + return; + } + check_cp1_enabled(ctx); + switch (extract32(ctx->opcode, 0, 3)) { + case NM_POOL32F_0: + switch (extract32(ctx->opcode, 3, 7)) { + case NM_RINT_S: + gen_farith(ctx, OPC_RINT_S, 0, rt, rs, 0); + break; + case NM_RINT_D: + gen_farith(ctx, OPC_RINT_D, 0, rt, rs, 0); + break; + case NM_CLASS_S: + gen_farith(ctx, OPC_CLASS_S, 0, rt, rs, 0); + break; + case NM_CLASS_D: + gen_farith(ctx, OPC_CLASS_D, 0, rt, rs, 0); + break; + case NM_ADD_S: + gen_farith(ctx, OPC_ADD_S, rt, rs, rd, 0); + break; + case NM_ADD_D: + gen_farith(ctx, OPC_ADD_D, rt, rs, rd, 0); + break; + case NM_SUB_S: + gen_farith(ctx, OPC_SUB_S, rt, rs, rd, 0); + break; + case NM_SUB_D: + gen_farith(ctx, OPC_SUB_D, rt, rs, rd, 0); + break; + case NM_MUL_S: + gen_farith(ctx, OPC_MUL_S, rt, rs, rd, 0); + break; + case NM_MUL_D: + gen_farith(ctx, OPC_MUL_D, rt, rs, rd, 0); + break; + case NM_DIV_S: + gen_farith(ctx, OPC_DIV_S, rt, rs, rd, 0); + break; + case NM_DIV_D: + gen_farith(ctx, OPC_DIV_D, rt, rs, rd, 0); + break; + case NM_SELEQZ_S: + gen_sel_s(ctx, OPC_SELEQZ_S, rd, rt, rs); + break; + case NM_SELEQZ_D: + gen_sel_d(ctx, OPC_SELEQZ_D, rd, rt, rs); + break; + case NM_SELNEZ_S: + gen_sel_s(ctx, OPC_SELNEZ_S, rd, rt, rs); + break; + case NM_SELNEZ_D: + gen_sel_d(ctx, OPC_SELNEZ_D, rd, rt, rs); + break; + case NM_SEL_S: + gen_sel_s(ctx, OPC_SEL_S, rd, rt, rs); + break; + case NM_SEL_D: + gen_sel_d(ctx, OPC_SEL_D, rd, rt, rs); + break; + case NM_MADDF_S: + gen_farith(ctx, OPC_MADDF_S, rt, rs, rd, 0); + break; + case NM_MADDF_D: + gen_farith(ctx, OPC_MADDF_D, rt, rs, rd, 0); + break; + case NM_MSUBF_S: + gen_farith(ctx, OPC_MSUBF_S, rt, rs, rd, 0); + break; + case NM_MSUBF_D: + gen_farith(ctx, OPC_MSUBF_D, rt, rs, rd, 0); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_POOL32F_3: + switch (extract32(ctx->opcode, 3, 3)) { + case NM_MIN_FMT: + switch (extract32(ctx->opcode, 9, 1)) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MIN_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MIN_D, rt, rs, rd, 0); + break; + } + break; + case NM_MAX_FMT: + switch (extract32(ctx->opcode, 9, 1)) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MAX_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MAX_D, rt, rs, rd, 0); + break; + } + break; + case NM_MINA_FMT: + switch (extract32(ctx->opcode, 9, 1)) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MINA_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MINA_D, rt, rs, rd, 0); + break; + } + break; + case NM_MAXA_FMT: + switch (extract32(ctx->opcode, 9, 1)) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MAXA_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MAXA_D, rt, rs, rd, 0); + break; + } + break; + case NM_POOL32FXF: + switch (extract32(ctx->opcode, 6, 8)) { + case NM_CFC1: + gen_cp1(ctx, OPC_CFC1, rt, rs); + break; + case NM_CTC1: + gen_cp1(ctx, OPC_CTC1, rt, rs); + break; + case NM_MFC1: + gen_cp1(ctx, OPC_MFC1, rt, rs); + break; + case NM_MTC1: + gen_cp1(ctx, OPC_MTC1, rt, rs); + break; + case NM_MFHC1: + gen_cp1(ctx, OPC_MFHC1, rt, rs); + break; + case NM_MTHC1: + gen_cp1(ctx, OPC_MTHC1, rt, rs); + break; + case NM_CVT_S_PL: + gen_farith(ctx, OPC_CVT_S_PL, -1, rs, rt, 0); + break; + case NM_CVT_S_PU: + gen_farith(ctx, OPC_CVT_S_PU, -1, rs, rt, 0); + break; + default: + switch (extract32(ctx->opcode, 6, 9)) { + case NM_CVT_L_S: + gen_farith(ctx, OPC_CVT_L_S, -1, rs, rt, 0); + break; + case NM_CVT_L_D: + gen_farith(ctx, OPC_CVT_L_D, -1, rs, rt, 0); + break; + case NM_CVT_W_S: + gen_farith(ctx, OPC_CVT_W_S, -1, rs, rt, 0); + break; + case NM_CVT_W_D: + gen_farith(ctx, OPC_CVT_W_D, -1, rs, rt, 0); + break; + case NM_RSQRT_S: + gen_farith(ctx, OPC_RSQRT_S, -1, rs, rt, 0); + break; + case NM_RSQRT_D: + gen_farith(ctx, OPC_RSQRT_D, -1, rs, rt, 0); + break; + case NM_SQRT_S: + gen_farith(ctx, OPC_SQRT_S, -1, rs, rt, 0); + break; + case NM_SQRT_D: + gen_farith(ctx, OPC_SQRT_D, -1, rs, rt, 0); + break; + case NM_RECIP_S: + gen_farith(ctx, OPC_RECIP_S, -1, rs, rt, 0); + break; + case NM_RECIP_D: + gen_farith(ctx, OPC_RECIP_D, -1, rs, rt, 0); + break; + case NM_FLOOR_L_S: + gen_farith(ctx, OPC_FLOOR_L_S, -1, rs, rt, 0); + break; + case NM_FLOOR_L_D: + gen_farith(ctx, OPC_FLOOR_L_D, -1, rs, rt, 0); + break; + case NM_FLOOR_W_S: + gen_farith(ctx, OPC_FLOOR_W_S, -1, rs, rt, 0); + break; + case NM_FLOOR_W_D: + gen_farith(ctx, OPC_FLOOR_W_D, -1, rs, rt, 0); + break; + case NM_CEIL_L_S: + gen_farith(ctx, OPC_CEIL_L_S, -1, rs, rt, 0); + break; + case NM_CEIL_L_D: + gen_farith(ctx, OPC_CEIL_L_D, -1, rs, rt, 0); + break; + case NM_CEIL_W_S: + gen_farith(ctx, OPC_CEIL_W_S, -1, rs, rt, 0); + break; + case NM_CEIL_W_D: + gen_farith(ctx, OPC_CEIL_W_D, -1, rs, rt, 0); + break; + case NM_TRUNC_L_S: + gen_farith(ctx, OPC_TRUNC_L_S, -1, rs, rt, 0); + break; + case NM_TRUNC_L_D: + gen_farith(ctx, OPC_TRUNC_L_D, -1, rs, rt, 0); + break; + case NM_TRUNC_W_S: + gen_farith(ctx, OPC_TRUNC_W_S, -1, rs, rt, 0); + break; + case NM_TRUNC_W_D: + gen_farith(ctx, OPC_TRUNC_W_D, -1, rs, rt, 0); + break; + case NM_ROUND_L_S: + gen_farith(ctx, OPC_ROUND_L_S, -1, rs, rt, 0); + break; + case NM_ROUND_L_D: + gen_farith(ctx, OPC_ROUND_L_D, -1, rs, rt, 0); + break; + case NM_ROUND_W_S: + gen_farith(ctx, OPC_ROUND_W_S, -1, rs, rt, 0); + break; + case NM_ROUND_W_D: + gen_farith(ctx, OPC_ROUND_W_D, -1, rs, rt, 0); + break; + case NM_MOV_S: + gen_farith(ctx, OPC_MOV_S, -1, rs, rt, 0); + break; + case NM_MOV_D: + gen_farith(ctx, OPC_MOV_D, -1, rs, rt, 0); + break; + case NM_ABS_S: + gen_farith(ctx, OPC_ABS_S, -1, rs, rt, 0); + break; + case NM_ABS_D: + gen_farith(ctx, OPC_ABS_D, -1, rs, rt, 0); + break; + case NM_NEG_S: + gen_farith(ctx, OPC_NEG_S, -1, rs, rt, 0); + break; + case NM_NEG_D: + gen_farith(ctx, OPC_NEG_D, -1, rs, rt, 0); + break; + case NM_CVT_D_S: + gen_farith(ctx, OPC_CVT_D_S, -1, rs, rt, 0); + break; + case NM_CVT_D_W: + gen_farith(ctx, OPC_CVT_D_W, -1, rs, rt, 0); + break; + case NM_CVT_D_L: + gen_farith(ctx, OPC_CVT_D_L, -1, rs, rt, 0); + break; + case NM_CVT_S_D: + gen_farith(ctx, OPC_CVT_S_D, -1, rs, rt, 0); + break; + case NM_CVT_S_W: + gen_farith(ctx, OPC_CVT_S_W, -1, rs, rt, 0); + break; + case NM_CVT_S_L: + gen_farith(ctx, OPC_CVT_S_L, -1, rs, rt, 0); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + } + break; + } + break; + case NM_POOL32F_5: + switch (extract32(ctx->opcode, 3, 3)) { + case NM_CMP_CONDN_S: + gen_r6_cmp_s(ctx, extract32(ctx->opcode, 6, 5), rt, rs, rd); + break; + case NM_CMP_CONDN_D: + gen_r6_cmp_d(ctx, extract32(ctx->opcode, 6, 5), rt, rs, rd); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + default: + gen_reserved_instruction(ctx); + break; + } +} + +static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, + int rd, int rs, int rt) +{ + int ret = rd; + TCGv t0 = tcg_temp_new(); + TCGv v1_t = tcg_temp_new(); + TCGv v2_t = tcg_temp_new(); + + gen_load_gpr(v1_t, rs); + gen_load_gpr(v2_t, rt); + + switch (opc) { + case NM_CMP_EQ_PH: + check_dsp(ctx); + gen_helper_cmp_eq_ph(v1_t, v2_t, cpu_env); + break; + case NM_CMP_LT_PH: + check_dsp(ctx); + gen_helper_cmp_lt_ph(v1_t, v2_t, cpu_env); + break; + case NM_CMP_LE_PH: + check_dsp(ctx); + gen_helper_cmp_le_ph(v1_t, v2_t, cpu_env); + break; + case NM_CMPU_EQ_QB: + check_dsp(ctx); + gen_helper_cmpu_eq_qb(v1_t, v2_t, cpu_env); + break; + case NM_CMPU_LT_QB: + check_dsp(ctx); + gen_helper_cmpu_lt_qb(v1_t, v2_t, cpu_env); + break; + case NM_CMPU_LE_QB: + check_dsp(ctx); + gen_helper_cmpu_le_qb(v1_t, v2_t, cpu_env); + break; + case NM_CMPGU_EQ_QB: + check_dsp(ctx); + gen_helper_cmpgu_eq_qb(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case NM_CMPGU_LT_QB: + check_dsp(ctx); + gen_helper_cmpgu_lt_qb(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case NM_CMPGU_LE_QB: + check_dsp(ctx); + gen_helper_cmpgu_le_qb(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case NM_CMPGDU_EQ_QB: + check_dsp_r2(ctx); + gen_helper_cmpgu_eq_qb(v1_t, v1_t, v2_t); + tcg_gen_deposit_tl(cpu_dspctrl, cpu_dspctrl, v1_t, 24, 4); + gen_store_gpr(v1_t, ret); + break; + case NM_CMPGDU_LT_QB: + check_dsp_r2(ctx); + gen_helper_cmpgu_lt_qb(v1_t, v1_t, v2_t); + tcg_gen_deposit_tl(cpu_dspctrl, cpu_dspctrl, v1_t, 24, 4); + gen_store_gpr(v1_t, ret); + break; + case NM_CMPGDU_LE_QB: + check_dsp_r2(ctx); + gen_helper_cmpgu_le_qb(v1_t, v1_t, v2_t); + tcg_gen_deposit_tl(cpu_dspctrl, cpu_dspctrl, v1_t, 24, 4); + gen_store_gpr(v1_t, ret); + break; + case NM_PACKRL_PH: + check_dsp(ctx); + gen_helper_packrl_ph(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case NM_PICK_QB: + check_dsp(ctx); + gen_helper_pick_qb(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_PICK_PH: + check_dsp(ctx); + gen_helper_pick_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_ADDQ_S_W: + check_dsp(ctx); + gen_helper_addq_s_w(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_SUBQ_S_W: + check_dsp(ctx); + gen_helper_subq_s_w(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_ADDSC: + check_dsp(ctx); + gen_helper_addsc(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_ADDWC: + check_dsp(ctx); + gen_helper_addwc(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_ADDQ_S_PH: + check_dsp(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* ADDQ_PH */ + gen_helper_addq_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* ADDQ_S_PH */ + gen_helper_addq_s_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_ADDQH_R_PH: + check_dsp_r2(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* ADDQH_PH */ + gen_helper_addqh_ph(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* ADDQH_R_PH */ + gen_helper_addqh_r_ph(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_ADDQH_R_W: + check_dsp_r2(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* ADDQH_W */ + gen_helper_addqh_w(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* ADDQH_R_W */ + gen_helper_addqh_r_w(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_ADDU_S_QB: + check_dsp(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* ADDU_QB */ + gen_helper_addu_qb(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* ADDU_S_QB */ + gen_helper_addu_s_qb(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_ADDU_S_PH: + check_dsp_r2(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* ADDU_PH */ + gen_helper_addu_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* ADDU_S_PH */ + gen_helper_addu_s_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_ADDUH_R_QB: + check_dsp_r2(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* ADDUH_QB */ + gen_helper_adduh_qb(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* ADDUH_R_QB */ + gen_helper_adduh_r_qb(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_SHRAV_R_PH: + check_dsp(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* SHRAV_PH */ + gen_helper_shra_ph(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* SHRAV_R_PH */ + gen_helper_shra_r_ph(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_SHRAV_R_QB: + check_dsp_r2(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* SHRAV_QB */ + gen_helper_shra_qb(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* SHRAV_R_QB */ + gen_helper_shra_r_qb(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_SUBQ_S_PH: + check_dsp(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* SUBQ_PH */ + gen_helper_subq_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* SUBQ_S_PH */ + gen_helper_subq_s_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_SUBQH_R_PH: + check_dsp_r2(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* SUBQH_PH */ + gen_helper_subqh_ph(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* SUBQH_R_PH */ + gen_helper_subqh_r_ph(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_SUBQH_R_W: + check_dsp_r2(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* SUBQH_W */ + gen_helper_subqh_w(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* SUBQH_R_W */ + gen_helper_subqh_r_w(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_SUBU_S_QB: + check_dsp(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* SUBU_QB */ + gen_helper_subu_qb(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* SUBU_S_QB */ + gen_helper_subu_s_qb(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_SUBU_S_PH: + check_dsp_r2(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* SUBU_PH */ + gen_helper_subu_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* SUBU_S_PH */ + gen_helper_subu_s_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_SUBUH_R_QB: + check_dsp_r2(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* SUBUH_QB */ + gen_helper_subuh_qb(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* SUBUH_R_QB */ + gen_helper_subuh_r_qb(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_SHLLV_S_PH: + check_dsp(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* SHLLV_PH */ + gen_helper_shll_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* SHLLV_S_PH */ + gen_helper_shll_s_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_PRECR_SRA_R_PH_W: + check_dsp_r2(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* PRECR_SRA_PH_W */ + { + TCGv_i32 sa_t = tcg_const_i32(rd); + gen_helper_precr_sra_ph_w(v1_t, sa_t, v1_t, + cpu_gpr[rt]); + gen_store_gpr(v1_t, rt); + tcg_temp_free_i32(sa_t); + } + break; + case 1: + /* PRECR_SRA_R_PH_W */ + { + TCGv_i32 sa_t = tcg_const_i32(rd); + gen_helper_precr_sra_r_ph_w(v1_t, sa_t, v1_t, + cpu_gpr[rt]); + gen_store_gpr(v1_t, rt); + tcg_temp_free_i32(sa_t); + } + break; + } + break; + case NM_MULEU_S_PH_QBL: + check_dsp(ctx); + gen_helper_muleu_s_ph_qbl(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_MULEU_S_PH_QBR: + check_dsp(ctx); + gen_helper_muleu_s_ph_qbr(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_MULQ_RS_PH: + check_dsp(ctx); + gen_helper_mulq_rs_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_MULQ_S_PH: + check_dsp_r2(ctx); + gen_helper_mulq_s_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_MULQ_RS_W: + check_dsp_r2(ctx); + gen_helper_mulq_rs_w(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_MULQ_S_W: + check_dsp_r2(ctx); + gen_helper_mulq_s_w(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_APPEND: + check_dsp_r2(ctx); + gen_load_gpr(t0, rs); + if (rd != 0) { + tcg_gen_deposit_tl(cpu_gpr[rt], t0, cpu_gpr[rt], rd, 32 - rd); + } + tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); + break; + case NM_MODSUB: + check_dsp(ctx); + gen_helper_modsub(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case NM_SHRAV_R_W: + check_dsp(ctx); + gen_helper_shra_r_w(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case NM_SHRLV_PH: + check_dsp_r2(ctx); + gen_helper_shrl_ph(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case NM_SHRLV_QB: + check_dsp(ctx); + gen_helper_shrl_qb(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case NM_SHLLV_QB: + check_dsp(ctx); + gen_helper_shll_qb(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_SHLLV_S_W: + check_dsp(ctx); + gen_helper_shll_s_w(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_SHILO: + check_dsp(ctx); + { + TCGv tv0 = tcg_temp_new(); + TCGv tv1 = tcg_temp_new(); + int16_t imm = extract32(ctx->opcode, 16, 7); + + tcg_gen_movi_tl(tv0, rd >> 3); + tcg_gen_movi_tl(tv1, imm); + gen_helper_shilo(tv0, tv1, cpu_env); + tcg_temp_free(tv1); + tcg_temp_free(tv0); + } + break; + case NM_MULEQ_S_W_PHL: + check_dsp(ctx); + gen_helper_muleq_s_w_phl(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_MULEQ_S_W_PHR: + check_dsp(ctx); + gen_helper_muleq_s_w_phr(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_MUL_S_PH: + check_dsp_r2(ctx); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* MUL_PH */ + gen_helper_mul_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case 1: + /* MUL_S_PH */ + gen_helper_mul_s_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + } + break; + case NM_PRECR_QB_PH: + check_dsp_r2(ctx); + gen_helper_precr_qb_ph(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case NM_PRECRQ_QB_PH: + check_dsp(ctx); + gen_helper_precrq_qb_ph(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case NM_PRECRQ_PH_W: + check_dsp(ctx); + gen_helper_precrq_ph_w(v1_t, v1_t, v2_t); + gen_store_gpr(v1_t, ret); + break; + case NM_PRECRQ_RS_PH_W: + check_dsp(ctx); + gen_helper_precrq_rs_ph_w(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_PRECRQU_S_QB_PH: + check_dsp(ctx); + gen_helper_precrqu_s_qb_ph(v1_t, v1_t, v2_t, cpu_env); + gen_store_gpr(v1_t, ret); + break; + case NM_SHRA_R_W: + check_dsp(ctx); + tcg_gen_movi_tl(t0, rd); + gen_helper_shra_r_w(v1_t, t0, v1_t); + gen_store_gpr(v1_t, rt); + break; + case NM_SHRA_R_PH: + check_dsp(ctx); + tcg_gen_movi_tl(t0, rd >> 1); + switch (extract32(ctx->opcode, 10, 1)) { + case 0: + /* SHRA_PH */ + gen_helper_shra_ph(v1_t, t0, v1_t); + gen_store_gpr(v1_t, rt); + break; + case 1: + /* SHRA_R_PH */ + gen_helper_shra_r_ph(v1_t, t0, v1_t); + gen_store_gpr(v1_t, rt); + break; + } + break; + case NM_SHLL_S_PH: + check_dsp(ctx); + tcg_gen_movi_tl(t0, rd >> 1); + switch (extract32(ctx->opcode, 10, 2)) { + case 0: + /* SHLL_PH */ + gen_helper_shll_ph(v1_t, t0, v1_t, cpu_env); + gen_store_gpr(v1_t, rt); + break; + case 2: + /* SHLL_S_PH */ + gen_helper_shll_s_ph(v1_t, t0, v1_t, cpu_env); + gen_store_gpr(v1_t, rt); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_SHLL_S_W: + check_dsp(ctx); + tcg_gen_movi_tl(t0, rd); + gen_helper_shll_s_w(v1_t, t0, v1_t, cpu_env); + gen_store_gpr(v1_t, rt); + break; + case NM_REPL_PH: + check_dsp(ctx); + { + int16_t imm; + imm = sextract32(ctx->opcode, 11, 11); + imm = (int16_t)(imm << 6) >> 6; + if (rt != 0) { + tcg_gen_movi_tl(cpu_gpr[rt], dup_const(MO_16, imm)); + } + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + + tcg_temp_free(v2_t); + tcg_temp_free(v1_t); + tcg_temp_free(t0); +} + +static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) +{ + uint16_t insn; + uint32_t op; + int rt, rs, rd; + int offset; + int imm; + + insn = translator_lduw(env, ctx->base.pc_next + 2); + ctx->opcode = (ctx->opcode << 16) | insn; + + rt = extract32(ctx->opcode, 21, 5); + rs = extract32(ctx->opcode, 16, 5); + rd = extract32(ctx->opcode, 11, 5); + + op = extract32(ctx->opcode, 26, 6); + switch (op) { + case NM_P_ADDIU: + if (rt == 0) { + /* P.RI */ + switch (extract32(ctx->opcode, 19, 2)) { + case NM_SIGRIE: + default: + gen_reserved_instruction(ctx); + break; + case NM_P_SYSCALL: + if ((extract32(ctx->opcode, 18, 1)) == NM_SYSCALL) { + generate_exception_end(ctx, EXCP_SYSCALL); + } else { + gen_reserved_instruction(ctx); + } + break; + case NM_BREAK: + generate_exception_end(ctx, EXCP_BREAK); + break; + case NM_SDBBP: + if (is_uhi(extract32(ctx->opcode, 0, 19))) { + gen_helper_do_semihosting(cpu_env); + } else { + if (ctx->hflags & MIPS_HFLAG_SBRI) { + gen_reserved_instruction(ctx); + } else { + generate_exception_end(ctx, EXCP_DBp); + } + } + break; + } + } else { + /* NM_ADDIU */ + imm = extract32(ctx->opcode, 0, 16); + if (rs != 0) { + tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], imm); + } else { + tcg_gen_movi_tl(cpu_gpr[rt], imm); + } + tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); + } + break; + case NM_ADDIUPC: + if (rt != 0) { + offset = sextract32(ctx->opcode, 0, 1) << 21 | + extract32(ctx->opcode, 1, 20) << 1; + target_long addr = addr_add(ctx, ctx->base.pc_next + 4, offset); + tcg_gen_movi_tl(cpu_gpr[rt], addr); + } + break; + case NM_POOL32A: + switch (ctx->opcode & 0x07) { + case NM_POOL32A0: + gen_pool32a0_nanomips_insn(env, ctx); + break; + case NM_POOL32A5: + { + int32_t op1 = extract32(ctx->opcode, 3, 7); + gen_pool32a5_nanomips_insn(ctx, op1, rd, rs, rt); + } + break; + case NM_POOL32A7: + switch (extract32(ctx->opcode, 3, 3)) { + case NM_P_LSX: + gen_p_lsx(ctx, rd, rs, rt); + break; + case NM_LSA: + /* + * In nanoMIPS, the shift field directly encodes the shift + * amount, meaning that the supported shift values are in + * the range 0 to 3 (instead of 1 to 4 in MIPSR6). + */ + gen_lsa(ctx, rd, rt, rs, extract32(ctx->opcode, 9, 2) - 1); + break; + case NM_EXTW: + gen_ext(ctx, 32, rd, rs, rt, extract32(ctx->opcode, 6, 5)); + break; + case NM_POOL32AXF: + gen_pool32axf_nanomips_insn(env, ctx); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_P_GP_W: + switch (ctx->opcode & 0x03) { + case NM_ADDIUGP_W: + if (rt != 0) { + offset = extract32(ctx->opcode, 0, 21); + gen_op_addr_addi(ctx, cpu_gpr[rt], cpu_gpr[28], offset); + } + break; + case NM_LWGP: + gen_ld(ctx, OPC_LW, rt, 28, extract32(ctx->opcode, 2, 19) << 2); + break; + case NM_SWGP: + gen_st(ctx, OPC_SW, rt, 28, extract32(ctx->opcode, 2, 19) << 2); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_P48I: + { + insn = translator_lduw(env, ctx->base.pc_next + 4); + target_long addr_off = extract32(ctx->opcode, 0, 16) | insn << 16; + switch (extract32(ctx->opcode, 16, 5)) { + case NM_LI48: + check_nms(ctx); + if (rt != 0) { + tcg_gen_movi_tl(cpu_gpr[rt], addr_off); + } + break; + case NM_ADDIU48: + check_nms(ctx); + if (rt != 0) { + tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rt], addr_off); + tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); + } + break; + case NM_ADDIUGP48: + check_nms(ctx); + if (rt != 0) { + gen_op_addr_addi(ctx, cpu_gpr[rt], cpu_gpr[28], addr_off); + } + break; + case NM_ADDIUPC48: + check_nms(ctx); + if (rt != 0) { + target_long addr = addr_add(ctx, ctx->base.pc_next + 6, + addr_off); + + tcg_gen_movi_tl(cpu_gpr[rt], addr); + } + break; + case NM_LWPC48: + check_nms(ctx); + if (rt != 0) { + TCGv t0; + t0 = tcg_temp_new(); + + target_long addr = addr_add(ctx, ctx->base.pc_next + 6, + addr_off); + + tcg_gen_movi_tl(t0, addr); + tcg_gen_qemu_ld_tl(cpu_gpr[rt], t0, ctx->mem_idx, MO_TESL); + tcg_temp_free(t0); + } + break; + case NM_SWPC48: + check_nms(ctx); + { + TCGv t0, t1; + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + target_long addr = addr_add(ctx, ctx->base.pc_next + 6, + addr_off); + + tcg_gen_movi_tl(t0, addr); + gen_load_gpr(t1, rt); + + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); + + tcg_temp_free(t0); + tcg_temp_free(t1); + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + return 6; + } + case NM_P_U12: + switch (extract32(ctx->opcode, 12, 4)) { + case NM_ORI: + gen_logic_imm(ctx, OPC_ORI, rt, rs, extract32(ctx->opcode, 0, 12)); + break; + case NM_XORI: + gen_logic_imm(ctx, OPC_XORI, rt, rs, extract32(ctx->opcode, 0, 12)); + break; + case NM_ANDI: + gen_logic_imm(ctx, OPC_ANDI, rt, rs, extract32(ctx->opcode, 0, 12)); + break; + case NM_P_SR: + switch (extract32(ctx->opcode, 20, 1)) { + case NM_PP_SR: + switch (ctx->opcode & 3) { + case NM_SAVE: + gen_save(ctx, rt, extract32(ctx->opcode, 16, 4), + extract32(ctx->opcode, 2, 1), + extract32(ctx->opcode, 3, 9) << 3); + break; + case NM_RESTORE: + case NM_RESTORE_JRC: + gen_restore(ctx, rt, extract32(ctx->opcode, 16, 4), + extract32(ctx->opcode, 2, 1), + extract32(ctx->opcode, 3, 9) << 3); + if ((ctx->opcode & 3) == NM_RESTORE_JRC) { + gen_compute_branch_nm(ctx, OPC_JR, 2, 31, 0, 0); + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_P_SR_F: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_SLTI: + gen_slt_imm(ctx, OPC_SLTI, rt, rs, extract32(ctx->opcode, 0, 12)); + break; + case NM_SLTIU: + gen_slt_imm(ctx, OPC_SLTIU, rt, rs, extract32(ctx->opcode, 0, 12)); + break; + case NM_SEQI: + { + TCGv t0 = tcg_temp_new(); + + imm = extract32(ctx->opcode, 0, 12); + gen_load_gpr(t0, rs); + tcg_gen_setcondi_tl(TCG_COND_EQ, t0, t0, imm); + gen_store_gpr(t0, rt); + + tcg_temp_free(t0); + } + break; + case NM_ADDIUNEG: + imm = (int16_t) extract32(ctx->opcode, 0, 12); + gen_arith_imm(ctx, OPC_ADDIU, rt, rs, -imm); + break; + case NM_P_SHIFT: + { + int shift = extract32(ctx->opcode, 0, 5); + switch (extract32(ctx->opcode, 5, 4)) { + case NM_P_SLL: + if (rt == 0 && shift == 0) { + /* NOP */ + } else if (rt == 0 && shift == 3) { + /* EHB - treat as NOP */ + } else if (rt == 0 && shift == 5) { + /* PAUSE - treat as NOP */ + } else if (rt == 0 && shift == 6) { + /* SYNC */ + gen_sync(extract32(ctx->opcode, 16, 5)); + } else { + /* SLL */ + gen_shift_imm(ctx, OPC_SLL, rt, rs, + extract32(ctx->opcode, 0, 5)); + } + break; + case NM_SRL: + gen_shift_imm(ctx, OPC_SRL, rt, rs, + extract32(ctx->opcode, 0, 5)); + break; + case NM_SRA: + gen_shift_imm(ctx, OPC_SRA, rt, rs, + extract32(ctx->opcode, 0, 5)); + break; + case NM_ROTR: + gen_shift_imm(ctx, OPC_ROTR, rt, rs, + extract32(ctx->opcode, 0, 5)); + break; + } + } + break; + case NM_P_ROTX: + check_nms(ctx); + if (rt != 0) { + TCGv t0 = tcg_temp_new(); + TCGv_i32 shift = tcg_const_i32(extract32(ctx->opcode, 0, 5)); + TCGv_i32 shiftx = tcg_const_i32(extract32(ctx->opcode, 7, 4) + << 1); + TCGv_i32 stripe = tcg_const_i32(extract32(ctx->opcode, 6, 1)); + + gen_load_gpr(t0, rs); + gen_helper_rotx(cpu_gpr[rt], t0, shift, shiftx, stripe); + tcg_temp_free(t0); + + tcg_temp_free_i32(shift); + tcg_temp_free_i32(shiftx); + tcg_temp_free_i32(stripe); + } + break; + case NM_P_INS: + switch (((ctx->opcode >> 10) & 2) | + (extract32(ctx->opcode, 5, 1))) { + case NM_INS: + check_nms(ctx); + gen_bitops(ctx, OPC_INS, rt, rs, extract32(ctx->opcode, 0, 5), + extract32(ctx->opcode, 6, 5)); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_P_EXT: + switch (((ctx->opcode >> 10) & 2) | + (extract32(ctx->opcode, 5, 1))) { + case NM_EXT: + check_nms(ctx); + gen_bitops(ctx, OPC_EXT, rt, rs, extract32(ctx->opcode, 0, 5), + extract32(ctx->opcode, 6, 5)); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_POOL32F: + gen_pool32f_nanomips_insn(ctx); + break; + case NM_POOL32S: + break; + case NM_P_LUI: + switch (extract32(ctx->opcode, 1, 1)) { + case NM_LUI: + if (rt != 0) { + tcg_gen_movi_tl(cpu_gpr[rt], + sextract32(ctx->opcode, 0, 1) << 31 | + extract32(ctx->opcode, 2, 10) << 21 | + extract32(ctx->opcode, 12, 9) << 12); + } + break; + case NM_ALUIPC: + if (rt != 0) { + offset = sextract32(ctx->opcode, 0, 1) << 31 | + extract32(ctx->opcode, 2, 10) << 21 | + extract32(ctx->opcode, 12, 9) << 12; + target_long addr; + addr = ~0xFFF & addr_add(ctx, ctx->base.pc_next + 4, offset); + tcg_gen_movi_tl(cpu_gpr[rt], addr); + } + break; + } + break; + case NM_P_GP_BH: + { + uint32_t u = extract32(ctx->opcode, 0, 18); + + switch (extract32(ctx->opcode, 18, 3)) { + case NM_LBGP: + gen_ld(ctx, OPC_LB, rt, 28, u); + break; + case NM_SBGP: + gen_st(ctx, OPC_SB, rt, 28, u); + break; + case NM_LBUGP: + gen_ld(ctx, OPC_LBU, rt, 28, u); + break; + case NM_ADDIUGP_B: + if (rt != 0) { + gen_op_addr_addi(ctx, cpu_gpr[rt], cpu_gpr[28], u); + } + break; + case NM_P_GP_LH: + u &= ~1; + switch (ctx->opcode & 1) { + case NM_LHGP: + gen_ld(ctx, OPC_LH, rt, 28, u); + break; + case NM_LHUGP: + gen_ld(ctx, OPC_LHU, rt, 28, u); + break; + } + break; + case NM_P_GP_SH: + u &= ~1; + switch (ctx->opcode & 1) { + case NM_SHGP: + gen_st(ctx, OPC_SH, rt, 28, u); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_P_GP_CP1: + u &= ~0x3; + switch (ctx->opcode & 0x3) { + case NM_LWC1GP: + gen_cop1_ldst(ctx, OPC_LWC1, rt, 28, u); + break; + case NM_LDC1GP: + gen_cop1_ldst(ctx, OPC_LDC1, rt, 28, u); + break; + case NM_SWC1GP: + gen_cop1_ldst(ctx, OPC_SWC1, rt, 28, u); + break; + case NM_SDC1GP: + gen_cop1_ldst(ctx, OPC_SDC1, rt, 28, u); + break; + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + } + break; + case NM_P_LS_U12: + { + uint32_t u = extract32(ctx->opcode, 0, 12); + + switch (extract32(ctx->opcode, 12, 4)) { + case NM_P_PREFU12: + if (rt == 31) { + /* SYNCI */ + /* + * Break the TB to be able to sync copied instructions + * immediately. + */ + ctx->base.is_jmp = DISAS_STOP; + } else { + /* PREF */ + /* Treat as NOP. */ + } + break; + case NM_LB: + gen_ld(ctx, OPC_LB, rt, rs, u); + break; + case NM_LH: + gen_ld(ctx, OPC_LH, rt, rs, u); + break; + case NM_LW: + gen_ld(ctx, OPC_LW, rt, rs, u); + break; + case NM_LBU: + gen_ld(ctx, OPC_LBU, rt, rs, u); + break; + case NM_LHU: + gen_ld(ctx, OPC_LHU, rt, rs, u); + break; + case NM_SB: + gen_st(ctx, OPC_SB, rt, rs, u); + break; + case NM_SH: + gen_st(ctx, OPC_SH, rt, rs, u); + break; + case NM_SW: + gen_st(ctx, OPC_SW, rt, rs, u); + break; + case NM_LWC1: + gen_cop1_ldst(ctx, OPC_LWC1, rt, rs, u); + break; + case NM_LDC1: + gen_cop1_ldst(ctx, OPC_LDC1, rt, rs, u); + break; + case NM_SWC1: + gen_cop1_ldst(ctx, OPC_SWC1, rt, rs, u); + break; + case NM_SDC1: + gen_cop1_ldst(ctx, OPC_SDC1, rt, rs, u); + break; + default: + gen_reserved_instruction(ctx); + break; + } + } + break; + case NM_P_LS_S9: + { + int32_t s = (sextract32(ctx->opcode, 15, 1) << 8) | + extract32(ctx->opcode, 0, 8); + + switch (extract32(ctx->opcode, 8, 3)) { + case NM_P_LS_S0: + switch (extract32(ctx->opcode, 11, 4)) { + case NM_LBS9: + gen_ld(ctx, OPC_LB, rt, rs, s); + break; + case NM_LHS9: + gen_ld(ctx, OPC_LH, rt, rs, s); + break; + case NM_LWS9: + gen_ld(ctx, OPC_LW, rt, rs, s); + break; + case NM_LBUS9: + gen_ld(ctx, OPC_LBU, rt, rs, s); + break; + case NM_LHUS9: + gen_ld(ctx, OPC_LHU, rt, rs, s); + break; + case NM_SBS9: + gen_st(ctx, OPC_SB, rt, rs, s); + break; + case NM_SHS9: + gen_st(ctx, OPC_SH, rt, rs, s); + break; + case NM_SWS9: + gen_st(ctx, OPC_SW, rt, rs, s); + break; + case NM_LWC1S9: + gen_cop1_ldst(ctx, OPC_LWC1, rt, rs, s); + break; + case NM_LDC1S9: + gen_cop1_ldst(ctx, OPC_LDC1, rt, rs, s); + break; + case NM_SWC1S9: + gen_cop1_ldst(ctx, OPC_SWC1, rt, rs, s); + break; + case NM_SDC1S9: + gen_cop1_ldst(ctx, OPC_SDC1, rt, rs, s); + break; + case NM_P_PREFS9: + if (rt == 31) { + /* SYNCI */ + /* + * Break the TB to be able to sync copied instructions + * immediately. + */ + ctx->base.is_jmp = DISAS_STOP; + } else { + /* PREF */ + /* Treat as NOP. */ + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_P_LS_S1: + switch (extract32(ctx->opcode, 11, 4)) { + case NM_UALH: + case NM_UASH: + check_nms(ctx); + { + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + gen_base_offset_addr(ctx, t0, rs, s); + + switch (extract32(ctx->opcode, 11, 4)) { + case NM_UALH: + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW | + MO_UNALN); + gen_store_gpr(t0, rt); + break; + case NM_UASH: + gen_load_gpr(t1, rt); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW | + MO_UNALN); + break; + } + tcg_temp_free(t0); + tcg_temp_free(t1); + } + break; + case NM_P_LL: + switch (ctx->opcode & 0x03) { + case NM_LL: + gen_ld(ctx, OPC_LL, rt, rs, s); + break; + case NM_LLWP: + check_xnp(ctx); + gen_llwp(ctx, rs, 0, rt, extract32(ctx->opcode, 3, 5)); + break; + } + break; + case NM_P_SC: + switch (ctx->opcode & 0x03) { + case NM_SC: + gen_st_cond(ctx, rt, rs, s, MO_TESL, false); + break; + case NM_SCWP: + check_xnp(ctx); + gen_scwp(ctx, rs, 0, rt, extract32(ctx->opcode, 3, 5), + false); + break; + } + break; + case NM_CACHE: + check_cp0_enabled(ctx); + if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) { + gen_cache_operation(ctx, rt, rs, s); + } + break; + } + break; + case NM_P_LS_E0: + switch (extract32(ctx->opcode, 11, 4)) { + case NM_LBE: + check_eva(ctx); + check_cp0_enabled(ctx); + gen_ld(ctx, OPC_LBE, rt, rs, s); + break; + case NM_SBE: + check_eva(ctx); + check_cp0_enabled(ctx); + gen_st(ctx, OPC_SBE, rt, rs, s); + break; + case NM_LBUE: + check_eva(ctx); + check_cp0_enabled(ctx); + gen_ld(ctx, OPC_LBUE, rt, rs, s); + break; + case NM_P_PREFE: + if (rt == 31) { + /* case NM_SYNCIE */ + check_eva(ctx); + check_cp0_enabled(ctx); + /* + * Break the TB to be able to sync copied instructions + * immediately. + */ + ctx->base.is_jmp = DISAS_STOP; + } else { + /* case NM_PREFE */ + check_eva(ctx); + check_cp0_enabled(ctx); + /* Treat as NOP. */ + } + break; + case NM_LHE: + check_eva(ctx); + check_cp0_enabled(ctx); + gen_ld(ctx, OPC_LHE, rt, rs, s); + break; + case NM_SHE: + check_eva(ctx); + check_cp0_enabled(ctx); + gen_st(ctx, OPC_SHE, rt, rs, s); + break; + case NM_LHUE: + check_eva(ctx); + check_cp0_enabled(ctx); + gen_ld(ctx, OPC_LHUE, rt, rs, s); + break; + case NM_CACHEE: + check_eva(ctx); + check_cp0_enabled(ctx); + check_nms_dl_il_sl_tl_l2c(ctx); + gen_cache_operation(ctx, rt, rs, s); + break; + case NM_LWE: + check_eva(ctx); + check_cp0_enabled(ctx); + gen_ld(ctx, OPC_LWE, rt, rs, s); + break; + case NM_SWE: + check_eva(ctx); + check_cp0_enabled(ctx); + gen_st(ctx, OPC_SWE, rt, rs, s); + break; + case NM_P_LLE: + switch (extract32(ctx->opcode, 2, 2)) { + case NM_LLE: + check_xnp(ctx); + check_eva(ctx); + check_cp0_enabled(ctx); + gen_ld(ctx, OPC_LLE, rt, rs, s); + break; + case NM_LLWPE: + check_xnp(ctx); + check_eva(ctx); + check_cp0_enabled(ctx); + gen_llwp(ctx, rs, 0, rt, extract32(ctx->opcode, 3, 5)); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_P_SCE: + switch (extract32(ctx->opcode, 2, 2)) { + case NM_SCE: + check_xnp(ctx); + check_eva(ctx); + check_cp0_enabled(ctx); + gen_st_cond(ctx, rt, rs, s, MO_TESL, true); + break; + case NM_SCWPE: + check_xnp(ctx); + check_eva(ctx); + check_cp0_enabled(ctx); + gen_scwp(ctx, rs, 0, rt, extract32(ctx->opcode, 3, 5), + true); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + } + break; + case NM_P_LS_WM: + case NM_P_LS_UAWM: + check_nms(ctx); + { + int count = extract32(ctx->opcode, 12, 3); + int counter = 0; + + offset = sextract32(ctx->opcode, 15, 1) << 8 | + extract32(ctx->opcode, 0, 8); + TCGv va = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + MemOp memop = (extract32(ctx->opcode, 8, 3)) == + NM_P_LS_UAWM ? MO_UNALN : 0; + + count = (count == 0) ? 8 : count; + while (counter != count) { + int this_rt = ((rt + counter) & 0x1f) | (rt & 0x10); + int this_offset = offset + (counter << 2); + + gen_base_offset_addr(ctx, va, rs, this_offset); + + switch (extract32(ctx->opcode, 11, 1)) { + case NM_LWM: + tcg_gen_qemu_ld_tl(t1, va, ctx->mem_idx, + memop | MO_TESL); + gen_store_gpr(t1, this_rt); + if ((this_rt == rs) && + (counter != (count - 1))) { + /* UNPREDICTABLE */ + } + break; + case NM_SWM: + this_rt = (rt == 0) ? 0 : this_rt; + gen_load_gpr(t1, this_rt); + tcg_gen_qemu_st_tl(t1, va, ctx->mem_idx, + memop | MO_TEUL); + break; + } + counter++; + } + tcg_temp_free(va); + tcg_temp_free(t1); + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + } + break; + case NM_MOVE_BALC: + check_nms(ctx); + { + TCGv t0 = tcg_temp_new(); + int32_t s = sextract32(ctx->opcode, 0, 1) << 21 | + extract32(ctx->opcode, 1, 20) << 1; + rd = (extract32(ctx->opcode, 24, 1)) == 0 ? 4 : 5; + rt = decode_gpr_gpr4_zero(extract32(ctx->opcode, 25, 1) << 3 | + extract32(ctx->opcode, 21, 3)); + gen_load_gpr(t0, rt); + tcg_gen_mov_tl(cpu_gpr[rd], t0); + gen_compute_branch_nm(ctx, OPC_BGEZAL, 4, 0, 0, s); + tcg_temp_free(t0); + } + break; + case NM_P_BAL: + { + int32_t s = sextract32(ctx->opcode, 0, 1) << 25 | + extract32(ctx->opcode, 1, 24) << 1; + + if ((extract32(ctx->opcode, 25, 1)) == 0) { + /* BC */ + gen_compute_branch_nm(ctx, OPC_BEQ, 4, 0, 0, s); + } else { + /* BALC */ + gen_compute_branch_nm(ctx, OPC_BGEZAL, 4, 0, 0, s); + } + } + break; + case NM_P_J: + switch (extract32(ctx->opcode, 12, 4)) { + case NM_JALRC: + case NM_JALRC_HB: + gen_compute_branch_nm(ctx, OPC_JALR, 4, rs, rt, 0); + break; + case NM_P_BALRSC: + gen_compute_nanomips_pbalrsc_branch(ctx, rs, rt); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_P_BR1: + { + int32_t s = sextract32(ctx->opcode, 0, 1) << 14 | + extract32(ctx->opcode, 1, 13) << 1; + switch (extract32(ctx->opcode, 14, 2)) { + case NM_BEQC: + check_nms(ctx); + gen_compute_branch_nm(ctx, OPC_BEQ, 4, rs, rt, s); + break; + case NM_P_BR3A: + s = sextract32(ctx->opcode, 0, 1) << 14 | + extract32(ctx->opcode, 1, 13) << 1; + check_cp1_enabled(ctx); + switch (extract32(ctx->opcode, 16, 5)) { + case NM_BC1EQZC: + gen_compute_branch_cp1_nm(ctx, OPC_BC1EQZ, rt, s); + break; + case NM_BC1NEZC: + gen_compute_branch_cp1_nm(ctx, OPC_BC1NEZ, rt, s); + break; + case NM_BPOSGE32C: + check_dsp_r3(ctx); + { + int32_t imm = extract32(ctx->opcode, 1, 13) | + extract32(ctx->opcode, 0, 1) << 13; + + gen_compute_branch_nm(ctx, OPC_BPOSGE32, 4, -1, -2, + imm << 1); + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_BGEC: + if (rs == rt) { + gen_compute_compact_branch_nm(ctx, OPC_BC, rs, rt, s); + } else { + gen_compute_compact_branch_nm(ctx, OPC_BGEC, rs, rt, s); + } + break; + case NM_BGEUC: + if (rs == rt || rt == 0) { + gen_compute_compact_branch_nm(ctx, OPC_BC, 0, 0, s); + } else if (rs == 0) { + gen_compute_compact_branch_nm(ctx, OPC_BEQZC, rt, 0, s); + } else { + gen_compute_compact_branch_nm(ctx, OPC_BGEUC, rs, rt, s); + } + break; + } + } + break; + case NM_P_BR2: + { + int32_t s = sextract32(ctx->opcode, 0, 1) << 14 | + extract32(ctx->opcode, 1, 13) << 1; + switch (extract32(ctx->opcode, 14, 2)) { + case NM_BNEC: + check_nms(ctx); + gen_compute_branch_nm(ctx, OPC_BNE, 4, rs, rt, s); + break; + case NM_BLTC: + if (rs != 0 && rt != 0 && rs == rt) { + /* NOP */ + ctx->hflags |= MIPS_HFLAG_FBNSLOT; + } else { + gen_compute_compact_branch_nm(ctx, OPC_BLTC, rs, rt, s); + } + break; + case NM_BLTUC: + if (rs == 0 || rs == rt) { + /* NOP */ + ctx->hflags |= MIPS_HFLAG_FBNSLOT; + } else { + gen_compute_compact_branch_nm(ctx, OPC_BLTUC, rs, rt, s); + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + } + break; + case NM_P_BRI: + { + int32_t s = sextract32(ctx->opcode, 0, 1) << 11 | + extract32(ctx->opcode, 1, 10) << 1; + uint32_t u = extract32(ctx->opcode, 11, 7); + + gen_compute_imm_branch(ctx, extract32(ctx->opcode, 18, 3), + rt, u, s); + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + return 4; +} + +static int decode_isa_nanomips(CPUMIPSState *env, DisasContext *ctx) +{ + uint32_t op; + int rt = decode_gpr_gpr3(NANOMIPS_EXTRACT_RT3(ctx->opcode)); + int rs = decode_gpr_gpr3(NANOMIPS_EXTRACT_RS3(ctx->opcode)); + int rd = decode_gpr_gpr3(NANOMIPS_EXTRACT_RD3(ctx->opcode)); + int offset; + int imm; + + /* make sure instructions are on a halfword boundary */ + if (ctx->base.pc_next & 0x1) { + TCGv tmp = tcg_const_tl(ctx->base.pc_next); + tcg_gen_st_tl(tmp, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr)); + tcg_temp_free(tmp); + generate_exception_end(ctx, EXCP_AdEL); + return 2; + } + + op = extract32(ctx->opcode, 10, 6); + switch (op) { + case NM_P16_MV: + rt = NANOMIPS_EXTRACT_RD5(ctx->opcode); + if (rt != 0) { + /* MOVE */ + rs = NANOMIPS_EXTRACT_RS5(ctx->opcode); + gen_arith(ctx, OPC_ADDU, rt, rs, 0); + } else { + /* P16.RI */ + switch (extract32(ctx->opcode, 3, 2)) { + case NM_P16_SYSCALL: + if (extract32(ctx->opcode, 2, 1) == 0) { + generate_exception_end(ctx, EXCP_SYSCALL); + } else { + gen_reserved_instruction(ctx); + } + break; + case NM_BREAK16: + generate_exception_end(ctx, EXCP_BREAK); + break; + case NM_SDBBP16: + if (is_uhi(extract32(ctx->opcode, 0, 3))) { + gen_helper_do_semihosting(cpu_env); + } else { + if (ctx->hflags & MIPS_HFLAG_SBRI) { + gen_reserved_instruction(ctx); + } else { + generate_exception_end(ctx, EXCP_DBp); + } + } + break; + default: + gen_reserved_instruction(ctx); + break; + } + } + break; + case NM_P16_SHIFT: + { + int shift = extract32(ctx->opcode, 0, 3); + uint32_t opc = 0; + shift = (shift == 0) ? 8 : shift; + + switch (extract32(ctx->opcode, 3, 1)) { + case NM_SLL16: + opc = OPC_SLL; + break; + case NM_SRL16: + opc = OPC_SRL; + break; + } + gen_shift_imm(ctx, opc, rt, rs, shift); + } + break; + case NM_P16C: + switch (ctx->opcode & 1) { + case NM_POOL16C_0: + gen_pool16c_nanomips_insn(ctx); + break; + case NM_LWXS16: + gen_ldxs(ctx, rt, rs, rd); + break; + } + break; + case NM_P16_A1: + switch (extract32(ctx->opcode, 6, 1)) { + case NM_ADDIUR1SP: + imm = extract32(ctx->opcode, 0, 6) << 2; + gen_arith_imm(ctx, OPC_ADDIU, rt, 29, imm); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_P16_A2: + switch (extract32(ctx->opcode, 3, 1)) { + case NM_ADDIUR2: + imm = extract32(ctx->opcode, 0, 3) << 2; + gen_arith_imm(ctx, OPC_ADDIU, rt, rs, imm); + break; + case NM_P_ADDIURS5: + rt = extract32(ctx->opcode, 5, 5); + if (rt != 0) { + /* imm = sign_extend(s[3] . s[2:0] , from_nbits = 4) */ + imm = (sextract32(ctx->opcode, 4, 1) << 3) | + (extract32(ctx->opcode, 0, 3)); + gen_arith_imm(ctx, OPC_ADDIU, rt, rt, imm); + } + break; + } + break; + case NM_P16_ADDU: + switch (ctx->opcode & 0x1) { + case NM_ADDU16: + gen_arith(ctx, OPC_ADDU, rd, rs, rt); + break; + case NM_SUBU16: + gen_arith(ctx, OPC_SUBU, rd, rs, rt); + break; + } + break; + case NM_P16_4X4: + rt = (extract32(ctx->opcode, 9, 1) << 3) | + extract32(ctx->opcode, 5, 3); + rs = (extract32(ctx->opcode, 4, 1) << 3) | + extract32(ctx->opcode, 0, 3); + rt = decode_gpr_gpr4(rt); + rs = decode_gpr_gpr4(rs); + switch ((extract32(ctx->opcode, 7, 2) & 0x2) | + (extract32(ctx->opcode, 3, 1))) { + case NM_ADDU4X4: + check_nms(ctx); + gen_arith(ctx, OPC_ADDU, rt, rs, rt); + break; + case NM_MUL4X4: + check_nms(ctx); + gen_r6_muldiv(ctx, R6_OPC_MUL, rt, rs, rt); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_LI16: + { + int imm = extract32(ctx->opcode, 0, 7); + imm = (imm == 0x7f ? -1 : imm); + if (rt != 0) { + tcg_gen_movi_tl(cpu_gpr[rt], imm); + } + } + break; + case NM_ANDI16: + { + uint32_t u = extract32(ctx->opcode, 0, 4); + u = (u == 12) ? 0xff : + (u == 13) ? 0xffff : u; + gen_logic_imm(ctx, OPC_ANDI, rt, rs, u); + } + break; + case NM_P16_LB: + offset = extract32(ctx->opcode, 0, 2); + switch (extract32(ctx->opcode, 2, 2)) { + case NM_LB16: + gen_ld(ctx, OPC_LB, rt, rs, offset); + break; + case NM_SB16: + rt = decode_gpr_gpr3_src_store( + NANOMIPS_EXTRACT_RT3(ctx->opcode)); + gen_st(ctx, OPC_SB, rt, rs, offset); + break; + case NM_LBU16: + gen_ld(ctx, OPC_LBU, rt, rs, offset); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_P16_LH: + offset = extract32(ctx->opcode, 1, 2) << 1; + switch ((extract32(ctx->opcode, 3, 1) << 1) | (ctx->opcode & 1)) { + case NM_LH16: + gen_ld(ctx, OPC_LH, rt, rs, offset); + break; + case NM_SH16: + rt = decode_gpr_gpr3_src_store( + NANOMIPS_EXTRACT_RT3(ctx->opcode)); + gen_st(ctx, OPC_SH, rt, rs, offset); + break; + case NM_LHU16: + gen_ld(ctx, OPC_LHU, rt, rs, offset); + break; + default: + gen_reserved_instruction(ctx); + break; + } + break; + case NM_LW16: + offset = extract32(ctx->opcode, 0, 4) << 2; + gen_ld(ctx, OPC_LW, rt, rs, offset); + break; + case NM_LWSP16: + rt = NANOMIPS_EXTRACT_RD5(ctx->opcode); + offset = extract32(ctx->opcode, 0, 5) << 2; + gen_ld(ctx, OPC_LW, rt, 29, offset); + break; + case NM_LW4X4: + check_nms(ctx); + rt = (extract32(ctx->opcode, 9, 1) << 3) | + extract32(ctx->opcode, 5, 3); + rs = (extract32(ctx->opcode, 4, 1) << 3) | + extract32(ctx->opcode, 0, 3); + offset = (extract32(ctx->opcode, 3, 1) << 3) | + (extract32(ctx->opcode, 8, 1) << 2); + rt = decode_gpr_gpr4(rt); + rs = decode_gpr_gpr4(rs); + gen_ld(ctx, OPC_LW, rt, rs, offset); + break; + case NM_SW4X4: + check_nms(ctx); + rt = (extract32(ctx->opcode, 9, 1) << 3) | + extract32(ctx->opcode, 5, 3); + rs = (extract32(ctx->opcode, 4, 1) << 3) | + extract32(ctx->opcode, 0, 3); + offset = (extract32(ctx->opcode, 3, 1) << 3) | + (extract32(ctx->opcode, 8, 1) << 2); + rt = decode_gpr_gpr4_zero(rt); + rs = decode_gpr_gpr4(rs); + gen_st(ctx, OPC_SW, rt, rs, offset); + break; + case NM_LWGP16: + offset = extract32(ctx->opcode, 0, 7) << 2; + gen_ld(ctx, OPC_LW, rt, 28, offset); + break; + case NM_SWSP16: + rt = NANOMIPS_EXTRACT_RD5(ctx->opcode); + offset = extract32(ctx->opcode, 0, 5) << 2; + gen_st(ctx, OPC_SW, rt, 29, offset); + break; + case NM_SW16: + rt = decode_gpr_gpr3_src_store( + NANOMIPS_EXTRACT_RT3(ctx->opcode)); + rs = decode_gpr_gpr3(NANOMIPS_EXTRACT_RS3(ctx->opcode)); + offset = extract32(ctx->opcode, 0, 4) << 2; + gen_st(ctx, OPC_SW, rt, rs, offset); + break; + case NM_SWGP16: + rt = decode_gpr_gpr3_src_store( + NANOMIPS_EXTRACT_RT3(ctx->opcode)); + offset = extract32(ctx->opcode, 0, 7) << 2; + gen_st(ctx, OPC_SW, rt, 28, offset); + break; + case NM_BC16: + gen_compute_branch_nm(ctx, OPC_BEQ, 2, 0, 0, + (sextract32(ctx->opcode, 0, 1) << 10) | + (extract32(ctx->opcode, 1, 9) << 1)); + break; + case NM_BALC16: + gen_compute_branch_nm(ctx, OPC_BGEZAL, 2, 0, 0, + (sextract32(ctx->opcode, 0, 1) << 10) | + (extract32(ctx->opcode, 1, 9) << 1)); + break; + case NM_BEQZC16: + gen_compute_branch_nm(ctx, OPC_BEQ, 2, rt, 0, + (sextract32(ctx->opcode, 0, 1) << 7) | + (extract32(ctx->opcode, 1, 6) << 1)); + break; + case NM_BNEZC16: + gen_compute_branch_nm(ctx, OPC_BNE, 2, rt, 0, + (sextract32(ctx->opcode, 0, 1) << 7) | + (extract32(ctx->opcode, 1, 6) << 1)); + break; + case NM_P16_BR: + switch (ctx->opcode & 0xf) { + case 0: + /* P16.JRC */ + switch (extract32(ctx->opcode, 4, 1)) { + case NM_JRC: + gen_compute_branch_nm(ctx, OPC_JR, 2, + extract32(ctx->opcode, 5, 5), 0, 0); + break; + case NM_JALRC16: + gen_compute_branch_nm(ctx, OPC_JALR, 2, + extract32(ctx->opcode, 5, 5), 31, 0); + break; + } + break; + default: + { + /* P16.BRI */ + uint32_t opc = extract32(ctx->opcode, 4, 3) < + extract32(ctx->opcode, 7, 3) ? OPC_BEQ : OPC_BNE; + gen_compute_branch_nm(ctx, opc, 2, rs, rt, + extract32(ctx->opcode, 0, 4) << 1); + } + break; + } + break; + case NM_P16_SR: + { + int count = extract32(ctx->opcode, 0, 4); + int u = extract32(ctx->opcode, 4, 4) << 4; + + rt = 30 + extract32(ctx->opcode, 9, 1); + switch (extract32(ctx->opcode, 8, 1)) { + case NM_SAVE16: + gen_save(ctx, rt, count, 0, u); + break; + case NM_RESTORE_JRC16: + gen_restore(ctx, rt, count, 0, u); + gen_compute_branch_nm(ctx, OPC_JR, 2, 31, 0, 0); + break; + } + } + break; + case NM_MOVEP: + case NM_MOVEPREV: + check_nms(ctx); + { + static const int gpr2reg1[] = {4, 5, 6, 7}; + static const int gpr2reg2[] = {5, 6, 7, 8}; + int re; + int rd2 = extract32(ctx->opcode, 3, 1) << 1 | + extract32(ctx->opcode, 8, 1); + int r1 = gpr2reg1[rd2]; + int r2 = gpr2reg2[rd2]; + int r3 = extract32(ctx->opcode, 4, 1) << 3 | + extract32(ctx->opcode, 0, 3); + int r4 = extract32(ctx->opcode, 9, 1) << 3 | + extract32(ctx->opcode, 5, 3); + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + if (op == NM_MOVEP) { + rd = r1; + re = r2; + rs = decode_gpr_gpr4_zero(r3); + rt = decode_gpr_gpr4_zero(r4); + } else { + rd = decode_gpr_gpr4(r3); + re = decode_gpr_gpr4(r4); + rs = r1; + rt = r2; + } + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + tcg_gen_mov_tl(cpu_gpr[rd], t0); + tcg_gen_mov_tl(cpu_gpr[re], t1); + tcg_temp_free(t0); + tcg_temp_free(t1); + } + break; + default: + return decode_nanomips_32_48_opc(env, ctx); + } + + return 2; +} diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index b4a454e..ae33c75 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -2278,31 +2278,6 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, tcg_temp_free(t0); } -static void gen_llwp(DisasContext *ctx, uint32_t base, int16_t offset, - uint32_t reg1, uint32_t reg2) -{ - TCGv taddr = tcg_temp_new(); - TCGv_i64 tval = tcg_temp_new_i64(); - TCGv tmp1 = tcg_temp_new(); - TCGv tmp2 = tcg_temp_new(); - - gen_base_offset_addr(ctx, taddr, base, offset); - tcg_gen_qemu_ld64(tval, taddr, ctx->mem_idx); -#ifdef TARGET_WORDS_BIGENDIAN - tcg_gen_extr_i64_tl(tmp2, tmp1, tval); -#else - tcg_gen_extr_i64_tl(tmp1, tmp2, tval); -#endif - gen_store_gpr(tmp1, reg1); - tcg_temp_free(tmp1); - gen_store_gpr(tmp2, reg2); - tcg_temp_free(tmp2); - tcg_gen_st_i64(tval, cpu_env, offsetof(CPUMIPSState, llval_wp)); - tcg_temp_free_i64(tval); - tcg_gen_st_tl(taddr, cpu_env, offsetof(CPUMIPSState, lladdr)); - tcg_temp_free(taddr); -} - /* Store */ static void gen_st(DisasContext *ctx, uint32_t opc, int rt, int base, int offset) @@ -2396,52 +2371,6 @@ static void gen_st_cond(DisasContext *ctx, int rt, int base, int offset, tcg_temp_free(t0); } - -static void gen_scwp(DisasContext *ctx, uint32_t base, int16_t offset, - uint32_t reg1, uint32_t reg2, bool eva) -{ - TCGv taddr = tcg_temp_local_new(); - TCGv lladdr = tcg_temp_local_new(); - TCGv_i64 tval = tcg_temp_new_i64(); - TCGv_i64 llval = tcg_temp_new_i64(); - TCGv_i64 val = tcg_temp_new_i64(); - TCGv tmp1 = tcg_temp_new(); - TCGv tmp2 = tcg_temp_new(); - TCGLabel *lab_fail = gen_new_label(); - TCGLabel *lab_done = gen_new_label(); - - gen_base_offset_addr(ctx, taddr, base, offset); - - tcg_gen_ld_tl(lladdr, cpu_env, offsetof(CPUMIPSState, lladdr)); - tcg_gen_brcond_tl(TCG_COND_NE, taddr, lladdr, lab_fail); - - gen_load_gpr(tmp1, reg1); - gen_load_gpr(tmp2, reg2); - -#ifdef TARGET_WORDS_BIGENDIAN - tcg_gen_concat_tl_i64(tval, tmp2, tmp1); -#else - tcg_gen_concat_tl_i64(tval, tmp1, tmp2); -#endif - - tcg_gen_ld_i64(llval, cpu_env, offsetof(CPUMIPSState, llval_wp)); - tcg_gen_atomic_cmpxchg_i64(val, taddr, llval, tval, - eva ? MIPS_HFLAG_UM : ctx->mem_idx, MO_64); - if (reg1 != 0) { - tcg_gen_movi_tl(cpu_gpr[reg1], 1); - } - tcg_gen_brcond_i64(TCG_COND_EQ, val, llval, lab_done); - - gen_set_label(lab_fail); - - if (reg1 != 0) { - tcg_gen_movi_tl(cpu_gpr[reg1], 0); - } - gen_set_label(lab_done); - tcg_gen_movi_tl(lladdr, -1); - tcg_gen_st_tl(lladdr, cpu_env, offsetof(CPUMIPSState, lladdr)); -} - /* Load and store */ static void gen_flt_ldst(DisasContext *ctx, uint32_t opc, int ft, TCGv t0) @@ -5304,129 +5233,6 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc, } -/* nanoMIPS Branches */ -static void gen_compute_branch_nm(DisasContext *ctx, uint32_t opc, - int insn_bytes, - int rs, int rt, int32_t offset) -{ - target_ulong btgt = -1; - int bcond_compute = 0; - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - - /* Load needed operands */ - switch (opc) { - case OPC_BEQ: - case OPC_BNE: - /* Compare two registers */ - if (rs != rt) { - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - bcond_compute = 1; - } - btgt = ctx->base.pc_next + insn_bytes + offset; - break; - case OPC_BGEZAL: - /* Compare to zero */ - if (rs != 0) { - gen_load_gpr(t0, rs); - bcond_compute = 1; - } - btgt = ctx->base.pc_next + insn_bytes + offset; - break; - case OPC_BPOSGE32: - tcg_gen_andi_tl(t0, cpu_dspctrl, 0x3F); - bcond_compute = 1; - btgt = ctx->base.pc_next + insn_bytes + offset; - break; - case OPC_JR: - case OPC_JALR: - /* Jump to register */ - if (offset != 0 && offset != 16) { - /* - * Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the - * others are reserved. - */ - MIPS_INVAL("jump hint"); - gen_reserved_instruction(ctx); - goto out; - } - gen_load_gpr(btarget, rs); - break; - default: - MIPS_INVAL("branch/jump"); - gen_reserved_instruction(ctx); - goto out; - } - if (bcond_compute == 0) { - /* No condition to be computed */ - switch (opc) { - case OPC_BEQ: /* rx == rx */ - /* Always take */ - ctx->hflags |= MIPS_HFLAG_B; - break; - case OPC_BGEZAL: /* 0 >= 0 */ - /* Always take and link */ - tcg_gen_movi_tl(cpu_gpr[31], - ctx->base.pc_next + insn_bytes); - ctx->hflags |= MIPS_HFLAG_B; - break; - case OPC_BNE: /* rx != rx */ - tcg_gen_movi_tl(cpu_gpr[31], ctx->base.pc_next + 8); - /* Skip the instruction in the delay slot */ - ctx->base.pc_next += 4; - goto out; - case OPC_JR: - ctx->hflags |= MIPS_HFLAG_BR; - break; - case OPC_JALR: - if (rt > 0) { - tcg_gen_movi_tl(cpu_gpr[rt], - ctx->base.pc_next + insn_bytes); - } - ctx->hflags |= MIPS_HFLAG_BR; - break; - default: - MIPS_INVAL("branch/jump"); - gen_reserved_instruction(ctx); - goto out; - } - } else { - switch (opc) { - case OPC_BEQ: - tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); - goto not_likely; - case OPC_BNE: - tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); - goto not_likely; - case OPC_BGEZAL: - tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); - tcg_gen_movi_tl(cpu_gpr[31], - ctx->base.pc_next + insn_bytes); - goto not_likely; - case OPC_BPOSGE32: - tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 32); - not_likely: - ctx->hflags |= MIPS_HFLAG_BC; - break; - default: - MIPS_INVAL("conditional branch/jump"); - gen_reserved_instruction(ctx); - goto out; - } - } - - ctx->btarget = btgt; - - out: - if (insn_bytes == 2) { - ctx->hflags |= MIPS_HFLAG_B16; - } - tcg_temp_free(t0); - tcg_temp_free(t1); -} - - /* special3 bitfield operations */ static void gen_bitops(DisasContext *ctx, uint32_t opc, int rt, int rs, int lsb, int msb) @@ -5629,18 +5435,11 @@ static void gen_align_bits(DisasContext *ctx, int wordsz, int rd, int rs, tcg_temp_free(t0); } -static void gen_align(DisasContext *ctx, int wordsz, int rd, int rs, int rt, - int bp) +void gen_align(DisasContext *ctx, int wordsz, int rd, int rs, int rt, int bp) { gen_align_bits(ctx, wordsz, rd, rs, rt, bp * 8); } -static void gen_ext(DisasContext *ctx, int wordsz, int rd, int rs, int rt, - int shift) -{ - gen_align_bits(ctx, wordsz, rd, rs, rt, wordsz - shift); -} - static void gen_bitswap(DisasContext *ctx, int opc, int rd, int rt) { TCGv t0; @@ -12393,393 +12192,8 @@ out: tcg_temp_free(t1); } -/* ISA extensions (ASEs) */ -/* MIPS16 extension to MIPS32 */ - -/* MIPS16 major opcodes */ -enum { - M16_OPC_ADDIUSP = 0x00, - M16_OPC_ADDIUPC = 0x01, - M16_OPC_B = 0x02, - M16_OPC_JAL = 0x03, - M16_OPC_BEQZ = 0x04, - M16_OPC_BNEQZ = 0x05, - M16_OPC_SHIFT = 0x06, - M16_OPC_LD = 0x07, - M16_OPC_RRIA = 0x08, - M16_OPC_ADDIU8 = 0x09, - M16_OPC_SLTI = 0x0a, - M16_OPC_SLTIU = 0x0b, - M16_OPC_I8 = 0x0c, - M16_OPC_LI = 0x0d, - M16_OPC_CMPI = 0x0e, - M16_OPC_SD = 0x0f, - M16_OPC_LB = 0x10, - M16_OPC_LH = 0x11, - M16_OPC_LWSP = 0x12, - M16_OPC_LW = 0x13, - M16_OPC_LBU = 0x14, - M16_OPC_LHU = 0x15, - M16_OPC_LWPC = 0x16, - M16_OPC_LWU = 0x17, - M16_OPC_SB = 0x18, - M16_OPC_SH = 0x19, - M16_OPC_SWSP = 0x1a, - M16_OPC_SW = 0x1b, - M16_OPC_RRR = 0x1c, - M16_OPC_RR = 0x1d, - M16_OPC_EXTEND = 0x1e, - M16_OPC_I64 = 0x1f -}; - -/* I8 funct field */ -enum { - I8_BTEQZ = 0x0, - I8_BTNEZ = 0x1, - I8_SWRASP = 0x2, - I8_ADJSP = 0x3, - I8_SVRS = 0x4, - I8_MOV32R = 0x5, - I8_MOVR32 = 0x7 -}; - -/* RRR f field */ -enum { - RRR_DADDU = 0x0, - RRR_ADDU = 0x1, - RRR_DSUBU = 0x2, - RRR_SUBU = 0x3 -}; - -/* RR funct field */ -enum { - RR_JR = 0x00, - RR_SDBBP = 0x01, - RR_SLT = 0x02, - RR_SLTU = 0x03, - RR_SLLV = 0x04, - RR_BREAK = 0x05, - RR_SRLV = 0x06, - RR_SRAV = 0x07, - RR_DSRL = 0x08, - RR_CMP = 0x0a, - RR_NEG = 0x0b, - RR_AND = 0x0c, - RR_OR = 0x0d, - RR_XOR = 0x0e, - RR_NOT = 0x0f, - RR_MFHI = 0x10, - RR_CNVT = 0x11, - RR_MFLO = 0x12, - RR_DSRA = 0x13, - RR_DSLLV = 0x14, - RR_DSRLV = 0x16, - RR_DSRAV = 0x17, - RR_MULT = 0x18, - RR_MULTU = 0x19, - RR_DIV = 0x1a, - RR_DIVU = 0x1b, - RR_DMULT = 0x1c, - RR_DMULTU = 0x1d, - RR_DDIV = 0x1e, - RR_DDIVU = 0x1f -}; - -/* I64 funct field */ -enum { - I64_LDSP = 0x0, - I64_SDSP = 0x1, - I64_SDRASP = 0x2, - I64_DADJSP = 0x3, - I64_LDPC = 0x4, - I64_DADDIU5 = 0x5, - I64_DADDIUPC = 0x6, - I64_DADDIUSP = 0x7 -}; - -/* RR ry field for CNVT */ -enum { - RR_RY_CNVT_ZEB = 0x0, - RR_RY_CNVT_ZEH = 0x1, - RR_RY_CNVT_ZEW = 0x2, - RR_RY_CNVT_SEB = 0x4, - RR_RY_CNVT_SEH = 0x5, - RR_RY_CNVT_SEW = 0x6, -}; - -static int xlat(int r) -{ - static int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 }; - - return map[r]; -} - -static void gen_mips16_save(DisasContext *ctx, - int xsregs, int aregs, - int do_ra, int do_s0, int do_s1, - int framesize) -{ - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - TCGv t2 = tcg_temp_new(); - int args, astatic; - - switch (aregs) { - case 0: - case 1: - case 2: - case 3: - case 11: - args = 0; - break; - case 4: - case 5: - case 6: - case 7: - args = 1; - break; - case 8: - case 9: - case 10: - args = 2; - break; - case 12: - case 13: - args = 3; - break; - case 14: - args = 4; - break; - default: - gen_reserved_instruction(ctx); - return; - } - - switch (args) { - case 4: - gen_base_offset_addr(ctx, t0, 29, 12); - gen_load_gpr(t1, 7); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); - /* Fall through */ - case 3: - gen_base_offset_addr(ctx, t0, 29, 8); - gen_load_gpr(t1, 6); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); - /* Fall through */ - case 2: - gen_base_offset_addr(ctx, t0, 29, 4); - gen_load_gpr(t1, 5); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); - /* Fall through */ - case 1: - gen_base_offset_addr(ctx, t0, 29, 0); - gen_load_gpr(t1, 4); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); - } - - gen_load_gpr(t0, 29); - -#define DECR_AND_STORE(reg) do { \ - tcg_gen_movi_tl(t2, -4); \ - gen_op_addr_add(ctx, t0, t0, t2); \ - gen_load_gpr(t1, reg); \ - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); \ - } while (0) - - if (do_ra) { - DECR_AND_STORE(31); - } - - switch (xsregs) { - case 7: - DECR_AND_STORE(30); - /* Fall through */ - case 6: - DECR_AND_STORE(23); - /* Fall through */ - case 5: - DECR_AND_STORE(22); - /* Fall through */ - case 4: - DECR_AND_STORE(21); - /* Fall through */ - case 3: - DECR_AND_STORE(20); - /* Fall through */ - case 2: - DECR_AND_STORE(19); - /* Fall through */ - case 1: - DECR_AND_STORE(18); - } - - if (do_s1) { - DECR_AND_STORE(17); - } - if (do_s0) { - DECR_AND_STORE(16); - } - - switch (aregs) { - case 0: - case 4: - case 8: - case 12: - case 14: - astatic = 0; - break; - case 1: - case 5: - case 9: - case 13: - astatic = 1; - break; - case 2: - case 6: - case 10: - astatic = 2; - break; - case 3: - case 7: - astatic = 3; - break; - case 11: - astatic = 4; - break; - default: - gen_reserved_instruction(ctx); - return; - } - - if (astatic > 0) { - DECR_AND_STORE(7); - if (astatic > 1) { - DECR_AND_STORE(6); - if (astatic > 2) { - DECR_AND_STORE(5); - if (astatic > 3) { - DECR_AND_STORE(4); - } - } - } - } -#undef DECR_AND_STORE - - tcg_gen_movi_tl(t2, -framesize); - gen_op_addr_add(ctx, cpu_gpr[29], cpu_gpr[29], t2); - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free(t2); -} - -static void gen_mips16_restore(DisasContext *ctx, - int xsregs, int aregs, - int do_ra, int do_s0, int do_s1, - int framesize) -{ - int astatic; - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - TCGv t2 = tcg_temp_new(); - - tcg_gen_movi_tl(t2, framesize); - gen_op_addr_add(ctx, t0, cpu_gpr[29], t2); - -#define DECR_AND_LOAD(reg) do { \ - tcg_gen_movi_tl(t2, -4); \ - gen_op_addr_add(ctx, t0, t0, t2); \ - tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL); \ - gen_store_gpr(t1, reg); \ - } while (0) - - if (do_ra) { - DECR_AND_LOAD(31); - } - - switch (xsregs) { - case 7: - DECR_AND_LOAD(30); - /* Fall through */ - case 6: - DECR_AND_LOAD(23); - /* Fall through */ - case 5: - DECR_AND_LOAD(22); - /* Fall through */ - case 4: - DECR_AND_LOAD(21); - /* Fall through */ - case 3: - DECR_AND_LOAD(20); - /* Fall through */ - case 2: - DECR_AND_LOAD(19); - /* Fall through */ - case 1: - DECR_AND_LOAD(18); - } - - if (do_s1) { - DECR_AND_LOAD(17); - } - if (do_s0) { - DECR_AND_LOAD(16); - } - - switch (aregs) { - case 0: - case 4: - case 8: - case 12: - case 14: - astatic = 0; - break; - case 1: - case 5: - case 9: - case 13: - astatic = 1; - break; - case 2: - case 6: - case 10: - astatic = 2; - break; - case 3: - case 7: - astatic = 3; - break; - case 11: - astatic = 4; - break; - default: - gen_reserved_instruction(ctx); - return; - } - - if (astatic > 0) { - DECR_AND_LOAD(7); - if (astatic > 1) { - DECR_AND_LOAD(6); - if (astatic > 2) { - DECR_AND_LOAD(5); - if (astatic > 3) { - DECR_AND_LOAD(4); - } - } - } - } -#undef DECR_AND_LOAD - - tcg_gen_movi_tl(t2, framesize); - gen_op_addr_add(ctx, cpu_gpr[29], cpu_gpr[29], t2); - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free(t2); -} - -static void gen_addiupc(DisasContext *ctx, int rx, int imm, - int is_64_bit, int extended) +void gen_addiupc(DisasContext *ctx, int rx, int imm, + int is_64_bit, int extended) { TCGv t0; @@ -12810,267 +12224,6 @@ static void gen_cache_operation(DisasContext *ctx, uint32_t op, int base, tcg_temp_free_i32(t0); } -#if defined(TARGET_MIPS64) -static void decode_i64_mips16(DisasContext *ctx, - int ry, int funct, int16_t offset, - int extended) -{ - switch (funct) { - case I64_LDSP: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - offset = extended ? offset : offset << 3; - gen_ld(ctx, OPC_LD, ry, 29, offset); - break; - case I64_SDSP: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - offset = extended ? offset : offset << 3; - gen_st(ctx, OPC_SD, ry, 29, offset); - break; - case I64_SDRASP: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - offset = extended ? offset : (ctx->opcode & 0xff) << 3; - gen_st(ctx, OPC_SD, 31, 29, offset); - break; - case I64_DADJSP: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - offset = extended ? offset : ((int8_t)ctx->opcode) << 3; - gen_arith_imm(ctx, OPC_DADDIU, 29, 29, offset); - break; - case I64_LDPC: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - if (extended && (ctx->hflags & MIPS_HFLAG_BMASK)) { - gen_reserved_instruction(ctx); - } else { - offset = extended ? offset : offset << 3; - gen_ld(ctx, OPC_LDPC, ry, 0, offset); - } - break; - case I64_DADDIU5: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - offset = extended ? offset : ((int8_t)(offset << 3)) >> 3; - gen_arith_imm(ctx, OPC_DADDIU, ry, ry, offset); - break; - case I64_DADDIUPC: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - offset = extended ? offset : offset << 2; - gen_addiupc(ctx, ry, offset, 1, extended); - break; - case I64_DADDIUSP: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - offset = extended ? offset : offset << 2; - gen_arith_imm(ctx, OPC_DADDIU, ry, 29, offset); - break; - } -} -#endif - -static int decode_extended_mips16_opc(CPUMIPSState *env, DisasContext *ctx) -{ - int extend = translator_lduw(env, ctx->base.pc_next + 2); - int op, rx, ry, funct, sa; - int16_t imm, offset; - - ctx->opcode = (ctx->opcode << 16) | extend; - op = (ctx->opcode >> 11) & 0x1f; - sa = (ctx->opcode >> 22) & 0x1f; - funct = (ctx->opcode >> 8) & 0x7; - rx = xlat((ctx->opcode >> 8) & 0x7); - ry = xlat((ctx->opcode >> 5) & 0x7); - offset = imm = (int16_t) (((ctx->opcode >> 16) & 0x1f) << 11 - | ((ctx->opcode >> 21) & 0x3f) << 5 - | (ctx->opcode & 0x1f)); - - /* - * The extended opcodes cleverly reuse the opcodes from their 16-bit - * counterparts. - */ - switch (op) { - case M16_OPC_ADDIUSP: - gen_arith_imm(ctx, OPC_ADDIU, rx, 29, imm); - break; - case M16_OPC_ADDIUPC: - gen_addiupc(ctx, rx, imm, 0, 1); - break; - case M16_OPC_B: - gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1, 0); - /* No delay slot, so just process as a normal instruction */ - break; - case M16_OPC_BEQZ: - gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1, 0); - /* No delay slot, so just process as a normal instruction */ - break; - case M16_OPC_BNEQZ: - gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1, 0); - /* No delay slot, so just process as a normal instruction */ - break; - case M16_OPC_SHIFT: - switch (ctx->opcode & 0x3) { - case 0x0: - gen_shift_imm(ctx, OPC_SLL, rx, ry, sa); - break; - case 0x1: -#if defined(TARGET_MIPS64) - check_mips_64(ctx); - gen_shift_imm(ctx, OPC_DSLL, rx, ry, sa); -#else - gen_reserved_instruction(ctx); -#endif - break; - case 0x2: - gen_shift_imm(ctx, OPC_SRL, rx, ry, sa); - break; - case 0x3: - gen_shift_imm(ctx, OPC_SRA, rx, ry, sa); - break; - } - break; -#if defined(TARGET_MIPS64) - case M16_OPC_LD: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_ld(ctx, OPC_LD, ry, rx, offset); - break; -#endif - case M16_OPC_RRIA: - imm = ctx->opcode & 0xf; - imm = imm | ((ctx->opcode >> 20) & 0x7f) << 4; - imm = imm | ((ctx->opcode >> 16) & 0xf) << 11; - imm = (int16_t) (imm << 1) >> 1; - if ((ctx->opcode >> 4) & 0x1) { -#if defined(TARGET_MIPS64) - check_mips_64(ctx); - gen_arith_imm(ctx, OPC_DADDIU, ry, rx, imm); -#else - gen_reserved_instruction(ctx); -#endif - } else { - gen_arith_imm(ctx, OPC_ADDIU, ry, rx, imm); - } - break; - case M16_OPC_ADDIU8: - gen_arith_imm(ctx, OPC_ADDIU, rx, rx, imm); - break; - case M16_OPC_SLTI: - gen_slt_imm(ctx, OPC_SLTI, 24, rx, imm); - break; - case M16_OPC_SLTIU: - gen_slt_imm(ctx, OPC_SLTIU, 24, rx, imm); - break; - case M16_OPC_I8: - switch (funct) { - case I8_BTEQZ: - gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1, 0); - break; - case I8_BTNEZ: - gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1, 0); - break; - case I8_SWRASP: - gen_st(ctx, OPC_SW, 31, 29, imm); - break; - case I8_ADJSP: - gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm); - break; - case I8_SVRS: - check_insn(ctx, ISA_MIPS_R1); - { - int xsregs = (ctx->opcode >> 24) & 0x7; - int aregs = (ctx->opcode >> 16) & 0xf; - int do_ra = (ctx->opcode >> 6) & 0x1; - int do_s0 = (ctx->opcode >> 5) & 0x1; - int do_s1 = (ctx->opcode >> 4) & 0x1; - int framesize = (((ctx->opcode >> 20) & 0xf) << 4 - | (ctx->opcode & 0xf)) << 3; - - if (ctx->opcode & (1 << 7)) { - gen_mips16_save(ctx, xsregs, aregs, - do_ra, do_s0, do_s1, - framesize); - } else { - gen_mips16_restore(ctx, xsregs, aregs, - do_ra, do_s0, do_s1, - framesize); - } - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case M16_OPC_LI: - tcg_gen_movi_tl(cpu_gpr[rx], (uint16_t) imm); - break; - case M16_OPC_CMPI: - tcg_gen_xori_tl(cpu_gpr[24], cpu_gpr[rx], (uint16_t) imm); - break; -#if defined(TARGET_MIPS64) - case M16_OPC_SD: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_st(ctx, OPC_SD, ry, rx, offset); - break; -#endif - case M16_OPC_LB: - gen_ld(ctx, OPC_LB, ry, rx, offset); - break; - case M16_OPC_LH: - gen_ld(ctx, OPC_LH, ry, rx, offset); - break; - case M16_OPC_LWSP: - gen_ld(ctx, OPC_LW, rx, 29, offset); - break; - case M16_OPC_LW: - gen_ld(ctx, OPC_LW, ry, rx, offset); - break; - case M16_OPC_LBU: - gen_ld(ctx, OPC_LBU, ry, rx, offset); - break; - case M16_OPC_LHU: - gen_ld(ctx, OPC_LHU, ry, rx, offset); - break; - case M16_OPC_LWPC: - gen_ld(ctx, OPC_LWPC, rx, 0, offset); - break; -#if defined(TARGET_MIPS64) - case M16_OPC_LWU: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_ld(ctx, OPC_LWU, ry, rx, offset); - break; -#endif - case M16_OPC_SB: - gen_st(ctx, OPC_SB, ry, rx, offset); - break; - case M16_OPC_SH: - gen_st(ctx, OPC_SH, ry, rx, offset); - break; - case M16_OPC_SWSP: - gen_st(ctx, OPC_SW, rx, 29, offset); - break; - case M16_OPC_SW: - gen_st(ctx, OPC_SW, ry, rx, offset); - break; -#if defined(TARGET_MIPS64) - case M16_OPC_I64: - decode_i64_mips16(ctx, ry, funct, offset, 1); - break; -#endif - default: - gen_reserved_instruction(ctx); - break; - } - - return 4; -} - static inline bool is_uhi(int sdbbp_code) { #ifdef CONFIG_USER_ONLY @@ -13088,1429 +12241,7 @@ static inline void gen_helper_do_semihosting(void *env) } #endif -static int decode_mips16_opc(CPUMIPSState *env, DisasContext *ctx) -{ - int rx, ry; - int sa; - int op, cnvt_op, op1, offset; - int funct; - int n_bytes; - - op = (ctx->opcode >> 11) & 0x1f; - sa = (ctx->opcode >> 2) & 0x7; - sa = sa == 0 ? 8 : sa; - rx = xlat((ctx->opcode >> 8) & 0x7); - cnvt_op = (ctx->opcode >> 5) & 0x7; - ry = xlat((ctx->opcode >> 5) & 0x7); - op1 = offset = ctx->opcode & 0x1f; - - n_bytes = 2; - - switch (op) { - case M16_OPC_ADDIUSP: - { - int16_t imm = ((uint8_t) ctx->opcode) << 2; - - gen_arith_imm(ctx, OPC_ADDIU, rx, 29, imm); - } - break; - case M16_OPC_ADDIUPC: - gen_addiupc(ctx, rx, ((uint8_t) ctx->opcode) << 2, 0, 0); - break; - case M16_OPC_B: - offset = (ctx->opcode & 0x7ff) << 1; - offset = (int16_t)(offset << 4) >> 4; - gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset, 0); - /* No delay slot, so just process as a normal instruction */ - break; - case M16_OPC_JAL: - offset = translator_lduw(env, ctx->base.pc_next + 2); - offset = (((ctx->opcode & 0x1f) << 21) - | ((ctx->opcode >> 5) & 0x1f) << 16 - | offset) << 2; - op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALX : OPC_JAL; - gen_compute_branch(ctx, op, 4, rx, ry, offset, 2); - n_bytes = 4; - break; - case M16_OPC_BEQZ: - gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, - ((int8_t)ctx->opcode) << 1, 0); - /* No delay slot, so just process as a normal instruction */ - break; - case M16_OPC_BNEQZ: - gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, - ((int8_t)ctx->opcode) << 1, 0); - /* No delay slot, so just process as a normal instruction */ - break; - case M16_OPC_SHIFT: - switch (ctx->opcode & 0x3) { - case 0x0: - gen_shift_imm(ctx, OPC_SLL, rx, ry, sa); - break; - case 0x1: -#if defined(TARGET_MIPS64) - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_shift_imm(ctx, OPC_DSLL, rx, ry, sa); -#else - gen_reserved_instruction(ctx); -#endif - break; - case 0x2: - gen_shift_imm(ctx, OPC_SRL, rx, ry, sa); - break; - case 0x3: - gen_shift_imm(ctx, OPC_SRA, rx, ry, sa); - break; - } - break; -#if defined(TARGET_MIPS64) - case M16_OPC_LD: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_ld(ctx, OPC_LD, ry, rx, offset << 3); - break; -#endif - case M16_OPC_RRIA: - { - int16_t imm = (int8_t)((ctx->opcode & 0xf) << 4) >> 4; - - if ((ctx->opcode >> 4) & 1) { -#if defined(TARGET_MIPS64) - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_arith_imm(ctx, OPC_DADDIU, ry, rx, imm); -#else - gen_reserved_instruction(ctx); -#endif - } else { - gen_arith_imm(ctx, OPC_ADDIU, ry, rx, imm); - } - } - break; - case M16_OPC_ADDIU8: - { - int16_t imm = (int8_t) ctx->opcode; - - gen_arith_imm(ctx, OPC_ADDIU, rx, rx, imm); - } - break; - case M16_OPC_SLTI: - { - int16_t imm = (uint8_t) ctx->opcode; - gen_slt_imm(ctx, OPC_SLTI, 24, rx, imm); - } - break; - case M16_OPC_SLTIU: - { - int16_t imm = (uint8_t) ctx->opcode; - gen_slt_imm(ctx, OPC_SLTIU, 24, rx, imm); - } - break; - case M16_OPC_I8: - { - int reg32; - - funct = (ctx->opcode >> 8) & 0x7; - switch (funct) { - case I8_BTEQZ: - gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0, - ((int8_t)ctx->opcode) << 1, 0); - break; - case I8_BTNEZ: - gen_compute_branch(ctx, OPC_BNE, 2, 24, 0, - ((int8_t)ctx->opcode) << 1, 0); - break; - case I8_SWRASP: - gen_st(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2); - break; - case I8_ADJSP: - gen_arith_imm(ctx, OPC_ADDIU, 29, 29, - ((int8_t)ctx->opcode) << 3); - break; - case I8_SVRS: - check_insn(ctx, ISA_MIPS_R1); - { - int do_ra = ctx->opcode & (1 << 6); - int do_s0 = ctx->opcode & (1 << 5); - int do_s1 = ctx->opcode & (1 << 4); - int framesize = ctx->opcode & 0xf; - - if (framesize == 0) { - framesize = 128; - } else { - framesize = framesize << 3; - } - - if (ctx->opcode & (1 << 7)) { - gen_mips16_save(ctx, 0, 0, - do_ra, do_s0, do_s1, framesize); - } else { - gen_mips16_restore(ctx, 0, 0, - do_ra, do_s0, do_s1, framesize); - } - } - break; - case I8_MOV32R: - { - int rz = xlat(ctx->opcode & 0x7); - - reg32 = (((ctx->opcode >> 3) & 0x3) << 3) | - ((ctx->opcode >> 5) & 0x7); - gen_arith(ctx, OPC_ADDU, reg32, rz, 0); - } - break; - case I8_MOVR32: - reg32 = ctx->opcode & 0x1f; - gen_arith(ctx, OPC_ADDU, ry, reg32, 0); - break; - default: - gen_reserved_instruction(ctx); - break; - } - } - break; - case M16_OPC_LI: - { - int16_t imm = (uint8_t) ctx->opcode; - - gen_arith_imm(ctx, OPC_ADDIU, rx, 0, imm); - } - break; - case M16_OPC_CMPI: - { - int16_t imm = (uint8_t) ctx->opcode; - gen_logic_imm(ctx, OPC_XORI, 24, rx, imm); - } - break; -#if defined(TARGET_MIPS64) - case M16_OPC_SD: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_st(ctx, OPC_SD, ry, rx, offset << 3); - break; -#endif - case M16_OPC_LB: - gen_ld(ctx, OPC_LB, ry, rx, offset); - break; - case M16_OPC_LH: - gen_ld(ctx, OPC_LH, ry, rx, offset << 1); - break; - case M16_OPC_LWSP: - gen_ld(ctx, OPC_LW, rx, 29, ((uint8_t)ctx->opcode) << 2); - break; - case M16_OPC_LW: - gen_ld(ctx, OPC_LW, ry, rx, offset << 2); - break; - case M16_OPC_LBU: - gen_ld(ctx, OPC_LBU, ry, rx, offset); - break; - case M16_OPC_LHU: - gen_ld(ctx, OPC_LHU, ry, rx, offset << 1); - break; - case M16_OPC_LWPC: - gen_ld(ctx, OPC_LWPC, rx, 0, ((uint8_t)ctx->opcode) << 2); - break; -#if defined(TARGET_MIPS64) - case M16_OPC_LWU: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_ld(ctx, OPC_LWU, ry, rx, offset << 2); - break; -#endif - case M16_OPC_SB: - gen_st(ctx, OPC_SB, ry, rx, offset); - break; - case M16_OPC_SH: - gen_st(ctx, OPC_SH, ry, rx, offset << 1); - break; - case M16_OPC_SWSP: - gen_st(ctx, OPC_SW, rx, 29, ((uint8_t)ctx->opcode) << 2); - break; - case M16_OPC_SW: - gen_st(ctx, OPC_SW, ry, rx, offset << 2); - break; - case M16_OPC_RRR: - { - int rz = xlat((ctx->opcode >> 2) & 0x7); - int mips32_op; - - switch (ctx->opcode & 0x3) { - case RRR_ADDU: - mips32_op = OPC_ADDU; - break; - case RRR_SUBU: - mips32_op = OPC_SUBU; - break; -#if defined(TARGET_MIPS64) - case RRR_DADDU: - mips32_op = OPC_DADDU; - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - break; - case RRR_DSUBU: - mips32_op = OPC_DSUBU; - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - break; -#endif - default: - gen_reserved_instruction(ctx); - goto done; - } - - gen_arith(ctx, mips32_op, rz, rx, ry); - done: - ; - } - break; - case M16_OPC_RR: - switch (op1) { - case RR_JR: - { - int nd = (ctx->opcode >> 7) & 0x1; - int link = (ctx->opcode >> 6) & 0x1; - int ra = (ctx->opcode >> 5) & 0x1; - - if (nd) { - check_insn(ctx, ISA_MIPS_R1); - } - - if (link) { - op = OPC_JALR; - } else { - op = OPC_JR; - } - - gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0, - (nd ? 0 : 2)); - } - break; - case RR_SDBBP: - if (is_uhi(extract32(ctx->opcode, 5, 6))) { - gen_helper_do_semihosting(cpu_env); - } else { - /* - * XXX: not clear which exception should be raised - * when in debug mode... - */ - check_insn(ctx, ISA_MIPS_R1); - generate_exception_end(ctx, EXCP_DBp); - } - break; - case RR_SLT: - gen_slt(ctx, OPC_SLT, 24, rx, ry); - break; - case RR_SLTU: - gen_slt(ctx, OPC_SLTU, 24, rx, ry); - break; - case RR_BREAK: - generate_exception_end(ctx, EXCP_BREAK); - break; - case RR_SLLV: - gen_shift(ctx, OPC_SLLV, ry, rx, ry); - break; - case RR_SRLV: - gen_shift(ctx, OPC_SRLV, ry, rx, ry); - break; - case RR_SRAV: - gen_shift(ctx, OPC_SRAV, ry, rx, ry); - break; -#if defined(TARGET_MIPS64) - case RR_DSRL: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_shift_imm(ctx, OPC_DSRL, ry, ry, sa); - break; -#endif - case RR_CMP: - gen_logic(ctx, OPC_XOR, 24, rx, ry); - break; - case RR_NEG: - gen_arith(ctx, OPC_SUBU, rx, 0, ry); - break; - case RR_AND: - gen_logic(ctx, OPC_AND, rx, rx, ry); - break; - case RR_OR: - gen_logic(ctx, OPC_OR, rx, rx, ry); - break; - case RR_XOR: - gen_logic(ctx, OPC_XOR, rx, rx, ry); - break; - case RR_NOT: - gen_logic(ctx, OPC_NOR, rx, ry, 0); - break; - case RR_MFHI: - gen_HILO(ctx, OPC_MFHI, 0, rx); - break; - case RR_CNVT: - check_insn(ctx, ISA_MIPS_R1); - switch (cnvt_op) { - case RR_RY_CNVT_ZEB: - tcg_gen_ext8u_tl(cpu_gpr[rx], cpu_gpr[rx]); - break; - case RR_RY_CNVT_ZEH: - tcg_gen_ext16u_tl(cpu_gpr[rx], cpu_gpr[rx]); - break; - case RR_RY_CNVT_SEB: - tcg_gen_ext8s_tl(cpu_gpr[rx], cpu_gpr[rx]); - break; - case RR_RY_CNVT_SEH: - tcg_gen_ext16s_tl(cpu_gpr[rx], cpu_gpr[rx]); - break; -#if defined(TARGET_MIPS64) - case RR_RY_CNVT_ZEW: - check_insn(ctx, ISA_MIPS_R1); - check_mips_64(ctx); - tcg_gen_ext32u_tl(cpu_gpr[rx], cpu_gpr[rx]); - break; - case RR_RY_CNVT_SEW: - check_insn(ctx, ISA_MIPS_R1); - check_mips_64(ctx); - tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]); - break; -#endif - default: - gen_reserved_instruction(ctx); - break; - } - break; - case RR_MFLO: - gen_HILO(ctx, OPC_MFLO, 0, rx); - break; -#if defined(TARGET_MIPS64) - case RR_DSRA: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_shift_imm(ctx, OPC_DSRA, ry, ry, sa); - break; - case RR_DSLLV: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_shift(ctx, OPC_DSLLV, ry, rx, ry); - break; - case RR_DSRLV: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_shift(ctx, OPC_DSRLV, ry, rx, ry); - break; - case RR_DSRAV: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_shift(ctx, OPC_DSRAV, ry, rx, ry); - break; -#endif - case RR_MULT: - gen_muldiv(ctx, OPC_MULT, 0, rx, ry); - break; - case RR_MULTU: - gen_muldiv(ctx, OPC_MULTU, 0, rx, ry); - break; - case RR_DIV: - gen_muldiv(ctx, OPC_DIV, 0, rx, ry); - break; - case RR_DIVU: - gen_muldiv(ctx, OPC_DIVU, 0, rx, ry); - break; -#if defined(TARGET_MIPS64) - case RR_DMULT: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_muldiv(ctx, OPC_DMULT, 0, rx, ry); - break; - case RR_DMULTU: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_muldiv(ctx, OPC_DMULTU, 0, rx, ry); - break; - case RR_DDIV: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_muldiv(ctx, OPC_DDIV, 0, rx, ry); - break; - case RR_DDIVU: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_muldiv(ctx, OPC_DDIVU, 0, rx, ry); - break; -#endif - default: - gen_reserved_instruction(ctx); - break; - } - break; - case M16_OPC_EXTEND: - decode_extended_mips16_opc(env, ctx); - n_bytes = 4; - break; -#if defined(TARGET_MIPS64) - case M16_OPC_I64: - funct = (ctx->opcode >> 8) & 0x7; - decode_i64_mips16(ctx, ry, funct, offset, 0); - break; -#endif - default: - gen_reserved_instruction(ctx); - break; - } - - return n_bytes; -} - -/* microMIPS extension to MIPS32/MIPS64 */ - -/* - * microMIPS32/microMIPS64 major opcodes - * - * 1. MIPS Architecture for Programmers Volume II-B: - * The microMIPS32 Instruction Set (Revision 3.05) - * - * Table 6.2 microMIPS32 Encoding of Major Opcode Field - * - * 2. MIPS Architecture For Programmers Volume II-A: - * The MIPS64 Instruction Set (Revision 3.51) - */ - -enum { - POOL32A = 0x00, - POOL16A = 0x01, - LBU16 = 0x02, - MOVE16 = 0x03, - ADDI32 = 0x04, - R6_LUI = 0x04, - AUI = 0x04, - LBU32 = 0x05, - SB32 = 0x06, - LB32 = 0x07, - - POOL32B = 0x08, - POOL16B = 0x09, - LHU16 = 0x0a, - ANDI16 = 0x0b, - ADDIU32 = 0x0c, - LHU32 = 0x0d, - SH32 = 0x0e, - LH32 = 0x0f, - - POOL32I = 0x10, - POOL16C = 0x11, - LWSP16 = 0x12, - POOL16D = 0x13, - ORI32 = 0x14, - POOL32F = 0x15, - POOL32S = 0x16, /* MIPS64 */ - DADDIU32 = 0x17, /* MIPS64 */ - - POOL32C = 0x18, - LWGP16 = 0x19, - LW16 = 0x1a, - POOL16E = 0x1b, - XORI32 = 0x1c, - JALS32 = 0x1d, - BOVC = 0x1d, - BEQC = 0x1d, - BEQZALC = 0x1d, - ADDIUPC = 0x1e, - PCREL = 0x1e, - BNVC = 0x1f, - BNEC = 0x1f, - BNEZALC = 0x1f, - - R6_BEQZC = 0x20, - JIC = 0x20, - POOL16F = 0x21, - SB16 = 0x22, - BEQZ16 = 0x23, - BEQZC16 = 0x23, - SLTI32 = 0x24, - BEQ32 = 0x25, - BC = 0x25, - SWC132 = 0x26, - LWC132 = 0x27, - - /* 0x29 is reserved */ - RES_29 = 0x29, - R6_BNEZC = 0x28, - JIALC = 0x28, - SH16 = 0x2a, - BNEZ16 = 0x2b, - BNEZC16 = 0x2b, - SLTIU32 = 0x2c, - BNE32 = 0x2d, - BALC = 0x2d, - SDC132 = 0x2e, - LDC132 = 0x2f, - - /* 0x31 is reserved */ - RES_31 = 0x31, - BLEZALC = 0x30, - BGEZALC = 0x30, - BGEUC = 0x30, - SWSP16 = 0x32, - B16 = 0x33, - BC16 = 0x33, - ANDI32 = 0x34, - J32 = 0x35, - BGTZC = 0x35, - BLTZC = 0x35, - BLTC = 0x35, - SD32 = 0x36, /* MIPS64 */ - LD32 = 0x37, /* MIPS64 */ - - /* 0x39 is reserved */ - RES_39 = 0x39, - BGTZALC = 0x38, - BLTZALC = 0x38, - BLTUC = 0x38, - SW16 = 0x3a, - LI16 = 0x3b, - JALX32 = 0x3c, - JAL32 = 0x3d, - BLEZC = 0x3d, - BGEZC = 0x3d, - BGEC = 0x3d, - SW32 = 0x3e, - LW32 = 0x3f -}; - -/* PCREL Instructions perform PC-Relative address calculation. bits 20..16 */ -enum { - ADDIUPC_00 = 0x00, - ADDIUPC_01 = 0x01, - ADDIUPC_02 = 0x02, - ADDIUPC_03 = 0x03, - ADDIUPC_04 = 0x04, - ADDIUPC_05 = 0x05, - ADDIUPC_06 = 0x06, - ADDIUPC_07 = 0x07, - AUIPC = 0x1e, - ALUIPC = 0x1f, - LWPC_08 = 0x08, - LWPC_09 = 0x09, - LWPC_0A = 0x0A, - LWPC_0B = 0x0B, - LWPC_0C = 0x0C, - LWPC_0D = 0x0D, - LWPC_0E = 0x0E, - LWPC_0F = 0x0F, -}; - -/* POOL32A encoding of minor opcode field */ - -enum { - /* - * These opcodes are distinguished only by bits 9..6; those bits are - * what are recorded below. - */ - SLL32 = 0x0, - SRL32 = 0x1, - SRA = 0x2, - ROTR = 0x3, - SELEQZ = 0x5, - SELNEZ = 0x6, - R6_RDHWR = 0x7, - - SLLV = 0x0, - SRLV = 0x1, - SRAV = 0x2, - ROTRV = 0x3, - ADD = 0x4, - ADDU32 = 0x5, - SUB = 0x6, - SUBU32 = 0x7, - MUL = 0x8, - AND = 0x9, - OR32 = 0xa, - NOR = 0xb, - XOR32 = 0xc, - SLT = 0xd, - SLTU = 0xe, - - MOVN = 0x0, - R6_MUL = 0x0, - MOVZ = 0x1, - MUH = 0x1, - MULU = 0x2, - MUHU = 0x3, - LWXS = 0x4, - R6_DIV = 0x4, - MOD = 0x5, - R6_DIVU = 0x6, - MODU = 0x7, - - /* The following can be distinguished by their lower 6 bits. */ - BREAK32 = 0x07, - INS = 0x0c, - LSA = 0x0f, - ALIGN = 0x1f, - EXT = 0x2c, - POOL32AXF = 0x3c, - SIGRIE = 0x3f -}; - -/* POOL32AXF encoding of minor opcode field extension */ - -/* - * 1. MIPS Architecture for Programmers Volume II-B: - * The microMIPS32 Instruction Set (Revision 3.05) - * - * Table 6.5 POOL32Axf Encoding of Minor Opcode Extension Field - * - * 2. MIPS Architecture for Programmers VolumeIV-e: - * The MIPS DSP Application-Specific Extension - * to the microMIPS32 Architecture (Revision 2.34) - * - * Table 5.5 POOL32Axf Encoding of Minor Opcode Extension Field - */ - -enum { - /* bits 11..6 */ - TEQ = 0x00, - TGE = 0x08, - TGEU = 0x10, - TLT = 0x20, - TLTU = 0x28, - TNE = 0x30, - - MFC0 = 0x03, - MTC0 = 0x0b, - - /* begin of microMIPS32 DSP */ - - /* bits 13..12 for 0x01 */ - MFHI_ACC = 0x0, - MFLO_ACC = 0x1, - MTHI_ACC = 0x2, - MTLO_ACC = 0x3, - - /* bits 13..12 for 0x2a */ - MADD_ACC = 0x0, - MADDU_ACC = 0x1, - MSUB_ACC = 0x2, - MSUBU_ACC = 0x3, - - /* bits 13..12 for 0x32 */ - MULT_ACC = 0x0, - MULTU_ACC = 0x1, - - /* end of microMIPS32 DSP */ - - /* bits 15..12 for 0x2c */ - BITSWAP = 0x0, - SEB = 0x2, - SEH = 0x3, - CLO = 0x4, - CLZ = 0x5, - RDHWR = 0x6, - WSBH = 0x7, - MULT = 0x8, - MULTU = 0x9, - DIV = 0xa, - DIVU = 0xb, - MADD = 0xc, - MADDU = 0xd, - MSUB = 0xe, - MSUBU = 0xf, - - /* bits 15..12 for 0x34 */ - MFC2 = 0x4, - MTC2 = 0x5, - MFHC2 = 0x8, - MTHC2 = 0x9, - CFC2 = 0xc, - CTC2 = 0xd, - - /* bits 15..12 for 0x3c */ - JALR = 0x0, - JR = 0x0, /* alias */ - JALRC = 0x0, - JRC = 0x0, - JALR_HB = 0x1, - JALRC_HB = 0x1, - JALRS = 0x4, - JALRS_HB = 0x5, - - /* bits 15..12 for 0x05 */ - RDPGPR = 0xe, - WRPGPR = 0xf, - - /* bits 15..12 for 0x0d */ - TLBP = 0x0, - TLBR = 0x1, - TLBWI = 0x2, - TLBWR = 0x3, - TLBINV = 0x4, - TLBINVF = 0x5, - WAIT = 0x9, - IRET = 0xd, - DERET = 0xe, - ERET = 0xf, - - /* bits 15..12 for 0x15 */ - DMT = 0x0, - DVPE = 0x1, - EMT = 0x2, - EVPE = 0x3, - - /* bits 15..12 for 0x1d */ - DI = 0x4, - EI = 0x5, - - /* bits 15..12 for 0x2d */ - SYNC = 0x6, - SYSCALL = 0x8, - SDBBP = 0xd, - - /* bits 15..12 for 0x35 */ - MFHI32 = 0x0, - MFLO32 = 0x1, - MTHI32 = 0x2, - MTLO32 = 0x3, -}; - -/* POOL32B encoding of minor opcode field (bits 15..12) */ - -enum { - LWC2 = 0x0, - LWP = 0x1, - LDP = 0x4, - LWM32 = 0x5, - CACHE = 0x6, - LDM = 0x7, - SWC2 = 0x8, - SWP = 0x9, - SDP = 0xc, - SWM32 = 0xd, - SDM = 0xf -}; - -/* POOL32C encoding of minor opcode field (bits 15..12) */ - -enum { - LWL = 0x0, - SWL = 0x8, - LWR = 0x1, - SWR = 0x9, - PREF = 0x2, - ST_EVA = 0xa, - LL = 0x3, - SC = 0xb, - LDL = 0x4, - SDL = 0xc, - LDR = 0x5, - SDR = 0xd, - LD_EVA = 0x6, - LWU = 0xe, - LLD = 0x7, - SCD = 0xf -}; - -/* POOL32C LD-EVA encoding of minor opcode field (bits 11..9) */ - -enum { - LBUE = 0x0, - LHUE = 0x1, - LWLE = 0x2, - LWRE = 0x3, - LBE = 0x4, - LHE = 0x5, - LLE = 0x6, - LWE = 0x7, -}; - -/* POOL32C ST-EVA encoding of minor opcode field (bits 11..9) */ - -enum { - SWLE = 0x0, - SWRE = 0x1, - PREFE = 0x2, - CACHEE = 0x3, - SBE = 0x4, - SHE = 0x5, - SCE = 0x6, - SWE = 0x7, -}; - -/* POOL32F encoding of minor opcode field (bits 5..0) */ - -enum { - /* These are the bit 7..6 values */ - ADD_FMT = 0x0, - - SUB_FMT = 0x1, - - MUL_FMT = 0x2, - - DIV_FMT = 0x3, - - /* These are the bit 8..6 values */ - MOVN_FMT = 0x0, - RSQRT2_FMT = 0x0, - MOVF_FMT = 0x0, - RINT_FMT = 0x0, - SELNEZ_FMT = 0x0, - - MOVZ_FMT = 0x1, - LWXC1 = 0x1, - MOVT_FMT = 0x1, - CLASS_FMT = 0x1, - SELEQZ_FMT = 0x1, - - PLL_PS = 0x2, - SWXC1 = 0x2, - SEL_FMT = 0x2, - - PLU_PS = 0x3, - LDXC1 = 0x3, - - MOVN_FMT_04 = 0x4, - PUL_PS = 0x4, - SDXC1 = 0x4, - RECIP2_FMT = 0x4, - - MOVZ_FMT_05 = 0x05, - PUU_PS = 0x5, - LUXC1 = 0x5, - - CVT_PS_S = 0x6, - SUXC1 = 0x6, - ADDR_PS = 0x6, - PREFX = 0x6, - MADDF_FMT = 0x6, - - MULR_PS = 0x7, - MSUBF_FMT = 0x7, - - MADD_S = 0x01, - MADD_D = 0x09, - MADD_PS = 0x11, - ALNV_PS = 0x19, - MSUB_S = 0x21, - MSUB_D = 0x29, - MSUB_PS = 0x31, - - NMADD_S = 0x02, - NMADD_D = 0x0a, - NMADD_PS = 0x12, - NMSUB_S = 0x22, - NMSUB_D = 0x2a, - NMSUB_PS = 0x32, - - MIN_FMT = 0x3, - MAX_FMT = 0xb, - MINA_FMT = 0x23, - MAXA_FMT = 0x2b, - POOL32FXF = 0x3b, - - CABS_COND_FMT = 0x1c, /* MIPS3D */ - C_COND_FMT = 0x3c, - - CMP_CONDN_S = 0x5, - CMP_CONDN_D = 0x15 -}; - -/* POOL32Fxf encoding of minor opcode extension field */ - -enum { - CVT_L = 0x04, - RSQRT_FMT = 0x08, - FLOOR_L = 0x0c, - CVT_PW_PS = 0x1c, - CVT_W = 0x24, - SQRT_FMT = 0x28, - FLOOR_W = 0x2c, - CVT_PS_PW = 0x3c, - CFC1 = 0x40, - RECIP_FMT = 0x48, - CEIL_L = 0x4c, - CTC1 = 0x60, - CEIL_W = 0x6c, - MFC1 = 0x80, - CVT_S_PL = 0x84, - TRUNC_L = 0x8c, - MTC1 = 0xa0, - CVT_S_PU = 0xa4, - TRUNC_W = 0xac, - MFHC1 = 0xc0, - ROUND_L = 0xcc, - MTHC1 = 0xe0, - ROUND_W = 0xec, - - MOV_FMT = 0x01, - MOVF = 0x05, - ABS_FMT = 0x0d, - RSQRT1_FMT = 0x1d, - MOVT = 0x25, - NEG_FMT = 0x2d, - CVT_D = 0x4d, - RECIP1_FMT = 0x5d, - CVT_S = 0x6d -}; - -/* POOL32I encoding of minor opcode field (bits 25..21) */ - -enum { - BLTZ = 0x00, - BLTZAL = 0x01, - BGEZ = 0x02, - BGEZAL = 0x03, - BLEZ = 0x04, - BNEZC = 0x05, - BGTZ = 0x06, - BEQZC = 0x07, - TLTI = 0x08, - BC1EQZC = 0x08, - TGEI = 0x09, - BC1NEZC = 0x09, - TLTIU = 0x0a, - BC2EQZC = 0x0a, - TGEIU = 0x0b, - BC2NEZC = 0x0a, - TNEI = 0x0c, - R6_SYNCI = 0x0c, - LUI = 0x0d, - TEQI = 0x0e, - SYNCI = 0x10, - BLTZALS = 0x11, - BGEZALS = 0x13, - BC2F = 0x14, - BC2T = 0x15, - /* These overlap and are distinguished by bit16 of the instruction */ - BC1F = 0x1c, - BC1T = 0x1d, - BC1ANY2F = 0x1c, - BC1ANY2T = 0x1d, - BC1ANY4F = 0x1e, - BC1ANY4T = 0x1f -}; - -/* POOL16A encoding of minor opcode field */ - -enum { - ADDU16 = 0x0, - SUBU16 = 0x1 -}; - -/* POOL16B encoding of minor opcode field */ - -enum { - SLL16 = 0x0, - SRL16 = 0x1 -}; - -/* POOL16C encoding of minor opcode field */ - -enum { - NOT16 = 0x00, - XOR16 = 0x04, - AND16 = 0x08, - OR16 = 0x0c, - LWM16 = 0x10, - SWM16 = 0x14, - JR16 = 0x18, - JRC16 = 0x1a, - JALR16 = 0x1c, - JALR16S = 0x1e, - MFHI16 = 0x20, - MFLO16 = 0x24, - BREAK16 = 0x28, - SDBBP16 = 0x2c, - JRADDIUSP = 0x30 -}; - -/* R6 POOL16C encoding of minor opcode field (bits 0..5) */ - -enum { - R6_NOT16 = 0x00, - R6_AND16 = 0x01, - R6_LWM16 = 0x02, - R6_JRC16 = 0x03, - MOVEP = 0x04, - MOVEP_05 = 0x05, - MOVEP_06 = 0x06, - MOVEP_07 = 0x07, - R6_XOR16 = 0x08, - R6_OR16 = 0x09, - R6_SWM16 = 0x0a, - JALRC16 = 0x0b, - MOVEP_0C = 0x0c, - MOVEP_0D = 0x0d, - MOVEP_0E = 0x0e, - MOVEP_0F = 0x0f, - JRCADDIUSP = 0x13, - R6_BREAK16 = 0x1b, - R6_SDBBP16 = 0x3b -}; - -/* POOL16D encoding of minor opcode field */ - -enum { - ADDIUS5 = 0x0, - ADDIUSP = 0x1 -}; - -/* POOL16E encoding of minor opcode field */ - -enum { - ADDIUR2 = 0x0, - ADDIUR1SP = 0x1 -}; - -static int mmreg(int r) -{ - static const int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 }; - - return map[r]; -} - -/* Used for 16-bit store instructions. */ -static int mmreg2(int r) -{ - static const int map[] = { 0, 17, 2, 3, 4, 5, 6, 7 }; - - return map[r]; -} - -#define uMIPS_RD(op) ((op >> 7) & 0x7) -#define uMIPS_RS(op) ((op >> 4) & 0x7) -#define uMIPS_RS2(op) uMIPS_RS(op) -#define uMIPS_RS1(op) ((op >> 1) & 0x7) -#define uMIPS_RD5(op) ((op >> 5) & 0x1f) -#define uMIPS_RS5(op) (op & 0x1f) - -/* Signed immediate */ -#define SIMM(op, start, width) \ - ((int32_t)(((op >> start) & ((~0U) >> (32 - width))) \ - << (32 - width)) \ - >> (32 - width)) -/* Zero-extended immediate */ -#define ZIMM(op, start, width) ((op >> start) & ((~0U) >> (32 - width))) - -static void gen_addiur1sp(DisasContext *ctx) -{ - int rd = mmreg(uMIPS_RD(ctx->opcode)); - - gen_arith_imm(ctx, OPC_ADDIU, rd, 29, ((ctx->opcode >> 1) & 0x3f) << 2); -} - -static void gen_addiur2(DisasContext *ctx) -{ - static const int decoded_imm[] = { 1, 4, 8, 12, 16, 20, 24, -1 }; - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rs = mmreg(uMIPS_RS(ctx->opcode)); - - gen_arith_imm(ctx, OPC_ADDIU, rd, rs, decoded_imm[ZIMM(ctx->opcode, 1, 3)]); -} - -static void gen_addiusp(DisasContext *ctx) -{ - int encoded = ZIMM(ctx->opcode, 1, 9); - int decoded; - - if (encoded <= 1) { - decoded = 256 + encoded; - } else if (encoded <= 255) { - decoded = encoded; - } else if (encoded <= 509) { - decoded = encoded - 512; - } else { - decoded = encoded - 768; - } - - gen_arith_imm(ctx, OPC_ADDIU, 29, 29, decoded << 2); -} - -static void gen_addius5(DisasContext *ctx) -{ - int imm = SIMM(ctx->opcode, 1, 4); - int rd = (ctx->opcode >> 5) & 0x1f; - - gen_arith_imm(ctx, OPC_ADDIU, rd, rd, imm); -} - -static void gen_andi16(DisasContext *ctx) -{ - static const int decoded_imm[] = { 128, 1, 2, 3, 4, 7, 8, 15, 16, - 31, 32, 63, 64, 255, 32768, 65535 }; - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rs = mmreg(uMIPS_RS(ctx->opcode)); - int encoded = ZIMM(ctx->opcode, 0, 4); - - gen_logic_imm(ctx, OPC_ANDI, rd, rs, decoded_imm[encoded]); -} - -static void gen_ldst_multiple(DisasContext *ctx, uint32_t opc, int reglist, - int base, int16_t offset) -{ - TCGv t0, t1; - TCGv_i32 t2; - - if (ctx->hflags & MIPS_HFLAG_BMASK) { - gen_reserved_instruction(ctx); - return; - } - - t0 = tcg_temp_new(); - - gen_base_offset_addr(ctx, t0, base, offset); - - t1 = tcg_const_tl(reglist); - t2 = tcg_const_i32(ctx->mem_idx); - - save_cpu_state(ctx, 1); - switch (opc) { - case LWM32: - gen_helper_lwm(cpu_env, t0, t1, t2); - break; - case SWM32: - gen_helper_swm(cpu_env, t0, t1, t2); - break; -#ifdef TARGET_MIPS64 - case LDM: - gen_helper_ldm(cpu_env, t0, t1, t2); - break; - case SDM: - gen_helper_sdm(cpu_env, t0, t1, t2); - break; -#endif - } - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free_i32(t2); -} - - -static void gen_pool16c_insn(DisasContext *ctx) -{ - int rd = mmreg((ctx->opcode >> 3) & 0x7); - int rs = mmreg(ctx->opcode & 0x7); - - switch (((ctx->opcode) >> 4) & 0x3f) { - case NOT16 + 0: - case NOT16 + 1: - case NOT16 + 2: - case NOT16 + 3: - gen_logic(ctx, OPC_NOR, rd, rs, 0); - break; - case XOR16 + 0: - case XOR16 + 1: - case XOR16 + 2: - case XOR16 + 3: - gen_logic(ctx, OPC_XOR, rd, rd, rs); - break; - case AND16 + 0: - case AND16 + 1: - case AND16 + 2: - case AND16 + 3: - gen_logic(ctx, OPC_AND, rd, rd, rs); - break; - case OR16 + 0: - case OR16 + 1: - case OR16 + 2: - case OR16 + 3: - gen_logic(ctx, OPC_OR, rd, rd, rs); - break; - case LWM16 + 0: - case LWM16 + 1: - case LWM16 + 2: - case LWM16 + 3: - { - static const int lwm_convert[] = { 0x11, 0x12, 0x13, 0x14 }; - int offset = ZIMM(ctx->opcode, 0, 4); - - gen_ldst_multiple(ctx, LWM32, lwm_convert[(ctx->opcode >> 4) & 0x3], - 29, offset << 2); - } - break; - case SWM16 + 0: - case SWM16 + 1: - case SWM16 + 2: - case SWM16 + 3: - { - static const int swm_convert[] = { 0x11, 0x12, 0x13, 0x14 }; - int offset = ZIMM(ctx->opcode, 0, 4); - - gen_ldst_multiple(ctx, SWM32, swm_convert[(ctx->opcode >> 4) & 0x3], - 29, offset << 2); - } - break; - case JR16 + 0: - case JR16 + 1: - { - int reg = ctx->opcode & 0x1f; - - gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 4); - } - break; - case JRC16 + 0: - case JRC16 + 1: - { - int reg = ctx->opcode & 0x1f; - gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 0); - /* - * Let normal delay slot handling in our caller take us - * to the branch target. - */ - } - break; - case JALR16 + 0: - case JALR16 + 1: - gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 4); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - case JALR16S + 0: - case JALR16S + 1: - gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 2); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - case MFHI16 + 0: - case MFHI16 + 1: - gen_HILO(ctx, OPC_MFHI, 0, uMIPS_RS5(ctx->opcode)); - break; - case MFLO16 + 0: - case MFLO16 + 1: - gen_HILO(ctx, OPC_MFLO, 0, uMIPS_RS5(ctx->opcode)); - break; - case BREAK16: - generate_exception_end(ctx, EXCP_BREAK); - break; - case SDBBP16: - if (is_uhi(extract32(ctx->opcode, 0, 4))) { - gen_helper_do_semihosting(cpu_env); - } else { - /* - * XXX: not clear which exception should be raised - * when in debug mode... - */ - check_insn(ctx, ISA_MIPS_R1); - generate_exception_end(ctx, EXCP_DBp); - } - break; - case JRADDIUSP + 0: - case JRADDIUSP + 1: - { - int imm = ZIMM(ctx->opcode, 0, 5); - gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0); - gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2); - /* - * Let normal delay slot handling in our caller take us - * to the branch target. - */ - } - break; - default: - gen_reserved_instruction(ctx); - break; - } -} - -static inline void gen_movep(DisasContext *ctx, int enc_dest, int enc_rt, - int enc_rs) -{ - int rd, re; - static const int rd_enc[] = { 5, 5, 6, 4, 4, 4, 4, 4 }; - static const int re_enc[] = { 6, 7, 7, 21, 22, 5, 6, 7 }; - static const int rs_rt_enc[] = { 0, 17, 2, 3, 16, 18, 19, 20 }; - - rd = rd_enc[enc_dest]; - re = re_enc[enc_dest]; - gen_load_gpr(cpu_gpr[rd], rs_rt_enc[enc_rs]); - gen_load_gpr(cpu_gpr[re], rs_rt_enc[enc_rt]); -} - -static void gen_pool16c_r6_insn(DisasContext *ctx) -{ - int rt = mmreg((ctx->opcode >> 7) & 0x7); - int rs = mmreg((ctx->opcode >> 4) & 0x7); - - switch (ctx->opcode & 0xf) { - case R6_NOT16: - gen_logic(ctx, OPC_NOR, rt, rs, 0); - break; - case R6_AND16: - gen_logic(ctx, OPC_AND, rt, rt, rs); - break; - case R6_LWM16: - { - int lwm_converted = 0x11 + extract32(ctx->opcode, 8, 2); - int offset = extract32(ctx->opcode, 4, 4); - gen_ldst_multiple(ctx, LWM32, lwm_converted, 29, offset << 2); - } - break; - case R6_JRC16: /* JRCADDIUSP */ - if ((ctx->opcode >> 4) & 1) { - /* JRCADDIUSP */ - int imm = extract32(ctx->opcode, 5, 5); - gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0); - gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2); - } else { - /* JRC16 */ - rs = extract32(ctx->opcode, 5, 5); - gen_compute_branch(ctx, OPC_JR, 2, rs, 0, 0, 0); - } - break; - case MOVEP: - case MOVEP_05: - case MOVEP_06: - case MOVEP_07: - case MOVEP_0C: - case MOVEP_0D: - case MOVEP_0E: - case MOVEP_0F: - { - int enc_dest = uMIPS_RD(ctx->opcode); - int enc_rt = uMIPS_RS2(ctx->opcode); - int enc_rs = (ctx->opcode & 3) | ((ctx->opcode >> 1) & 4); - gen_movep(ctx, enc_dest, enc_rt, enc_rs); - } - break; - case R6_XOR16: - gen_logic(ctx, OPC_XOR, rt, rt, rs); - break; - case R6_OR16: - gen_logic(ctx, OPC_OR, rt, rt, rs); - break; - case R6_SWM16: - { - int swm_converted = 0x11 + extract32(ctx->opcode, 8, 2); - int offset = extract32(ctx->opcode, 4, 4); - gen_ldst_multiple(ctx, SWM32, swm_converted, 29, offset << 2); - } - break; - case JALRC16: /* BREAK16, SDBBP16 */ - switch (ctx->opcode & 0x3f) { - case JALRC16: - case JALRC16 + 0x20: - /* JALRC16 */ - gen_compute_branch(ctx, OPC_JALR, 2, (ctx->opcode >> 5) & 0x1f, - 31, 0, 0); - break; - case R6_BREAK16: - /* BREAK16 */ - generate_exception(ctx, EXCP_BREAK); - break; - case R6_SDBBP16: - /* SDBBP16 */ - if (is_uhi(extract32(ctx->opcode, 6, 4))) { - gen_helper_do_semihosting(cpu_env); - } else { - if (ctx->hflags & MIPS_HFLAG_SBRI) { - generate_exception(ctx, EXCP_RI); - } else { - generate_exception(ctx, EXCP_DBp); - } - } - break; - } - break; - default: - generate_exception(ctx, EXCP_RI); - break; - } -} - -static void gen_ldxs(DisasContext *ctx, int base, int index, int rd) +void gen_ldxs(DisasContext *ctx, int base, int index, int rd) { TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); @@ -14530,69 +12261,6 @@ static void gen_ldxs(DisasContext *ctx, int base, int index, int rd) tcg_temp_free(t1); } -static void gen_ldst_pair(DisasContext *ctx, uint32_t opc, int rd, - int base, int16_t offset) -{ - TCGv t0, t1; - - if (ctx->hflags & MIPS_HFLAG_BMASK || rd == 31) { - gen_reserved_instruction(ctx); - return; - } - - t0 = tcg_temp_new(); - t1 = tcg_temp_new(); - - gen_base_offset_addr(ctx, t0, base, offset); - - switch (opc) { - case LWP: - if (rd == base) { - gen_reserved_instruction(ctx); - return; - } - tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL); - gen_store_gpr(t1, rd); - tcg_gen_movi_tl(t1, 4); - gen_op_addr_add(ctx, t0, t0, t1); - tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL); - gen_store_gpr(t1, rd + 1); - break; - case SWP: - gen_load_gpr(t1, rd); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); - tcg_gen_movi_tl(t1, 4); - gen_op_addr_add(ctx, t0, t0, t1); - gen_load_gpr(t1, rd + 1); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); - break; -#ifdef TARGET_MIPS64 - case LDP: - if (rd == base) { - gen_reserved_instruction(ctx); - return; - } - tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ); - gen_store_gpr(t1, rd); - tcg_gen_movi_tl(t1, 8); - gen_op_addr_add(ctx, t0, t0, t1); - tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ); - gen_store_gpr(t1, rd + 1); - break; - case SDP: - gen_load_gpr(t1, rd); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ); - tcg_gen_movi_tl(t1, 8); - gen_op_addr_add(ctx, t0, t0, t1); - gen_load_gpr(t1, rd + 1); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ); - break; -#endif - } - tcg_temp_free(t0); - tcg_temp_free(t1); -} - static void gen_sync(int stype) { TCGBar tcg_mo = TCG_BAR_SC; @@ -14621,353 +12289,12 @@ static void gen_sync(int stype) tcg_gen_mb(tcg_mo); } -static void gen_pool32axf(CPUMIPSState *env, DisasContext *ctx, int rt, int rs) -{ - int extension = (ctx->opcode >> 6) & 0x3f; - int minor = (ctx->opcode >> 12) & 0xf; - uint32_t mips32_op; - - switch (extension) { - case TEQ: - mips32_op = OPC_TEQ; - goto do_trap; - case TGE: - mips32_op = OPC_TGE; - goto do_trap; - case TGEU: - mips32_op = OPC_TGEU; - goto do_trap; - case TLT: - mips32_op = OPC_TLT; - goto do_trap; - case TLTU: - mips32_op = OPC_TLTU; - goto do_trap; - case TNE: - mips32_op = OPC_TNE; - do_trap: - gen_trap(ctx, mips32_op, rs, rt, -1); - break; -#ifndef CONFIG_USER_ONLY - case MFC0: - case MFC0 + 32: - check_cp0_enabled(ctx); - if (rt == 0) { - /* Treat as NOP. */ - break; - } - gen_mfc0(ctx, cpu_gpr[rt], rs, (ctx->opcode >> 11) & 0x7); - break; - case MTC0: - case MTC0 + 32: - check_cp0_enabled(ctx); - { - TCGv t0 = tcg_temp_new(); - - gen_load_gpr(t0, rt); - gen_mtc0(ctx, t0, rs, (ctx->opcode >> 11) & 0x7); - tcg_temp_free(t0); - } - break; -#endif - case 0x2a: - switch (minor & 3) { - case MADD_ACC: - gen_muldiv(ctx, OPC_MADD, (ctx->opcode >> 14) & 3, rs, rt); - break; - case MADDU_ACC: - gen_muldiv(ctx, OPC_MADDU, (ctx->opcode >> 14) & 3, rs, rt); - break; - case MSUB_ACC: - gen_muldiv(ctx, OPC_MSUB, (ctx->opcode >> 14) & 3, rs, rt); - break; - case MSUBU_ACC: - gen_muldiv(ctx, OPC_MSUBU, (ctx->opcode >> 14) & 3, rs, rt); - break; - default: - goto pool32axf_invalid; - } - break; - case 0x32: - switch (minor & 3) { - case MULT_ACC: - gen_muldiv(ctx, OPC_MULT, (ctx->opcode >> 14) & 3, rs, rt); - break; - case MULTU_ACC: - gen_muldiv(ctx, OPC_MULTU, (ctx->opcode >> 14) & 3, rs, rt); - break; - default: - goto pool32axf_invalid; - } - break; - case 0x2c: - switch (minor) { - case BITSWAP: - check_insn(ctx, ISA_MIPS_R6); - gen_bitswap(ctx, OPC_BITSWAP, rs, rt); - break; - case SEB: - gen_bshfl(ctx, OPC_SEB, rs, rt); - break; - case SEH: - gen_bshfl(ctx, OPC_SEH, rs, rt); - break; - case CLO: - mips32_op = OPC_CLO; - goto do_cl; - case CLZ: - mips32_op = OPC_CLZ; - do_cl: - check_insn(ctx, ISA_MIPS_R1); - gen_cl(ctx, mips32_op, rt, rs); - break; - case RDHWR: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_rdhwr(ctx, rt, rs, 0); - break; - case WSBH: - gen_bshfl(ctx, OPC_WSBH, rs, rt); - break; - case MULT: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MULT; - goto do_mul; - case MULTU: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MULTU; - goto do_mul; - case DIV: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_DIV; - goto do_div; - case DIVU: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_DIVU; - goto do_div; - do_div: - check_insn(ctx, ISA_MIPS_R1); - gen_muldiv(ctx, mips32_op, 0, rs, rt); - break; - case MADD: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MADD; - goto do_mul; - case MADDU: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MADDU; - goto do_mul; - case MSUB: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MSUB; - goto do_mul; - case MSUBU: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MSUBU; - do_mul: - check_insn(ctx, ISA_MIPS_R1); - gen_muldiv(ctx, mips32_op, 0, rs, rt); - break; - default: - goto pool32axf_invalid; - } - break; - case 0x34: - switch (minor) { - case MFC2: - case MTC2: - case MFHC2: - case MTHC2: - case CFC2: - case CTC2: - generate_exception_err(ctx, EXCP_CpU, 2); - break; - default: - goto pool32axf_invalid; - } - break; - case 0x3c: - switch (minor) { - case JALR: /* JALRC */ - case JALR_HB: /* JALRC_HB */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* JALRC, JALRC_HB */ - gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 0); - } else { - /* JALR, JALR_HB */ - gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 4); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - } - break; - case JALRS: - case JALRS_HB: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 2); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - default: - goto pool32axf_invalid; - } - break; - case 0x05: - switch (minor) { - case RDPGPR: - check_cp0_enabled(ctx); - check_insn(ctx, ISA_MIPS_R2); - gen_load_srsgpr(rs, rt); - break; - case WRPGPR: - check_cp0_enabled(ctx); - check_insn(ctx, ISA_MIPS_R2); - gen_store_srsgpr(rs, rt); - break; - default: - goto pool32axf_invalid; - } - break; -#ifndef CONFIG_USER_ONLY - case 0x0d: - switch (minor) { - case TLBP: - mips32_op = OPC_TLBP; - goto do_cp0; - case TLBR: - mips32_op = OPC_TLBR; - goto do_cp0; - case TLBWI: - mips32_op = OPC_TLBWI; - goto do_cp0; - case TLBWR: - mips32_op = OPC_TLBWR; - goto do_cp0; - case TLBINV: - mips32_op = OPC_TLBINV; - goto do_cp0; - case TLBINVF: - mips32_op = OPC_TLBINVF; - goto do_cp0; - case WAIT: - mips32_op = OPC_WAIT; - goto do_cp0; - case DERET: - mips32_op = OPC_DERET; - goto do_cp0; - case ERET: - mips32_op = OPC_ERET; - do_cp0: - gen_cp0(env, ctx, mips32_op, rt, rs); - break; - default: - goto pool32axf_invalid; - } - break; - case 0x1d: - switch (minor) { - case DI: - check_cp0_enabled(ctx); - { - TCGv t0 = tcg_temp_new(); +/* ISA extensions (ASEs) */ - save_cpu_state(ctx, 1); - gen_helper_di(t0, cpu_env); - gen_store_gpr(t0, rs); - /* - * Stop translation as we may have switched the execution - * mode. - */ - ctx->base.is_jmp = DISAS_STOP; - tcg_temp_free(t0); - } - break; - case EI: - check_cp0_enabled(ctx); - { - TCGv t0 = tcg_temp_new(); +/* MIPS16 extension to MIPS32 */ +#include "mips16e_translate.c.inc" - save_cpu_state(ctx, 1); - gen_helper_ei(t0, cpu_env); - gen_store_gpr(t0, rs); - /* - * DISAS_STOP isn't sufficient, we need to ensure we break out - * of translated code to check for pending interrupts. - */ - gen_save_pc(ctx->base.pc_next + 4); - ctx->base.is_jmp = DISAS_EXIT; - tcg_temp_free(t0); - } - break; - default: - goto pool32axf_invalid; - } - break; -#endif - case 0x2d: - switch (minor) { - case SYNC: - gen_sync(extract32(ctx->opcode, 16, 5)); - break; - case SYSCALL: - generate_exception_end(ctx, EXCP_SYSCALL); - break; - case SDBBP: - if (is_uhi(extract32(ctx->opcode, 16, 10))) { - gen_helper_do_semihosting(cpu_env); - } else { - check_insn(ctx, ISA_MIPS_R1); - if (ctx->hflags & MIPS_HFLAG_SBRI) { - gen_reserved_instruction(ctx); - } else { - generate_exception_end(ctx, EXCP_DBp); - } - } - break; - default: - goto pool32axf_invalid; - } - break; - case 0x01: - switch (minor & 3) { - case MFHI_ACC: - gen_HILO(ctx, OPC_MFHI, minor >> 2, rs); - break; - case MFLO_ACC: - gen_HILO(ctx, OPC_MFLO, minor >> 2, rs); - break; - case MTHI_ACC: - gen_HILO(ctx, OPC_MTHI, minor >> 2, rs); - break; - case MTLO_ACC: - gen_HILO(ctx, OPC_MTLO, minor >> 2, rs); - break; - default: - goto pool32axf_invalid; - } - break; - case 0x35: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - switch (minor) { - case MFHI32: - gen_HILO(ctx, OPC_MFHI, 0, rs); - break; - case MFLO32: - gen_HILO(ctx, OPC_MFLO, 0, rs); - break; - case MTHI32: - gen_HILO(ctx, OPC_MTHI, 0, rs); - break; - case MTLO32: - gen_HILO(ctx, OPC_MTLO, 0, rs); - break; - default: - goto pool32axf_invalid; - } - break; - default: - pool32axf_invalid: - MIPS_INVAL("pool32axf"); - gen_reserved_instruction(ctx); - break; - } -} +/* microMIPS extension to MIPS32/MIPS64 */ /* * Values for microMIPS fmt field. Variable-width, depending on which @@ -14990,6587 +12317,9 @@ enum { FMT_DWL_L = 2 }; -static void gen_pool32fxf(DisasContext *ctx, int rt, int rs) -{ - int extension = (ctx->opcode >> 6) & 0x3ff; - uint32_t mips32_op; - -#define FLOAT_1BIT_FMT(opc, fmt) ((fmt << 8) | opc) -#define FLOAT_2BIT_FMT(opc, fmt) ((fmt << 7) | opc) -#define COND_FLOAT_MOV(opc, cond) ((cond << 7) | opc) - - switch (extension) { - case FLOAT_1BIT_FMT(CFC1, 0): - mips32_op = OPC_CFC1; - goto do_cp1; - case FLOAT_1BIT_FMT(CTC1, 0): - mips32_op = OPC_CTC1; - goto do_cp1; - case FLOAT_1BIT_FMT(MFC1, 0): - mips32_op = OPC_MFC1; - goto do_cp1; - case FLOAT_1BIT_FMT(MTC1, 0): - mips32_op = OPC_MTC1; - goto do_cp1; - case FLOAT_1BIT_FMT(MFHC1, 0): - mips32_op = OPC_MFHC1; - goto do_cp1; - case FLOAT_1BIT_FMT(MTHC1, 0): - mips32_op = OPC_MTHC1; - do_cp1: - gen_cp1(ctx, mips32_op, rt, rs); - break; - - /* Reciprocal square root */ - case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_S): - mips32_op = OPC_RSQRT_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_D): - mips32_op = OPC_RSQRT_D; - goto do_unaryfp; - - /* Square root */ - case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_S): - mips32_op = OPC_SQRT_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_D): - mips32_op = OPC_SQRT_D; - goto do_unaryfp; - - /* Reciprocal */ - case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_S): - mips32_op = OPC_RECIP_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_D): - mips32_op = OPC_RECIP_D; - goto do_unaryfp; - - /* Floor */ - case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_S): - mips32_op = OPC_FLOOR_L_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_D): - mips32_op = OPC_FLOOR_L_D; - goto do_unaryfp; - case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_S): - mips32_op = OPC_FLOOR_W_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_D): - mips32_op = OPC_FLOOR_W_D; - goto do_unaryfp; - - /* Ceiling */ - case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_S): - mips32_op = OPC_CEIL_L_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_D): - mips32_op = OPC_CEIL_L_D; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_S): - mips32_op = OPC_CEIL_W_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_D): - mips32_op = OPC_CEIL_W_D; - goto do_unaryfp; - - /* Truncation */ - case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_S): - mips32_op = OPC_TRUNC_L_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_D): - mips32_op = OPC_TRUNC_L_D; - goto do_unaryfp; - case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_S): - mips32_op = OPC_TRUNC_W_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_D): - mips32_op = OPC_TRUNC_W_D; - goto do_unaryfp; - - /* Round */ - case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_S): - mips32_op = OPC_ROUND_L_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_D): - mips32_op = OPC_ROUND_L_D; - goto do_unaryfp; - case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_S): - mips32_op = OPC_ROUND_W_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_D): - mips32_op = OPC_ROUND_W_D; - goto do_unaryfp; - - /* Integer to floating-point conversion */ - case FLOAT_1BIT_FMT(CVT_L, FMT_SD_S): - mips32_op = OPC_CVT_L_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CVT_L, FMT_SD_D): - mips32_op = OPC_CVT_L_D; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CVT_W, FMT_SD_S): - mips32_op = OPC_CVT_W_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CVT_W, FMT_SD_D): - mips32_op = OPC_CVT_W_D; - goto do_unaryfp; - - /* Paired-foo conversions */ - case FLOAT_1BIT_FMT(CVT_S_PL, 0): - mips32_op = OPC_CVT_S_PL; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CVT_S_PU, 0): - mips32_op = OPC_CVT_S_PU; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CVT_PW_PS, 0): - mips32_op = OPC_CVT_PW_PS; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CVT_PS_PW, 0): - mips32_op = OPC_CVT_PS_PW; - goto do_unaryfp; - - /* Floating-point moves */ - case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_S): - mips32_op = OPC_MOV_S; - goto do_unaryfp; - case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_D): - mips32_op = OPC_MOV_D; - goto do_unaryfp; - case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_PS): - mips32_op = OPC_MOV_PS; - goto do_unaryfp; - - /* Absolute value */ - case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_S): - mips32_op = OPC_ABS_S; - goto do_unaryfp; - case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_D): - mips32_op = OPC_ABS_D; - goto do_unaryfp; - case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_PS): - mips32_op = OPC_ABS_PS; - goto do_unaryfp; - - /* Negation */ - case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_S): - mips32_op = OPC_NEG_S; - goto do_unaryfp; - case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_D): - mips32_op = OPC_NEG_D; - goto do_unaryfp; - case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_PS): - mips32_op = OPC_NEG_PS; - goto do_unaryfp; - - /* Reciprocal square root step */ - case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_S): - mips32_op = OPC_RSQRT1_S; - goto do_unaryfp; - case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_D): - mips32_op = OPC_RSQRT1_D; - goto do_unaryfp; - case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_PS): - mips32_op = OPC_RSQRT1_PS; - goto do_unaryfp; - - /* Reciprocal step */ - case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_S): - mips32_op = OPC_RECIP1_S; - goto do_unaryfp; - case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_D): - mips32_op = OPC_RECIP1_S; - goto do_unaryfp; - case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_PS): - mips32_op = OPC_RECIP1_PS; - goto do_unaryfp; - - /* Conversions from double */ - case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_S): - mips32_op = OPC_CVT_D_S; - goto do_unaryfp; - case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_W): - mips32_op = OPC_CVT_D_W; - goto do_unaryfp; - case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_L): - mips32_op = OPC_CVT_D_L; - goto do_unaryfp; - - /* Conversions from single */ - case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_D): - mips32_op = OPC_CVT_S_D; - goto do_unaryfp; - case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_W): - mips32_op = OPC_CVT_S_W; - goto do_unaryfp; - case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_L): - mips32_op = OPC_CVT_S_L; - do_unaryfp: - gen_farith(ctx, mips32_op, -1, rs, rt, 0); - break; - - /* Conditional moves on floating-point codes */ - case COND_FLOAT_MOV(MOVT, 0): - case COND_FLOAT_MOV(MOVT, 1): - case COND_FLOAT_MOV(MOVT, 2): - case COND_FLOAT_MOV(MOVT, 3): - case COND_FLOAT_MOV(MOVT, 4): - case COND_FLOAT_MOV(MOVT, 5): - case COND_FLOAT_MOV(MOVT, 6): - case COND_FLOAT_MOV(MOVT, 7): - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 1); - break; - case COND_FLOAT_MOV(MOVF, 0): - case COND_FLOAT_MOV(MOVF, 1): - case COND_FLOAT_MOV(MOVF, 2): - case COND_FLOAT_MOV(MOVF, 3): - case COND_FLOAT_MOV(MOVF, 4): - case COND_FLOAT_MOV(MOVF, 5): - case COND_FLOAT_MOV(MOVF, 6): - case COND_FLOAT_MOV(MOVF, 7): - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 0); - break; - default: - MIPS_INVAL("pool32fxf"); - gen_reserved_instruction(ctx); - break; - } -} - -static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) -{ - int32_t offset; - uint16_t insn; - int rt, rs, rd, rr; - int16_t imm; - uint32_t op, minor, minor2, mips32_op; - uint32_t cond, fmt, cc; - - insn = translator_lduw(env, ctx->base.pc_next + 2); - ctx->opcode = (ctx->opcode << 16) | insn; - - rt = (ctx->opcode >> 21) & 0x1f; - rs = (ctx->opcode >> 16) & 0x1f; - rd = (ctx->opcode >> 11) & 0x1f; - rr = (ctx->opcode >> 6) & 0x1f; - imm = (int16_t) ctx->opcode; - - op = (ctx->opcode >> 26) & 0x3f; - switch (op) { - case POOL32A: - minor = ctx->opcode & 0x3f; - switch (minor) { - case 0x00: - minor = (ctx->opcode >> 6) & 0xf; - switch (minor) { - case SLL32: - mips32_op = OPC_SLL; - goto do_shifti; - case SRA: - mips32_op = OPC_SRA; - goto do_shifti; - case SRL32: - mips32_op = OPC_SRL; - goto do_shifti; - case ROTR: - mips32_op = OPC_ROTR; - do_shifti: - gen_shift_imm(ctx, mips32_op, rt, rs, rd); - break; - case SELEQZ: - check_insn(ctx, ISA_MIPS_R6); - gen_cond_move(ctx, OPC_SELEQZ, rd, rs, rt); - break; - case SELNEZ: - check_insn(ctx, ISA_MIPS_R6); - gen_cond_move(ctx, OPC_SELNEZ, rd, rs, rt); - break; - case R6_RDHWR: - check_insn(ctx, ISA_MIPS_R6); - gen_rdhwr(ctx, rt, rs, extract32(ctx->opcode, 11, 3)); - break; - default: - goto pool32a_invalid; - } - break; - case 0x10: - minor = (ctx->opcode >> 6) & 0xf; - switch (minor) { - /* Arithmetic */ - case ADD: - mips32_op = OPC_ADD; - goto do_arith; - case ADDU32: - mips32_op = OPC_ADDU; - goto do_arith; - case SUB: - mips32_op = OPC_SUB; - goto do_arith; - case SUBU32: - mips32_op = OPC_SUBU; - goto do_arith; - case MUL: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MUL; - do_arith: - gen_arith(ctx, mips32_op, rd, rs, rt); - break; - /* Shifts */ - case SLLV: - mips32_op = OPC_SLLV; - goto do_shift; - case SRLV: - mips32_op = OPC_SRLV; - goto do_shift; - case SRAV: - mips32_op = OPC_SRAV; - goto do_shift; - case ROTRV: - mips32_op = OPC_ROTRV; - do_shift: - gen_shift(ctx, mips32_op, rd, rs, rt); - break; - /* Logical operations */ - case AND: - mips32_op = OPC_AND; - goto do_logic; - case OR32: - mips32_op = OPC_OR; - goto do_logic; - case NOR: - mips32_op = OPC_NOR; - goto do_logic; - case XOR32: - mips32_op = OPC_XOR; - do_logic: - gen_logic(ctx, mips32_op, rd, rs, rt); - break; - /* Set less than */ - case SLT: - mips32_op = OPC_SLT; - goto do_slt; - case SLTU: - mips32_op = OPC_SLTU; - do_slt: - gen_slt(ctx, mips32_op, rd, rs, rt); - break; - default: - goto pool32a_invalid; - } - break; - case 0x18: - minor = (ctx->opcode >> 6) & 0xf; - switch (minor) { - /* Conditional moves */ - case MOVN: /* MUL */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* MUL */ - gen_r6_muldiv(ctx, R6_OPC_MUL, rd, rs, rt); - } else { - /* MOVN */ - gen_cond_move(ctx, OPC_MOVN, rd, rs, rt); - } - break; - case MOVZ: /* MUH */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* MUH */ - gen_r6_muldiv(ctx, R6_OPC_MUH, rd, rs, rt); - } else { - /* MOVZ */ - gen_cond_move(ctx, OPC_MOVZ, rd, rs, rt); - } - break; - case MULU: - check_insn(ctx, ISA_MIPS_R6); - gen_r6_muldiv(ctx, R6_OPC_MULU, rd, rs, rt); - break; - case MUHU: - check_insn(ctx, ISA_MIPS_R6); - gen_r6_muldiv(ctx, R6_OPC_MUHU, rd, rs, rt); - break; - case LWXS: /* DIV */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* DIV */ - gen_r6_muldiv(ctx, R6_OPC_DIV, rd, rs, rt); - } else { - /* LWXS */ - gen_ldxs(ctx, rs, rt, rd); - } - break; - case MOD: - check_insn(ctx, ISA_MIPS_R6); - gen_r6_muldiv(ctx, R6_OPC_MOD, rd, rs, rt); - break; - case R6_DIVU: - check_insn(ctx, ISA_MIPS_R6); - gen_r6_muldiv(ctx, R6_OPC_DIVU, rd, rs, rt); - break; - case MODU: - check_insn(ctx, ISA_MIPS_R6); - gen_r6_muldiv(ctx, R6_OPC_MODU, rd, rs, rt); - break; - default: - goto pool32a_invalid; - } - break; - case INS: - gen_bitops(ctx, OPC_INS, rt, rs, rr, rd); - return; - case LSA: - check_insn(ctx, ISA_MIPS_R6); - gen_lsa(ctx, rd, rt, rs, extract32(ctx->opcode, 9, 2)); - break; - case ALIGN: - check_insn(ctx, ISA_MIPS_R6); - gen_align(ctx, 32, rd, rs, rt, extract32(ctx->opcode, 9, 2)); - break; - case EXT: - gen_bitops(ctx, OPC_EXT, rt, rs, rr, rd); - return; - case POOL32AXF: - gen_pool32axf(env, ctx, rt, rs); - break; - case BREAK32: - generate_exception_end(ctx, EXCP_BREAK); - break; - case SIGRIE: - check_insn(ctx, ISA_MIPS_R6); - gen_reserved_instruction(ctx); - break; - default: - pool32a_invalid: - MIPS_INVAL("pool32a"); - gen_reserved_instruction(ctx); - break; - } - break; - case POOL32B: - minor = (ctx->opcode >> 12) & 0xf; - switch (minor) { - case CACHE: - check_cp0_enabled(ctx); - if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) { - gen_cache_operation(ctx, rt, rs, imm); - } - break; - case LWC2: - case SWC2: - /* COP2: Not implemented. */ - generate_exception_err(ctx, EXCP_CpU, 2); - break; -#ifdef TARGET_MIPS64 - case LDP: - case SDP: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); -#endif - /* fall through */ - case LWP: - case SWP: - gen_ldst_pair(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12)); - break; -#ifdef TARGET_MIPS64 - case LDM: - case SDM: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); -#endif - /* fall through */ - case LWM32: - case SWM32: - gen_ldst_multiple(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12)); - break; - default: - MIPS_INVAL("pool32b"); - gen_reserved_instruction(ctx); - break; - } - break; - case POOL32F: - if (ctx->CP0_Config1 & (1 << CP0C1_FP)) { - minor = ctx->opcode & 0x3f; - check_cp1_enabled(ctx); - switch (minor) { - case ALNV_PS: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_ALNV_PS; - goto do_madd; - case MADD_S: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MADD_S; - goto do_madd; - case MADD_D: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MADD_D; - goto do_madd; - case MADD_PS: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MADD_PS; - goto do_madd; - case MSUB_S: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MSUB_S; - goto do_madd; - case MSUB_D: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MSUB_D; - goto do_madd; - case MSUB_PS: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MSUB_PS; - goto do_madd; - case NMADD_S: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_NMADD_S; - goto do_madd; - case NMADD_D: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_NMADD_D; - goto do_madd; - case NMADD_PS: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_NMADD_PS; - goto do_madd; - case NMSUB_S: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_NMSUB_S; - goto do_madd; - case NMSUB_D: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_NMSUB_D; - goto do_madd; - case NMSUB_PS: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_NMSUB_PS; - do_madd: - gen_flt3_arith(ctx, mips32_op, rd, rr, rs, rt); - break; - case CABS_COND_FMT: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - cond = (ctx->opcode >> 6) & 0xf; - cc = (ctx->opcode >> 13) & 0x7; - fmt = (ctx->opcode >> 10) & 0x3; - switch (fmt) { - case 0x0: - gen_cmpabs_s(ctx, cond, rt, rs, cc); - break; - case 0x1: - gen_cmpabs_d(ctx, cond, rt, rs, cc); - break; - case 0x2: - gen_cmpabs_ps(ctx, cond, rt, rs, cc); - break; - default: - goto pool32f_invalid; - } - break; - case C_COND_FMT: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - cond = (ctx->opcode >> 6) & 0xf; - cc = (ctx->opcode >> 13) & 0x7; - fmt = (ctx->opcode >> 10) & 0x3; - switch (fmt) { - case 0x0: - gen_cmp_s(ctx, cond, rt, rs, cc); - break; - case 0x1: - gen_cmp_d(ctx, cond, rt, rs, cc); - break; - case 0x2: - gen_cmp_ps(ctx, cond, rt, rs, cc); - break; - default: - goto pool32f_invalid; - } - break; - case CMP_CONDN_S: - check_insn(ctx, ISA_MIPS_R6); - gen_r6_cmp_s(ctx, (ctx->opcode >> 6) & 0x1f, rt, rs, rd); - break; - case CMP_CONDN_D: - check_insn(ctx, ISA_MIPS_R6); - gen_r6_cmp_d(ctx, (ctx->opcode >> 6) & 0x1f, rt, rs, rd); - break; - case POOL32FXF: - gen_pool32fxf(ctx, rt, rs); - break; - case 0x00: - /* PLL foo */ - switch ((ctx->opcode >> 6) & 0x7) { - case PLL_PS: - mips32_op = OPC_PLL_PS; - goto do_ps; - case PLU_PS: - mips32_op = OPC_PLU_PS; - goto do_ps; - case PUL_PS: - mips32_op = OPC_PUL_PS; - goto do_ps; - case PUU_PS: - mips32_op = OPC_PUU_PS; - goto do_ps; - case CVT_PS_S: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_CVT_PS_S; - do_ps: - gen_farith(ctx, mips32_op, rt, rs, rd, 0); - break; - default: - goto pool32f_invalid; - } - break; - case MIN_FMT: - check_insn(ctx, ISA_MIPS_R6); - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_MIN_S, rt, rs, rd, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_MIN_D, rt, rs, rd, 0); - break; - default: - goto pool32f_invalid; - } - break; - case 0x08: - /* [LS][WDU]XC1 */ - switch ((ctx->opcode >> 6) & 0x7) { - case LWXC1: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LWXC1; - goto do_ldst_cp1; - case SWXC1: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SWXC1; - goto do_ldst_cp1; - case LDXC1: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LDXC1; - goto do_ldst_cp1; - case SDXC1: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SDXC1; - goto do_ldst_cp1; - case LUXC1: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LUXC1; - goto do_ldst_cp1; - case SUXC1: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SUXC1; - do_ldst_cp1: - gen_flt3_ldst(ctx, mips32_op, rd, rd, rt, rs); - break; - default: - goto pool32f_invalid; - } - break; - case MAX_FMT: - check_insn(ctx, ISA_MIPS_R6); - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_MAX_S, rt, rs, rd, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_MAX_D, rt, rs, rd, 0); - break; - default: - goto pool32f_invalid; - } - break; - case 0x18: - /* 3D insns */ - check_insn_opc_removed(ctx, ISA_MIPS_R6); - fmt = (ctx->opcode >> 9) & 0x3; - switch ((ctx->opcode >> 6) & 0x7) { - case RSQRT2_FMT: - switch (fmt) { - case FMT_SDPS_S: - mips32_op = OPC_RSQRT2_S; - goto do_3d; - case FMT_SDPS_D: - mips32_op = OPC_RSQRT2_D; - goto do_3d; - case FMT_SDPS_PS: - mips32_op = OPC_RSQRT2_PS; - goto do_3d; - default: - goto pool32f_invalid; - } - break; - case RECIP2_FMT: - switch (fmt) { - case FMT_SDPS_S: - mips32_op = OPC_RECIP2_S; - goto do_3d; - case FMT_SDPS_D: - mips32_op = OPC_RECIP2_D; - goto do_3d; - case FMT_SDPS_PS: - mips32_op = OPC_RECIP2_PS; - goto do_3d; - default: - goto pool32f_invalid; - } - break; - case ADDR_PS: - mips32_op = OPC_ADDR_PS; - goto do_3d; - case MULR_PS: - mips32_op = OPC_MULR_PS; - do_3d: - gen_farith(ctx, mips32_op, rt, rs, rd, 0); - break; - default: - goto pool32f_invalid; - } - break; - case 0x20: - /* MOV[FT].fmt, PREFX, RINT.fmt, CLASS.fmt*/ - cc = (ctx->opcode >> 13) & 0x7; - fmt = (ctx->opcode >> 9) & 0x3; - switch ((ctx->opcode >> 6) & 0x7) { - case MOVF_FMT: /* RINT_FMT */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* RINT_FMT */ - switch (fmt) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_RINT_S, 0, rt, rs, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_RINT_D, 0, rt, rs, 0); - break; - default: - goto pool32f_invalid; - } - } else { - /* MOVF_FMT */ - switch (fmt) { - case FMT_SDPS_S: - gen_movcf_s(ctx, rs, rt, cc, 0); - break; - case FMT_SDPS_D: - gen_movcf_d(ctx, rs, rt, cc, 0); - break; - case FMT_SDPS_PS: - check_ps(ctx); - gen_movcf_ps(ctx, rs, rt, cc, 0); - break; - default: - goto pool32f_invalid; - } - } - break; - case MOVT_FMT: /* CLASS_FMT */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* CLASS_FMT */ - switch (fmt) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_CLASS_S, 0, rt, rs, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_CLASS_D, 0, rt, rs, 0); - break; - default: - goto pool32f_invalid; - } - } else { - /* MOVT_FMT */ - switch (fmt) { - case FMT_SDPS_S: - gen_movcf_s(ctx, rs, rt, cc, 1); - break; - case FMT_SDPS_D: - gen_movcf_d(ctx, rs, rt, cc, 1); - break; - case FMT_SDPS_PS: - check_ps(ctx); - gen_movcf_ps(ctx, rs, rt, cc, 1); - break; - default: - goto pool32f_invalid; - } - } - break; - case PREFX: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - break; - default: - goto pool32f_invalid; - } - break; -#define FINSN_3ARG_SDPS(prfx) \ - switch ((ctx->opcode >> 8) & 0x3) { \ - case FMT_SDPS_S: \ - mips32_op = OPC_##prfx##_S; \ - goto do_fpop; \ - case FMT_SDPS_D: \ - mips32_op = OPC_##prfx##_D; \ - goto do_fpop; \ - case FMT_SDPS_PS: \ - check_ps(ctx); \ - mips32_op = OPC_##prfx##_PS; \ - goto do_fpop; \ - default: \ - goto pool32f_invalid; \ - } - case MINA_FMT: - check_insn(ctx, ISA_MIPS_R6); - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_MINA_S, rt, rs, rd, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_MINA_D, rt, rs, rd, 0); - break; - default: - goto pool32f_invalid; - } - break; - case MAXA_FMT: - check_insn(ctx, ISA_MIPS_R6); - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_MAXA_S, rt, rs, rd, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_MAXA_D, rt, rs, rd, 0); - break; - default: - goto pool32f_invalid; - } - break; - case 0x30: - /* regular FP ops */ - switch ((ctx->opcode >> 6) & 0x3) { - case ADD_FMT: - FINSN_3ARG_SDPS(ADD); - break; - case SUB_FMT: - FINSN_3ARG_SDPS(SUB); - break; - case MUL_FMT: - FINSN_3ARG_SDPS(MUL); - break; - case DIV_FMT: - fmt = (ctx->opcode >> 8) & 0x3; - if (fmt == 1) { - mips32_op = OPC_DIV_D; - } else if (fmt == 0) { - mips32_op = OPC_DIV_S; - } else { - goto pool32f_invalid; - } - goto do_fpop; - default: - goto pool32f_invalid; - } - break; - case 0x38: - /* cmovs */ - switch ((ctx->opcode >> 6) & 0x7) { - case MOVN_FMT: /* SELEQZ_FMT */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* SELEQZ_FMT */ - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - gen_sel_s(ctx, OPC_SELEQZ_S, rd, rt, rs); - break; - case FMT_SDPS_D: - gen_sel_d(ctx, OPC_SELEQZ_D, rd, rt, rs); - break; - default: - goto pool32f_invalid; - } - } else { - /* MOVN_FMT */ - FINSN_3ARG_SDPS(MOVN); - } - break; - case MOVN_FMT_04: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - FINSN_3ARG_SDPS(MOVN); - break; - case MOVZ_FMT: /* SELNEZ_FMT */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* SELNEZ_FMT */ - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - gen_sel_s(ctx, OPC_SELNEZ_S, rd, rt, rs); - break; - case FMT_SDPS_D: - gen_sel_d(ctx, OPC_SELNEZ_D, rd, rt, rs); - break; - default: - goto pool32f_invalid; - } - } else { - /* MOVZ_FMT */ - FINSN_3ARG_SDPS(MOVZ); - } - break; - case MOVZ_FMT_05: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - FINSN_3ARG_SDPS(MOVZ); - break; - case SEL_FMT: - check_insn(ctx, ISA_MIPS_R6); - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - gen_sel_s(ctx, OPC_SEL_S, rd, rt, rs); - break; - case FMT_SDPS_D: - gen_sel_d(ctx, OPC_SEL_D, rd, rt, rs); - break; - default: - goto pool32f_invalid; - } - break; - case MADDF_FMT: - check_insn(ctx, ISA_MIPS_R6); - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - mips32_op = OPC_MADDF_S; - goto do_fpop; - case FMT_SDPS_D: - mips32_op = OPC_MADDF_D; - goto do_fpop; - default: - goto pool32f_invalid; - } - break; - case MSUBF_FMT: - check_insn(ctx, ISA_MIPS_R6); - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - mips32_op = OPC_MSUBF_S; - goto do_fpop; - case FMT_SDPS_D: - mips32_op = OPC_MSUBF_D; - goto do_fpop; - default: - goto pool32f_invalid; - } - break; - default: - goto pool32f_invalid; - } - break; - do_fpop: - gen_farith(ctx, mips32_op, rt, rs, rd, 0); - break; - default: - pool32f_invalid: - MIPS_INVAL("pool32f"); - gen_reserved_instruction(ctx); - break; - } - } else { - generate_exception_err(ctx, EXCP_CpU, 1); - } - break; - case POOL32I: - minor = (ctx->opcode >> 21) & 0x1f; - switch (minor) { - case BLTZ: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BLTZ, 4, rs, -1, imm << 1, 4); - break; - case BLTZAL: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 4); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - case BLTZALS: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 2); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - case BGEZ: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BGEZ, 4, rs, -1, imm << 1, 4); - break; - case BGEZAL: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 4); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - case BGEZALS: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 2); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - case BLEZ: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BLEZ, 4, rs, -1, imm << 1, 4); - break; - case BGTZ: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BGTZ, 4, rs, -1, imm << 1, 4); - break; - - /* Traps */ - case TLTI: /* BC1EQZC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* BC1EQZC */ - check_cp1_enabled(ctx); - gen_compute_branch1_r6(ctx, OPC_BC1EQZ, rs, imm << 1, 0); - } else { - /* TLTI */ - mips32_op = OPC_TLTI; - goto do_trapi; - } - break; - case TGEI: /* BC1NEZC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* BC1NEZC */ - check_cp1_enabled(ctx); - gen_compute_branch1_r6(ctx, OPC_BC1NEZ, rs, imm << 1, 0); - } else { - /* TGEI */ - mips32_op = OPC_TGEI; - goto do_trapi; - } - break; - case TLTIU: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_TLTIU; - goto do_trapi; - case TGEIU: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_TGEIU; - goto do_trapi; - case TNEI: /* SYNCI */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* SYNCI */ - /* - * Break the TB to be able to sync copied instructions - * immediately. - */ - ctx->base.is_jmp = DISAS_STOP; - } else { - /* TNEI */ - mips32_op = OPC_TNEI; - goto do_trapi; - } - break; - case TEQI: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_TEQI; - do_trapi: - gen_trap(ctx, mips32_op, rs, -1, imm); - break; - - case BNEZC: - case BEQZC: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ, - 4, rs, 0, imm << 1, 0); - /* - * Compact branches don't have a delay slot, so just let - * the normal delay slot handling take us to the branch - * target. - */ - break; - case LUI: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_logic_imm(ctx, OPC_LUI, rs, 0, imm); - break; - case SYNCI: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - /* - * Break the TB to be able to sync copied instructions - * immediately. - */ - ctx->base.is_jmp = DISAS_STOP; - break; - case BC2F: - case BC2T: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - /* COP2: Not implemented. */ - generate_exception_err(ctx, EXCP_CpU, 2); - break; - case BC1F: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1FANY2 : OPC_BC1F; - goto do_cp1branch; - case BC1T: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1TANY2 : OPC_BC1T; - goto do_cp1branch; - case BC1ANY4F: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_BC1FANY4; - goto do_cp1mips3d; - case BC1ANY4T: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_BC1TANY4; - do_cp1mips3d: - check_cop1x(ctx); - check_insn(ctx, ASE_MIPS3D); - /* Fall through */ - do_cp1branch: - if (env->CP0_Config1 & (1 << CP0C1_FP)) { - check_cp1_enabled(ctx); - gen_compute_branch1(ctx, mips32_op, - (ctx->opcode >> 18) & 0x7, imm << 1); - } else { - generate_exception_err(ctx, EXCP_CpU, 1); - } - break; - default: - MIPS_INVAL("pool32i"); - gen_reserved_instruction(ctx); - break; - } - break; - case POOL32C: - minor = (ctx->opcode >> 12) & 0xf; - offset = sextract32(ctx->opcode, 0, - (ctx->insn_flags & ISA_MIPS_R6) ? 9 : 12); - switch (minor) { - case LWL: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LWL; - goto do_ld_lr; - case SWL: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SWL; - goto do_st_lr; - case LWR: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LWR; - goto do_ld_lr; - case SWR: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SWR; - goto do_st_lr; -#if defined(TARGET_MIPS64) - case LDL: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LDL; - goto do_ld_lr; - case SDL: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SDL; - goto do_st_lr; - case LDR: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LDR; - goto do_ld_lr; - case SDR: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SDR; - goto do_st_lr; - case LWU: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - mips32_op = OPC_LWU; - goto do_ld_lr; - case LLD: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - mips32_op = OPC_LLD; - goto do_ld_lr; -#endif - case LL: - mips32_op = OPC_LL; - goto do_ld_lr; - do_ld_lr: - gen_ld(ctx, mips32_op, rt, rs, offset); - break; - do_st_lr: - gen_st(ctx, mips32_op, rt, rs, offset); - break; - case SC: - gen_st_cond(ctx, rt, rs, offset, MO_TESL, false); - break; -#if defined(TARGET_MIPS64) - case SCD: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_st_cond(ctx, rt, rs, offset, MO_TEQ, false); - break; -#endif - case LD_EVA: - if (!ctx->eva) { - MIPS_INVAL("pool32c ld-eva"); - gen_reserved_instruction(ctx); - break; - } - check_cp0_enabled(ctx); - - minor2 = (ctx->opcode >> 9) & 0x7; - offset = sextract32(ctx->opcode, 0, 9); - switch (minor2) { - case LBUE: - mips32_op = OPC_LBUE; - goto do_ld_lr; - case LHUE: - mips32_op = OPC_LHUE; - goto do_ld_lr; - case LWLE: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LWLE; - goto do_ld_lr; - case LWRE: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LWRE; - goto do_ld_lr; - case LBE: - mips32_op = OPC_LBE; - goto do_ld_lr; - case LHE: - mips32_op = OPC_LHE; - goto do_ld_lr; - case LLE: - mips32_op = OPC_LLE; - goto do_ld_lr; - case LWE: - mips32_op = OPC_LWE; - goto do_ld_lr; - }; - break; - case ST_EVA: - if (!ctx->eva) { - MIPS_INVAL("pool32c st-eva"); - gen_reserved_instruction(ctx); - break; - } - check_cp0_enabled(ctx); - - minor2 = (ctx->opcode >> 9) & 0x7; - offset = sextract32(ctx->opcode, 0, 9); - switch (minor2) { - case SWLE: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SWLE; - goto do_st_lr; - case SWRE: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SWRE; - goto do_st_lr; - case PREFE: - /* Treat as no-op */ - if ((ctx->insn_flags & ISA_MIPS_R6) && (rt >= 24)) { - /* hint codes 24-31 are reserved and signal RI */ - generate_exception(ctx, EXCP_RI); - } - break; - case CACHEE: - /* Treat as no-op */ - if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) { - gen_cache_operation(ctx, rt, rs, offset); - } - break; - case SBE: - mips32_op = OPC_SBE; - goto do_st_lr; - case SHE: - mips32_op = OPC_SHE; - goto do_st_lr; - case SCE: - gen_st_cond(ctx, rt, rs, offset, MO_TESL, true); - break; - case SWE: - mips32_op = OPC_SWE; - goto do_st_lr; - }; - break; - case PREF: - /* Treat as no-op */ - if ((ctx->insn_flags & ISA_MIPS_R6) && (rt >= 24)) { - /* hint codes 24-31 are reserved and signal RI */ - generate_exception(ctx, EXCP_RI); - } - break; - default: - MIPS_INVAL("pool32c"); - gen_reserved_instruction(ctx); - break; - } - break; - case ADDI32: /* AUI, LUI */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* AUI, LUI */ - gen_logic_imm(ctx, OPC_LUI, rt, rs, imm); - } else { - /* ADDI32 */ - mips32_op = OPC_ADDI; - goto do_addi; - } - break; - case ADDIU32: - mips32_op = OPC_ADDIU; - do_addi: - gen_arith_imm(ctx, mips32_op, rt, rs, imm); - break; - - /* Logical operations */ - case ORI32: - mips32_op = OPC_ORI; - goto do_logici; - case XORI32: - mips32_op = OPC_XORI; - goto do_logici; - case ANDI32: - mips32_op = OPC_ANDI; - do_logici: - gen_logic_imm(ctx, mips32_op, rt, rs, imm); - break; - - /* Set less than immediate */ - case SLTI32: - mips32_op = OPC_SLTI; - goto do_slti; - case SLTIU32: - mips32_op = OPC_SLTIU; - do_slti: - gen_slt_imm(ctx, mips32_op, rt, rs, imm); - break; - case JALX32: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; - gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset, 4); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - case JALS32: /* BOVC, BEQC, BEQZALC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - if (rs >= rt) { - /* BOVC */ - mips32_op = OPC_BOVC; - } else if (rs < rt && rs == 0) { - /* BEQZALC */ - mips32_op = OPC_BEQZALC; - } else { - /* BEQC */ - mips32_op = OPC_BEQC; - } - gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); - } else { - /* JALS32 */ - offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1; - gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, offset, 2); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - } - break; - case BEQ32: /* BC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* BC */ - gen_compute_compact_branch(ctx, OPC_BC, 0, 0, - sextract32(ctx->opcode << 1, 0, 27)); - } else { - /* BEQ32 */ - gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1, 4); - } - break; - case BNE32: /* BALC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* BALC */ - gen_compute_compact_branch(ctx, OPC_BALC, 0, 0, - sextract32(ctx->opcode << 1, 0, 27)); - } else { - /* BNE32 */ - gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1, 4); - } - break; - case J32: /* BGTZC, BLTZC, BLTC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - if (rs == 0 && rt != 0) { - /* BGTZC */ - mips32_op = OPC_BGTZC; - } else if (rs != 0 && rt != 0 && rs == rt) { - /* BLTZC */ - mips32_op = OPC_BLTZC; - } else { - /* BLTC */ - mips32_op = OPC_BLTC; - } - gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); - } else { - /* J32 */ - gen_compute_branch(ctx, OPC_J, 4, rt, rs, - (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); - } - break; - case JAL32: /* BLEZC, BGEZC, BGEC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - if (rs == 0 && rt != 0) { - /* BLEZC */ - mips32_op = OPC_BLEZC; - } else if (rs != 0 && rt != 0 && rs == rt) { - /* BGEZC */ - mips32_op = OPC_BGEZC; - } else { - /* BGEC */ - mips32_op = OPC_BGEC; - } - gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); - } else { - /* JAL32 */ - gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, - (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - } - break; - /* Floating point (COP1) */ - case LWC132: - mips32_op = OPC_LWC1; - goto do_cop1; - case LDC132: - mips32_op = OPC_LDC1; - goto do_cop1; - case SWC132: - mips32_op = OPC_SWC1; - goto do_cop1; - case SDC132: - mips32_op = OPC_SDC1; - do_cop1: - gen_cop1_ldst(ctx, mips32_op, rt, rs, imm); - break; - case ADDIUPC: /* PCREL: ADDIUPC, AUIPC, ALUIPC, LWPC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* PCREL: ADDIUPC, AUIPC, ALUIPC, LWPC */ - switch ((ctx->opcode >> 16) & 0x1f) { - case ADDIUPC_00: - case ADDIUPC_01: - case ADDIUPC_02: - case ADDIUPC_03: - case ADDIUPC_04: - case ADDIUPC_05: - case ADDIUPC_06: - case ADDIUPC_07: - gen_pcrel(ctx, OPC_ADDIUPC, ctx->base.pc_next & ~0x3, rt); - break; - case AUIPC: - gen_pcrel(ctx, OPC_AUIPC, ctx->base.pc_next, rt); - break; - case ALUIPC: - gen_pcrel(ctx, OPC_ALUIPC, ctx->base.pc_next, rt); - break; - case LWPC_08: - case LWPC_09: - case LWPC_0A: - case LWPC_0B: - case LWPC_0C: - case LWPC_0D: - case LWPC_0E: - case LWPC_0F: - gen_pcrel(ctx, R6_OPC_LWPC, ctx->base.pc_next & ~0x3, rt); - break; - default: - generate_exception(ctx, EXCP_RI); - break; - } - } else { - /* ADDIUPC */ - int reg = mmreg(ZIMM(ctx->opcode, 23, 3)); - offset = SIMM(ctx->opcode, 0, 23) << 2; - - gen_addiupc(ctx, reg, offset, 0, 0); - } - break; - case BNVC: /* BNEC, BNEZALC */ - check_insn(ctx, ISA_MIPS_R6); - if (rs >= rt) { - /* BNVC */ - mips32_op = OPC_BNVC; - } else if (rs < rt && rs == 0) { - /* BNEZALC */ - mips32_op = OPC_BNEZALC; - } else { - /* BNEC */ - mips32_op = OPC_BNEC; - } - gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); - break; - case R6_BNEZC: /* JIALC */ - check_insn(ctx, ISA_MIPS_R6); - if (rt != 0) { - /* BNEZC */ - gen_compute_compact_branch(ctx, OPC_BNEZC, rt, 0, - sextract32(ctx->opcode << 1, 0, 22)); - } else { - /* JIALC */ - gen_compute_compact_branch(ctx, OPC_JIALC, 0, rs, imm); - } - break; - case R6_BEQZC: /* JIC */ - check_insn(ctx, ISA_MIPS_R6); - if (rt != 0) { - /* BEQZC */ - gen_compute_compact_branch(ctx, OPC_BEQZC, rt, 0, - sextract32(ctx->opcode << 1, 0, 22)); - } else { - /* JIC */ - gen_compute_compact_branch(ctx, OPC_JIC, 0, rs, imm); - } - break; - case BLEZALC: /* BGEZALC, BGEUC */ - check_insn(ctx, ISA_MIPS_R6); - if (rs == 0 && rt != 0) { - /* BLEZALC */ - mips32_op = OPC_BLEZALC; - } else if (rs != 0 && rt != 0 && rs == rt) { - /* BGEZALC */ - mips32_op = OPC_BGEZALC; - } else { - /* BGEUC */ - mips32_op = OPC_BGEUC; - } - gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); - break; - case BGTZALC: /* BLTZALC, BLTUC */ - check_insn(ctx, ISA_MIPS_R6); - if (rs == 0 && rt != 0) { - /* BGTZALC */ - mips32_op = OPC_BGTZALC; - } else if (rs != 0 && rt != 0 && rs == rt) { - /* BLTZALC */ - mips32_op = OPC_BLTZALC; - } else { - /* BLTUC */ - mips32_op = OPC_BLTUC; - } - gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); - break; - /* Loads and stores */ - case LB32: - mips32_op = OPC_LB; - goto do_ld; - case LBU32: - mips32_op = OPC_LBU; - goto do_ld; - case LH32: - mips32_op = OPC_LH; - goto do_ld; - case LHU32: - mips32_op = OPC_LHU; - goto do_ld; - case LW32: - mips32_op = OPC_LW; - goto do_ld; -#ifdef TARGET_MIPS64 - case LD32: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - mips32_op = OPC_LD; - goto do_ld; - case SD32: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - mips32_op = OPC_SD; - goto do_st; -#endif - case SB32: - mips32_op = OPC_SB; - goto do_st; - case SH32: - mips32_op = OPC_SH; - goto do_st; - case SW32: - mips32_op = OPC_SW; - goto do_st; - do_ld: - gen_ld(ctx, mips32_op, rt, rs, imm); - break; - do_st: - gen_st(ctx, mips32_op, rt, rs, imm); - break; - default: - gen_reserved_instruction(ctx); - break; - } -} - -static int decode_micromips_opc(CPUMIPSState *env, DisasContext *ctx) -{ - uint32_t op; - - /* make sure instructions are on a halfword boundary */ - if (ctx->base.pc_next & 0x1) { - env->CP0_BadVAddr = ctx->base.pc_next; - generate_exception_end(ctx, EXCP_AdEL); - return 2; - } - - op = (ctx->opcode >> 10) & 0x3f; - /* Enforce properly-sized instructions in a delay slot */ - if (ctx->hflags & MIPS_HFLAG_BDS_STRICT) { - switch (op & 0x7) { /* MSB-3..MSB-5 */ - case 0: - /* POOL32A, POOL32B, POOL32I, POOL32C */ - case 4: - /* ADDI32, ADDIU32, ORI32, XORI32, SLTI32, SLTIU32, ANDI32, JALX32 */ - case 5: - /* LBU32, LHU32, POOL32F, JALS32, BEQ32, BNE32, J32, JAL32 */ - case 6: - /* SB32, SH32, ADDIUPC, SWC132, SDC132, SW32 */ - case 7: - /* LB32, LH32, LWC132, LDC132, LW32 */ - if (ctx->hflags & MIPS_HFLAG_BDS16) { - gen_reserved_instruction(ctx); - return 2; - } - break; - case 1: - /* POOL16A, POOL16B, POOL16C, LWGP16, POOL16F */ - case 2: - /* LBU16, LHU16, LWSP16, LW16, SB16, SH16, SWSP16, SW16 */ - case 3: - /* MOVE16, ANDI16, POOL16D, POOL16E, BEQZ16, BNEZ16, B16, LI16 */ - if (ctx->hflags & MIPS_HFLAG_BDS32) { - gen_reserved_instruction(ctx); - return 2; - } - break; - } - } - - switch (op) { - case POOL16A: - { - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rs1 = mmreg(uMIPS_RS1(ctx->opcode)); - int rs2 = mmreg(uMIPS_RS2(ctx->opcode)); - uint32_t opc = 0; - - switch (ctx->opcode & 0x1) { - case ADDU16: - opc = OPC_ADDU; - break; - case SUBU16: - opc = OPC_SUBU; - break; - } - if (ctx->insn_flags & ISA_MIPS_R6) { - /* - * In the Release 6, the register number location in - * the instruction encoding has changed. - */ - gen_arith(ctx, opc, rs1, rd, rs2); - } else { - gen_arith(ctx, opc, rd, rs1, rs2); - } - } - break; - case POOL16B: - { - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rs = mmreg(uMIPS_RS(ctx->opcode)); - int amount = (ctx->opcode >> 1) & 0x7; - uint32_t opc = 0; - amount = amount == 0 ? 8 : amount; - - switch (ctx->opcode & 0x1) { - case SLL16: - opc = OPC_SLL; - break; - case SRL16: - opc = OPC_SRL; - break; - } - - gen_shift_imm(ctx, opc, rd, rs, amount); - } - break; - case POOL16C: - if (ctx->insn_flags & ISA_MIPS_R6) { - gen_pool16c_r6_insn(ctx); - } else { - gen_pool16c_insn(ctx); - } - break; - case LWGP16: - { - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rb = 28; /* GP */ - int16_t offset = SIMM(ctx->opcode, 0, 7) << 2; - - gen_ld(ctx, OPC_LW, rd, rb, offset); - } - break; - case POOL16F: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - if (ctx->opcode & 1) { - gen_reserved_instruction(ctx); - } else { - /* MOVEP */ - int enc_dest = uMIPS_RD(ctx->opcode); - int enc_rt = uMIPS_RS2(ctx->opcode); - int enc_rs = uMIPS_RS1(ctx->opcode); - gen_movep(ctx, enc_dest, enc_rt, enc_rs); - } - break; - case LBU16: - { - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rb = mmreg(uMIPS_RS(ctx->opcode)); - int16_t offset = ZIMM(ctx->opcode, 0, 4); - offset = (offset == 0xf ? -1 : offset); - - gen_ld(ctx, OPC_LBU, rd, rb, offset); - } - break; - case LHU16: - { - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rb = mmreg(uMIPS_RS(ctx->opcode)); - int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1; - - gen_ld(ctx, OPC_LHU, rd, rb, offset); - } - break; - case LWSP16: - { - int rd = (ctx->opcode >> 5) & 0x1f; - int rb = 29; /* SP */ - int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2; - - gen_ld(ctx, OPC_LW, rd, rb, offset); - } - break; - case LW16: - { - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rb = mmreg(uMIPS_RS(ctx->opcode)); - int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2; - - gen_ld(ctx, OPC_LW, rd, rb, offset); - } - break; - case SB16: - { - int rd = mmreg2(uMIPS_RD(ctx->opcode)); - int rb = mmreg(uMIPS_RS(ctx->opcode)); - int16_t offset = ZIMM(ctx->opcode, 0, 4); - - gen_st(ctx, OPC_SB, rd, rb, offset); - } - break; - case SH16: - { - int rd = mmreg2(uMIPS_RD(ctx->opcode)); - int rb = mmreg(uMIPS_RS(ctx->opcode)); - int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1; - - gen_st(ctx, OPC_SH, rd, rb, offset); - } - break; - case SWSP16: - { - int rd = (ctx->opcode >> 5) & 0x1f; - int rb = 29; /* SP */ - int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2; - - gen_st(ctx, OPC_SW, rd, rb, offset); - } - break; - case SW16: - { - int rd = mmreg2(uMIPS_RD(ctx->opcode)); - int rb = mmreg(uMIPS_RS(ctx->opcode)); - int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2; - - gen_st(ctx, OPC_SW, rd, rb, offset); - } - break; - case MOVE16: - { - int rd = uMIPS_RD5(ctx->opcode); - int rs = uMIPS_RS5(ctx->opcode); - - gen_arith(ctx, OPC_ADDU, rd, rs, 0); - } - break; - case ANDI16: - gen_andi16(ctx); - break; - case POOL16D: - switch (ctx->opcode & 0x1) { - case ADDIUS5: - gen_addius5(ctx); - break; - case ADDIUSP: - gen_addiusp(ctx); - break; - } - break; - case POOL16E: - switch (ctx->opcode & 0x1) { - case ADDIUR2: - gen_addiur2(ctx); - break; - case ADDIUR1SP: - gen_addiur1sp(ctx); - break; - } - break; - case B16: /* BC16 */ - gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, - sextract32(ctx->opcode, 0, 10) << 1, - (ctx->insn_flags & ISA_MIPS_R6) ? 0 : 4); - break; - case BNEZ16: /* BNEZC16 */ - case BEQZ16: /* BEQZC16 */ - gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2, - mmreg(uMIPS_RD(ctx->opcode)), - 0, sextract32(ctx->opcode, 0, 7) << 1, - (ctx->insn_flags & ISA_MIPS_R6) ? 0 : 4); - - break; - case LI16: - { - int reg = mmreg(uMIPS_RD(ctx->opcode)); - int imm = ZIMM(ctx->opcode, 0, 7); - - imm = (imm == 0x7f ? -1 : imm); - tcg_gen_movi_tl(cpu_gpr[reg], imm); - } - break; - case RES_29: - case RES_31: - case RES_39: - gen_reserved_instruction(ctx); - break; - default: - decode_micromips32_opc(env, ctx); - return 4; - } - - return 2; -} - -/* - * - * nanoMIPS opcodes - * - */ - -/* MAJOR, P16, and P32 pools opcodes */ -enum { - NM_P_ADDIU = 0x00, - NM_ADDIUPC = 0x01, - NM_MOVE_BALC = 0x02, - NM_P16_MV = 0x04, - NM_LW16 = 0x05, - NM_BC16 = 0x06, - NM_P16_SR = 0x07, - - NM_POOL32A = 0x08, - NM_P_BAL = 0x0a, - NM_P16_SHIFT = 0x0c, - NM_LWSP16 = 0x0d, - NM_BALC16 = 0x0e, - NM_P16_4X4 = 0x0f, - - NM_P_GP_W = 0x10, - NM_P_GP_BH = 0x11, - NM_P_J = 0x12, - NM_P16C = 0x14, - NM_LWGP16 = 0x15, - NM_P16_LB = 0x17, - - NM_P48I = 0x18, - NM_P16_A1 = 0x1c, - NM_LW4X4 = 0x1d, - NM_P16_LH = 0x1f, - - NM_P_U12 = 0x20, - NM_P_LS_U12 = 0x21, - NM_P_BR1 = 0x22, - NM_P16_A2 = 0x24, - NM_SW16 = 0x25, - NM_BEQZC16 = 0x26, - - NM_POOL32F = 0x28, - NM_P_LS_S9 = 0x29, - NM_P_BR2 = 0x2a, - - NM_P16_ADDU = 0x2c, - NM_SWSP16 = 0x2d, - NM_BNEZC16 = 0x2e, - NM_MOVEP = 0x2f, - - NM_POOL32S = 0x30, - NM_P_BRI = 0x32, - NM_LI16 = 0x34, - NM_SWGP16 = 0x35, - NM_P16_BR = 0x36, - - NM_P_LUI = 0x38, - NM_ANDI16 = 0x3c, - NM_SW4X4 = 0x3d, - NM_MOVEPREV = 0x3f, -}; - -/* POOL32A instruction pool */ -enum { - NM_POOL32A0 = 0x00, - NM_SPECIAL2 = 0x01, - NM_COP2_1 = 0x02, - NM_UDI = 0x03, - NM_POOL32A5 = 0x05, - NM_POOL32A7 = 0x07, -}; - -/* P.GP.W instruction pool */ -enum { - NM_ADDIUGP_W = 0x00, - NM_LWGP = 0x02, - NM_SWGP = 0x03, -}; - -/* P48I instruction pool */ -enum { - NM_LI48 = 0x00, - NM_ADDIU48 = 0x01, - NM_ADDIUGP48 = 0x02, - NM_ADDIUPC48 = 0x03, - NM_LWPC48 = 0x0b, - NM_SWPC48 = 0x0f, -}; - -/* P.U12 instruction pool */ -enum { - NM_ORI = 0x00, - NM_XORI = 0x01, - NM_ANDI = 0x02, - NM_P_SR = 0x03, - NM_SLTI = 0x04, - NM_SLTIU = 0x05, - NM_SEQI = 0x06, - NM_ADDIUNEG = 0x08, - NM_P_SHIFT = 0x0c, - NM_P_ROTX = 0x0d, - NM_P_INS = 0x0e, - NM_P_EXT = 0x0f, -}; - -/* POOL32F instruction pool */ -enum { - NM_POOL32F_0 = 0x00, - NM_POOL32F_3 = 0x03, - NM_POOL32F_5 = 0x05, -}; - -/* POOL32S instruction pool */ -enum { - NM_POOL32S_0 = 0x00, - NM_POOL32S_4 = 0x04, -}; - -/* P.LUI instruction pool */ -enum { - NM_LUI = 0x00, - NM_ALUIPC = 0x01, -}; - -/* P.GP.BH instruction pool */ -enum { - NM_LBGP = 0x00, - NM_SBGP = 0x01, - NM_LBUGP = 0x02, - NM_ADDIUGP_B = 0x03, - NM_P_GP_LH = 0x04, - NM_P_GP_SH = 0x05, - NM_P_GP_CP1 = 0x06, -}; - -/* P.LS.U12 instruction pool */ -enum { - NM_LB = 0x00, - NM_SB = 0x01, - NM_LBU = 0x02, - NM_P_PREFU12 = 0x03, - NM_LH = 0x04, - NM_SH = 0x05, - NM_LHU = 0x06, - NM_LWU = 0x07, - NM_LW = 0x08, - NM_SW = 0x09, - NM_LWC1 = 0x0a, - NM_SWC1 = 0x0b, - NM_LDC1 = 0x0e, - NM_SDC1 = 0x0f, -}; - -/* P.LS.S9 instruction pool */ -enum { - NM_P_LS_S0 = 0x00, - NM_P_LS_S1 = 0x01, - NM_P_LS_E0 = 0x02, - NM_P_LS_WM = 0x04, - NM_P_LS_UAWM = 0x05, -}; - -/* P.BAL instruction pool */ -enum { - NM_BC = 0x00, - NM_BALC = 0x01, -}; - -/* P.J instruction pool */ -enum { - NM_JALRC = 0x00, - NM_JALRC_HB = 0x01, - NM_P_BALRSC = 0x08, -}; - -/* P.BR1 instruction pool */ -enum { - NM_BEQC = 0x00, - NM_P_BR3A = 0x01, - NM_BGEC = 0x02, - NM_BGEUC = 0x03, -}; - -/* P.BR2 instruction pool */ -enum { - NM_BNEC = 0x00, - NM_BLTC = 0x02, - NM_BLTUC = 0x03, -}; - -/* P.BRI instruction pool */ -enum { - NM_BEQIC = 0x00, - NM_BBEQZC = 0x01, - NM_BGEIC = 0x02, - NM_BGEIUC = 0x03, - NM_BNEIC = 0x04, - NM_BBNEZC = 0x05, - NM_BLTIC = 0x06, - NM_BLTIUC = 0x07, -}; - -/* P16.SHIFT instruction pool */ -enum { - NM_SLL16 = 0x00, - NM_SRL16 = 0x01, -}; - -/* POOL16C instruction pool */ -enum { - NM_POOL16C_0 = 0x00, - NM_LWXS16 = 0x01, -}; - -/* P16.A1 instruction pool */ -enum { - NM_ADDIUR1SP = 0x01, -}; - -/* P16.A2 instruction pool */ -enum { - NM_ADDIUR2 = 0x00, - NM_P_ADDIURS5 = 0x01, -}; - -/* P16.ADDU instruction pool */ -enum { - NM_ADDU16 = 0x00, - NM_SUBU16 = 0x01, -}; - -/* P16.SR instruction pool */ -enum { - NM_SAVE16 = 0x00, - NM_RESTORE_JRC16 = 0x01, -}; - -/* P16.4X4 instruction pool */ -enum { - NM_ADDU4X4 = 0x00, - NM_MUL4X4 = 0x01, -}; - -/* P16.LB instruction pool */ -enum { - NM_LB16 = 0x00, - NM_SB16 = 0x01, - NM_LBU16 = 0x02, -}; - -/* P16.LH instruction pool */ -enum { - NM_LH16 = 0x00, - NM_SH16 = 0x01, - NM_LHU16 = 0x02, -}; - -/* P.RI instruction pool */ -enum { - NM_SIGRIE = 0x00, - NM_P_SYSCALL = 0x01, - NM_BREAK = 0x02, - NM_SDBBP = 0x03, -}; - -/* POOL32A0 instruction pool */ -enum { - NM_P_TRAP = 0x00, - NM_SEB = 0x01, - NM_SLLV = 0x02, - NM_MUL = 0x03, - NM_MFC0 = 0x06, - NM_MFHC0 = 0x07, - NM_SEH = 0x09, - NM_SRLV = 0x0a, - NM_MUH = 0x0b, - NM_MTC0 = 0x0e, - NM_MTHC0 = 0x0f, - NM_SRAV = 0x12, - NM_MULU = 0x13, - NM_ROTRV = 0x1a, - NM_MUHU = 0x1b, - NM_ADD = 0x22, - NM_DIV = 0x23, - NM_ADDU = 0x2a, - NM_MOD = 0x2b, - NM_SUB = 0x32, - NM_DIVU = 0x33, - NM_RDHWR = 0x38, - NM_SUBU = 0x3a, - NM_MODU = 0x3b, - NM_P_CMOVE = 0x42, - NM_FORK = 0x45, - NM_MFTR = 0x46, - NM_MFHTR = 0x47, - NM_AND = 0x4a, - NM_YIELD = 0x4d, - NM_MTTR = 0x4e, - NM_MTHTR = 0x4f, - NM_OR = 0x52, - NM_D_E_MT_VPE = 0x56, - NM_NOR = 0x5a, - NM_XOR = 0x62, - NM_SLT = 0x6a, - NM_P_SLTU = 0x72, - NM_SOV = 0x7a, -}; - -/* CRC32 instruction pool */ -enum { - NM_CRC32B = 0x00, - NM_CRC32H = 0x01, - NM_CRC32W = 0x02, - NM_CRC32CB = 0x04, - NM_CRC32CH = 0x05, - NM_CRC32CW = 0x06, -}; - -/* POOL32A5 instruction pool */ -enum { - NM_CMP_EQ_PH = 0x00, - NM_CMP_LT_PH = 0x08, - NM_CMP_LE_PH = 0x10, - NM_CMPGU_EQ_QB = 0x18, - NM_CMPGU_LT_QB = 0x20, - NM_CMPGU_LE_QB = 0x28, - NM_CMPGDU_EQ_QB = 0x30, - NM_CMPGDU_LT_QB = 0x38, - NM_CMPGDU_LE_QB = 0x40, - NM_CMPU_EQ_QB = 0x48, - NM_CMPU_LT_QB = 0x50, - NM_CMPU_LE_QB = 0x58, - NM_ADDQ_S_W = 0x60, - NM_SUBQ_S_W = 0x68, - NM_ADDSC = 0x70, - NM_ADDWC = 0x78, - - NM_ADDQ_S_PH = 0x01, - NM_ADDQH_R_PH = 0x09, - NM_ADDQH_R_W = 0x11, - NM_ADDU_S_QB = 0x19, - NM_ADDU_S_PH = 0x21, - NM_ADDUH_R_QB = 0x29, - NM_SHRAV_R_PH = 0x31, - NM_SHRAV_R_QB = 0x39, - NM_SUBQ_S_PH = 0x41, - NM_SUBQH_R_PH = 0x49, - NM_SUBQH_R_W = 0x51, - NM_SUBU_S_QB = 0x59, - NM_SUBU_S_PH = 0x61, - NM_SUBUH_R_QB = 0x69, - NM_SHLLV_S_PH = 0x71, - NM_PRECR_SRA_R_PH_W = 0x79, - - NM_MULEU_S_PH_QBL = 0x12, - NM_MULEU_S_PH_QBR = 0x1a, - NM_MULQ_RS_PH = 0x22, - NM_MULQ_S_PH = 0x2a, - NM_MULQ_RS_W = 0x32, - NM_MULQ_S_W = 0x3a, - NM_APPEND = 0x42, - NM_MODSUB = 0x52, - NM_SHRAV_R_W = 0x5a, - NM_SHRLV_PH = 0x62, - NM_SHRLV_QB = 0x6a, - NM_SHLLV_QB = 0x72, - NM_SHLLV_S_W = 0x7a, - - NM_SHILO = 0x03, - - NM_MULEQ_S_W_PHL = 0x04, - NM_MULEQ_S_W_PHR = 0x0c, - - NM_MUL_S_PH = 0x05, - NM_PRECR_QB_PH = 0x0d, - NM_PRECRQ_QB_PH = 0x15, - NM_PRECRQ_PH_W = 0x1d, - NM_PRECRQ_RS_PH_W = 0x25, - NM_PRECRQU_S_QB_PH = 0x2d, - NM_PACKRL_PH = 0x35, - NM_PICK_QB = 0x3d, - NM_PICK_PH = 0x45, - - NM_SHRA_R_W = 0x5e, - NM_SHRA_R_PH = 0x66, - NM_SHLL_S_PH = 0x76, - NM_SHLL_S_W = 0x7e, - - NM_REPL_PH = 0x07 -}; - -/* POOL32A7 instruction pool */ -enum { - NM_P_LSX = 0x00, - NM_LSA = 0x01, - NM_EXTW = 0x03, - NM_POOL32AXF = 0x07, -}; - -/* P.SR instruction pool */ -enum { - NM_PP_SR = 0x00, - NM_P_SR_F = 0x01, -}; - -/* P.SHIFT instruction pool */ -enum { - NM_P_SLL = 0x00, - NM_SRL = 0x02, - NM_SRA = 0x04, - NM_ROTR = 0x06, -}; - -/* P.ROTX instruction pool */ -enum { - NM_ROTX = 0x00, -}; - -/* P.INS instruction pool */ -enum { - NM_INS = 0x00, -}; - -/* P.EXT instruction pool */ -enum { - NM_EXT = 0x00, -}; - -/* POOL32F_0 (fmt) instruction pool */ -enum { - NM_RINT_S = 0x04, - NM_RINT_D = 0x44, - NM_ADD_S = 0x06, - NM_SELEQZ_S = 0x07, - NM_SELEQZ_D = 0x47, - NM_CLASS_S = 0x0c, - NM_CLASS_D = 0x4c, - NM_SUB_S = 0x0e, - NM_SELNEZ_S = 0x0f, - NM_SELNEZ_D = 0x4f, - NM_MUL_S = 0x16, - NM_SEL_S = 0x17, - NM_SEL_D = 0x57, - NM_DIV_S = 0x1e, - NM_ADD_D = 0x26, - NM_SUB_D = 0x2e, - NM_MUL_D = 0x36, - NM_MADDF_S = 0x37, - NM_MADDF_D = 0x77, - NM_DIV_D = 0x3e, - NM_MSUBF_S = 0x3f, - NM_MSUBF_D = 0x7f, -}; - -/* POOL32F_3 instruction pool */ -enum { - NM_MIN_FMT = 0x00, - NM_MAX_FMT = 0x01, - NM_MINA_FMT = 0x04, - NM_MAXA_FMT = 0x05, - NM_POOL32FXF = 0x07, -}; - -/* POOL32F_5 instruction pool */ -enum { - NM_CMP_CONDN_S = 0x00, - NM_CMP_CONDN_D = 0x02, -}; - -/* P.GP.LH instruction pool */ -enum { - NM_LHGP = 0x00, - NM_LHUGP = 0x01, -}; - -/* P.GP.SH instruction pool */ -enum { - NM_SHGP = 0x00, -}; - -/* P.GP.CP1 instruction pool */ -enum { - NM_LWC1GP = 0x00, - NM_SWC1GP = 0x01, - NM_LDC1GP = 0x02, - NM_SDC1GP = 0x03, -}; - -/* P.LS.S0 instruction pool */ -enum { - NM_LBS9 = 0x00, - NM_LHS9 = 0x04, - NM_LWS9 = 0x08, - NM_LDS9 = 0x0c, - - NM_SBS9 = 0x01, - NM_SHS9 = 0x05, - NM_SWS9 = 0x09, - NM_SDS9 = 0x0d, - - NM_LBUS9 = 0x02, - NM_LHUS9 = 0x06, - NM_LWC1S9 = 0x0a, - NM_LDC1S9 = 0x0e, - - NM_P_PREFS9 = 0x03, - NM_LWUS9 = 0x07, - NM_SWC1S9 = 0x0b, - NM_SDC1S9 = 0x0f, -}; - -/* P.LS.S1 instruction pool */ -enum { - NM_ASET_ACLR = 0x02, - NM_UALH = 0x04, - NM_UASH = 0x05, - NM_CACHE = 0x07, - NM_P_LL = 0x0a, - NM_P_SC = 0x0b, -}; - -/* P.LS.E0 instruction pool */ -enum { - NM_LBE = 0x00, - NM_SBE = 0x01, - NM_LBUE = 0x02, - NM_P_PREFE = 0x03, - NM_LHE = 0x04, - NM_SHE = 0x05, - NM_LHUE = 0x06, - NM_CACHEE = 0x07, - NM_LWE = 0x08, - NM_SWE = 0x09, - NM_P_LLE = 0x0a, - NM_P_SCE = 0x0b, -}; - -/* P.PREFE instruction pool */ -enum { - NM_SYNCIE = 0x00, - NM_PREFE = 0x01, -}; - -/* P.LLE instruction pool */ -enum { - NM_LLE = 0x00, - NM_LLWPE = 0x01, -}; - -/* P.SCE instruction pool */ -enum { - NM_SCE = 0x00, - NM_SCWPE = 0x01, -}; - -/* P.LS.WM instruction pool */ -enum { - NM_LWM = 0x00, - NM_SWM = 0x01, -}; - -/* P.LS.UAWM instruction pool */ -enum { - NM_UALWM = 0x00, - NM_UASWM = 0x01, -}; - -/* P.BR3A instruction pool */ -enum { - NM_BC1EQZC = 0x00, - NM_BC1NEZC = 0x01, - NM_BC2EQZC = 0x02, - NM_BC2NEZC = 0x03, - NM_BPOSGE32C = 0x04, -}; - -/* P16.RI instruction pool */ -enum { - NM_P16_SYSCALL = 0x01, - NM_BREAK16 = 0x02, - NM_SDBBP16 = 0x03, -}; - -/* POOL16C_0 instruction pool */ -enum { - NM_POOL16C_00 = 0x00, -}; - -/* P16.JRC instruction pool */ -enum { - NM_JRC = 0x00, - NM_JALRC16 = 0x01, -}; - -/* P.SYSCALL instruction pool */ -enum { - NM_SYSCALL = 0x00, - NM_HYPCALL = 0x01, -}; - -/* P.TRAP instruction pool */ -enum { - NM_TEQ = 0x00, - NM_TNE = 0x01, -}; - -/* P.CMOVE instruction pool */ -enum { - NM_MOVZ = 0x00, - NM_MOVN = 0x01, -}; - -/* POOL32Axf instruction pool */ -enum { - NM_POOL32AXF_1 = 0x01, - NM_POOL32AXF_2 = 0x02, - NM_POOL32AXF_4 = 0x04, - NM_POOL32AXF_5 = 0x05, - NM_POOL32AXF_7 = 0x07, -}; - -/* POOL32Axf_1 instruction pool */ -enum { - NM_POOL32AXF_1_0 = 0x00, - NM_POOL32AXF_1_1 = 0x01, - NM_POOL32AXF_1_3 = 0x03, - NM_POOL32AXF_1_4 = 0x04, - NM_POOL32AXF_1_5 = 0x05, - NM_POOL32AXF_1_7 = 0x07, -}; - -/* POOL32Axf_2 instruction pool */ -enum { - NM_POOL32AXF_2_0_7 = 0x00, - NM_POOL32AXF_2_8_15 = 0x01, - NM_POOL32AXF_2_16_23 = 0x02, - NM_POOL32AXF_2_24_31 = 0x03, -}; - -/* POOL32Axf_7 instruction pool */ -enum { - NM_SHRA_R_QB = 0x0, - NM_SHRL_PH = 0x1, - NM_REPL_QB = 0x2, -}; - -/* POOL32Axf_1_0 instruction pool */ -enum { - NM_MFHI = 0x0, - NM_MFLO = 0x1, - NM_MTHI = 0x2, - NM_MTLO = 0x3, -}; - -/* POOL32Axf_1_1 instruction pool */ -enum { - NM_MTHLIP = 0x0, - NM_SHILOV = 0x1, -}; - -/* POOL32Axf_1_3 instruction pool */ -enum { - NM_RDDSP = 0x0, - NM_WRDSP = 0x1, - NM_EXTP = 0x2, - NM_EXTPDP = 0x3, -}; - -/* POOL32Axf_1_4 instruction pool */ -enum { - NM_SHLL_QB = 0x0, - NM_SHRL_QB = 0x1, -}; - -/* POOL32Axf_1_5 instruction pool */ -enum { - NM_MAQ_S_W_PHR = 0x0, - NM_MAQ_S_W_PHL = 0x1, - NM_MAQ_SA_W_PHR = 0x2, - NM_MAQ_SA_W_PHL = 0x3, -}; - -/* POOL32Axf_1_7 instruction pool */ -enum { - NM_EXTR_W = 0x0, - NM_EXTR_R_W = 0x1, - NM_EXTR_RS_W = 0x2, - NM_EXTR_S_H = 0x3, -}; - -/* POOL32Axf_2_0_7 instruction pool */ -enum { - NM_DPA_W_PH = 0x0, - NM_DPAQ_S_W_PH = 0x1, - NM_DPS_W_PH = 0x2, - NM_DPSQ_S_W_PH = 0x3, - NM_BALIGN = 0x4, - NM_MADD = 0x5, - NM_MULT = 0x6, - NM_EXTRV_W = 0x7, -}; - -/* POOL32Axf_2_8_15 instruction pool */ -enum { - NM_DPAX_W_PH = 0x0, - NM_DPAQ_SA_L_W = 0x1, - NM_DPSX_W_PH = 0x2, - NM_DPSQ_SA_L_W = 0x3, - NM_MADDU = 0x5, - NM_MULTU = 0x6, - NM_EXTRV_R_W = 0x7, -}; - -/* POOL32Axf_2_16_23 instruction pool */ -enum { - NM_DPAU_H_QBL = 0x0, - NM_DPAQX_S_W_PH = 0x1, - NM_DPSU_H_QBL = 0x2, - NM_DPSQX_S_W_PH = 0x3, - NM_EXTPV = 0x4, - NM_MSUB = 0x5, - NM_MULSA_W_PH = 0x6, - NM_EXTRV_RS_W = 0x7, -}; - -/* POOL32Axf_2_24_31 instruction pool */ -enum { - NM_DPAU_H_QBR = 0x0, - NM_DPAQX_SA_W_PH = 0x1, - NM_DPSU_H_QBR = 0x2, - NM_DPSQX_SA_W_PH = 0x3, - NM_EXTPDPV = 0x4, - NM_MSUBU = 0x5, - NM_MULSAQ_S_W_PH = 0x6, - NM_EXTRV_S_H = 0x7, -}; - -/* POOL32Axf_{4, 5} instruction pool */ -enum { - NM_CLO = 0x25, - NM_CLZ = 0x2d, - - NM_TLBP = 0x01, - NM_TLBR = 0x09, - NM_TLBWI = 0x11, - NM_TLBWR = 0x19, - NM_TLBINV = 0x03, - NM_TLBINVF = 0x0b, - NM_DI = 0x23, - NM_EI = 0x2b, - NM_RDPGPR = 0x70, - NM_WRPGPR = 0x78, - NM_WAIT = 0x61, - NM_DERET = 0x71, - NM_ERETX = 0x79, - - /* nanoMIPS DSP instructions */ - NM_ABSQ_S_QB = 0x00, - NM_ABSQ_S_PH = 0x08, - NM_ABSQ_S_W = 0x10, - NM_PRECEQ_W_PHL = 0x28, - NM_PRECEQ_W_PHR = 0x30, - NM_PRECEQU_PH_QBL = 0x38, - NM_PRECEQU_PH_QBR = 0x48, - NM_PRECEU_PH_QBL = 0x58, - NM_PRECEU_PH_QBR = 0x68, - NM_PRECEQU_PH_QBLA = 0x39, - NM_PRECEQU_PH_QBRA = 0x49, - NM_PRECEU_PH_QBLA = 0x59, - NM_PRECEU_PH_QBRA = 0x69, - NM_REPLV_PH = 0x01, - NM_REPLV_QB = 0x09, - NM_BITREV = 0x18, - NM_INSV = 0x20, - NM_RADDU_W_QB = 0x78, - - NM_BITSWAP = 0x05, - NM_WSBH = 0x3d, -}; - -/* PP.SR instruction pool */ -enum { - NM_SAVE = 0x00, - NM_RESTORE = 0x02, - NM_RESTORE_JRC = 0x03, -}; - -/* P.SR.F instruction pool */ -enum { - NM_SAVEF = 0x00, - NM_RESTOREF = 0x01, -}; - -/* P16.SYSCALL instruction pool */ -enum { - NM_SYSCALL16 = 0x00, - NM_HYPCALL16 = 0x01, -}; - -/* POOL16C_00 instruction pool */ -enum { - NM_NOT16 = 0x00, - NM_XOR16 = 0x01, - NM_AND16 = 0x02, - NM_OR16 = 0x03, -}; - -/* PP.LSX and PP.LSXS instruction pool */ -enum { - NM_LBX = 0x00, - NM_LHX = 0x04, - NM_LWX = 0x08, - NM_LDX = 0x0c, - - NM_SBX = 0x01, - NM_SHX = 0x05, - NM_SWX = 0x09, - NM_SDX = 0x0d, - - NM_LBUX = 0x02, - NM_LHUX = 0x06, - NM_LWC1X = 0x0a, - NM_LDC1X = 0x0e, - - NM_LWUX = 0x07, - NM_SWC1X = 0x0b, - NM_SDC1X = 0x0f, - - NM_LHXS = 0x04, - NM_LWXS = 0x08, - NM_LDXS = 0x0c, - - NM_SHXS = 0x05, - NM_SWXS = 0x09, - NM_SDXS = 0x0d, - - NM_LHUXS = 0x06, - NM_LWC1XS = 0x0a, - NM_LDC1XS = 0x0e, - - NM_LWUXS = 0x07, - NM_SWC1XS = 0x0b, - NM_SDC1XS = 0x0f, -}; - -/* ERETx instruction pool */ -enum { - NM_ERET = 0x00, - NM_ERETNC = 0x01, -}; - -/* POOL32FxF_{0, 1} insturction pool */ -enum { - NM_CFC1 = 0x40, - NM_CTC1 = 0x60, - NM_MFC1 = 0x80, - NM_MTC1 = 0xa0, - NM_MFHC1 = 0xc0, - NM_MTHC1 = 0xe0, - - NM_CVT_S_PL = 0x84, - NM_CVT_S_PU = 0xa4, - - NM_CVT_L_S = 0x004, - NM_CVT_L_D = 0x104, - NM_CVT_W_S = 0x024, - NM_CVT_W_D = 0x124, - - NM_RSQRT_S = 0x008, - NM_RSQRT_D = 0x108, - - NM_SQRT_S = 0x028, - NM_SQRT_D = 0x128, - - NM_RECIP_S = 0x048, - NM_RECIP_D = 0x148, - - NM_FLOOR_L_S = 0x00c, - NM_FLOOR_L_D = 0x10c, - - NM_FLOOR_W_S = 0x02c, - NM_FLOOR_W_D = 0x12c, - - NM_CEIL_L_S = 0x04c, - NM_CEIL_L_D = 0x14c, - NM_CEIL_W_S = 0x06c, - NM_CEIL_W_D = 0x16c, - NM_TRUNC_L_S = 0x08c, - NM_TRUNC_L_D = 0x18c, - NM_TRUNC_W_S = 0x0ac, - NM_TRUNC_W_D = 0x1ac, - NM_ROUND_L_S = 0x0cc, - NM_ROUND_L_D = 0x1cc, - NM_ROUND_W_S = 0x0ec, - NM_ROUND_W_D = 0x1ec, - - NM_MOV_S = 0x01, - NM_MOV_D = 0x81, - NM_ABS_S = 0x0d, - NM_ABS_D = 0x8d, - NM_NEG_S = 0x2d, - NM_NEG_D = 0xad, - NM_CVT_D_S = 0x04d, - NM_CVT_D_W = 0x0cd, - NM_CVT_D_L = 0x14d, - NM_CVT_S_D = 0x06d, - NM_CVT_S_W = 0x0ed, - NM_CVT_S_L = 0x16d, -}; - -/* P.LL instruction pool */ -enum { - NM_LL = 0x00, - NM_LLWP = 0x01, -}; - -/* P.SC instruction pool */ -enum { - NM_SC = 0x00, - NM_SCWP = 0x01, -}; - -/* P.DVP instruction pool */ -enum { - NM_DVP = 0x00, - NM_EVP = 0x01, -}; - - -/* - * - * nanoMIPS decoding engine - * - */ - - -/* extraction utilities */ - -#define NANOMIPS_EXTRACT_RT3(op) ((op >> 7) & 0x7) -#define NANOMIPS_EXTRACT_RS3(op) ((op >> 4) & 0x7) -#define NANOMIPS_EXTRACT_RD3(op) ((op >> 1) & 0x7) -#define NANOMIPS_EXTRACT_RD5(op) ((op >> 5) & 0x1f) -#define NANOMIPS_EXTRACT_RS5(op) (op & 0x1f) - -/* Implement nanoMIPS pseudocode decode_gpr(encoded_gpr, 'gpr3'). */ -static inline int decode_gpr_gpr3(int r) -{ - static const int map[] = { 16, 17, 18, 19, 4, 5, 6, 7 }; - - return map[r & 0x7]; -} - -/* Implement nanoMIPS pseudocode decode_gpr(encoded_gpr, 'gpr3.src.store'). */ -static inline int decode_gpr_gpr3_src_store(int r) -{ - static const int map[] = { 0, 17, 18, 19, 4, 5, 6, 7 }; - - return map[r & 0x7]; -} - -/* Implement nanoMIPS pseudocode decode_gpr(encoded_gpr, 'gpr4'). */ -static inline int decode_gpr_gpr4(int r) -{ - static const int map[] = { 8, 9, 10, 11, 4, 5, 6, 7, - 16, 17, 18, 19, 20, 21, 22, 23 }; - - return map[r & 0xf]; -} - -/* Implement nanoMIPS pseudocode decode_gpr(encoded_gpr, 'gpr4.zero'). */ -static inline int decode_gpr_gpr4_zero(int r) -{ - static const int map[] = { 8, 9, 10, 0, 4, 5, 6, 7, - 16, 17, 18, 19, 20, 21, 22, 23 }; - - return map[r & 0xf]; -} - - -static void gen_adjust_sp(DisasContext *ctx, int u) -{ - gen_op_addr_addi(ctx, cpu_gpr[29], cpu_gpr[29], u); -} - -static void gen_save(DisasContext *ctx, uint8_t rt, uint8_t count, - uint8_t gp, uint16_t u) -{ - int counter = 0; - TCGv va = tcg_temp_new(); - TCGv t0 = tcg_temp_new(); - - while (counter != count) { - bool use_gp = gp && (counter == count - 1); - int this_rt = use_gp ? 28 : (rt & 0x10) | ((rt + counter) & 0x1f); - int this_offset = -((counter + 1) << 2); - gen_base_offset_addr(ctx, va, 29, this_offset); - gen_load_gpr(t0, this_rt); - tcg_gen_qemu_st_tl(t0, va, ctx->mem_idx, - (MO_TEUL | ctx->default_tcg_memop_mask)); - counter++; - } - - /* adjust stack pointer */ - gen_adjust_sp(ctx, -u); - - tcg_temp_free(t0); - tcg_temp_free(va); -} - -static void gen_restore(DisasContext *ctx, uint8_t rt, uint8_t count, - uint8_t gp, uint16_t u) -{ - int counter = 0; - TCGv va = tcg_temp_new(); - TCGv t0 = tcg_temp_new(); - - while (counter != count) { - bool use_gp = gp && (counter == count - 1); - int this_rt = use_gp ? 28 : (rt & 0x10) | ((rt + counter) & 0x1f); - int this_offset = u - ((counter + 1) << 2); - gen_base_offset_addr(ctx, va, 29, this_offset); - tcg_gen_qemu_ld_tl(t0, va, ctx->mem_idx, MO_TESL | - ctx->default_tcg_memop_mask); - tcg_gen_ext32s_tl(t0, t0); - gen_store_gpr(t0, this_rt); - counter++; - } - - /* adjust stack pointer */ - gen_adjust_sp(ctx, u); - - tcg_temp_free(t0); - tcg_temp_free(va); -} - -static void gen_pool16c_nanomips_insn(DisasContext *ctx) -{ - int rt = decode_gpr_gpr3(NANOMIPS_EXTRACT_RT3(ctx->opcode)); - int rs = decode_gpr_gpr3(NANOMIPS_EXTRACT_RS3(ctx->opcode)); - - switch (extract32(ctx->opcode, 2, 2)) { - case NM_NOT16: - gen_logic(ctx, OPC_NOR, rt, rs, 0); - break; - case NM_AND16: - gen_logic(ctx, OPC_AND, rt, rt, rs); - break; - case NM_XOR16: - gen_logic(ctx, OPC_XOR, rt, rt, rs); - break; - case NM_OR16: - gen_logic(ctx, OPC_OR, rt, rt, rs); - break; - } -} - -static void gen_pool32a0_nanomips_insn(CPUMIPSState *env, DisasContext *ctx) -{ - int rt = extract32(ctx->opcode, 21, 5); - int rs = extract32(ctx->opcode, 16, 5); - int rd = extract32(ctx->opcode, 11, 5); - - switch (extract32(ctx->opcode, 3, 7)) { - case NM_P_TRAP: - switch (extract32(ctx->opcode, 10, 1)) { - case NM_TEQ: - check_nms(ctx); - gen_trap(ctx, OPC_TEQ, rs, rt, -1); - break; - case NM_TNE: - check_nms(ctx); - gen_trap(ctx, OPC_TNE, rs, rt, -1); - break; - } - break; - case NM_RDHWR: - check_nms(ctx); - gen_rdhwr(ctx, rt, rs, extract32(ctx->opcode, 11, 3)); - break; - case NM_SEB: - check_nms(ctx); - gen_bshfl(ctx, OPC_SEB, rs, rt); - break; - case NM_SEH: - gen_bshfl(ctx, OPC_SEH, rs, rt); - break; - case NM_SLLV: - gen_shift(ctx, OPC_SLLV, rd, rt, rs); - break; - case NM_SRLV: - gen_shift(ctx, OPC_SRLV, rd, rt, rs); - break; - case NM_SRAV: - gen_shift(ctx, OPC_SRAV, rd, rt, rs); - break; - case NM_ROTRV: - gen_shift(ctx, OPC_ROTRV, rd, rt, rs); - break; - case NM_ADD: - gen_arith(ctx, OPC_ADD, rd, rs, rt); - break; - case NM_ADDU: - gen_arith(ctx, OPC_ADDU, rd, rs, rt); - break; - case NM_SUB: - check_nms(ctx); - gen_arith(ctx, OPC_SUB, rd, rs, rt); - break; - case NM_SUBU: - gen_arith(ctx, OPC_SUBU, rd, rs, rt); - break; - case NM_P_CMOVE: - switch (extract32(ctx->opcode, 10, 1)) { - case NM_MOVZ: - gen_cond_move(ctx, OPC_MOVZ, rd, rs, rt); - break; - case NM_MOVN: - gen_cond_move(ctx, OPC_MOVN, rd, rs, rt); - break; - } - break; - case NM_AND: - gen_logic(ctx, OPC_AND, rd, rs, rt); - break; - case NM_OR: - gen_logic(ctx, OPC_OR, rd, rs, rt); - break; - case NM_NOR: - gen_logic(ctx, OPC_NOR, rd, rs, rt); - break; - case NM_XOR: - gen_logic(ctx, OPC_XOR, rd, rs, rt); - break; - case NM_SLT: - gen_slt(ctx, OPC_SLT, rd, rs, rt); - break; - case NM_P_SLTU: - if (rd == 0) { - /* P_DVP */ -#ifndef CONFIG_USER_ONLY - TCGv t0 = tcg_temp_new(); - switch (extract32(ctx->opcode, 10, 1)) { - case NM_DVP: - if (ctx->vp) { - check_cp0_enabled(ctx); - gen_helper_dvp(t0, cpu_env); - gen_store_gpr(t0, rt); - } - break; - case NM_EVP: - if (ctx->vp) { - check_cp0_enabled(ctx); - gen_helper_evp(t0, cpu_env); - gen_store_gpr(t0, rt); - } - break; - } - tcg_temp_free(t0); -#endif - } else { - gen_slt(ctx, OPC_SLTU, rd, rs, rt); - } - break; - case NM_SOV: - { - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - TCGv t2 = tcg_temp_new(); - - gen_load_gpr(t1, rs); - gen_load_gpr(t2, rt); - tcg_gen_add_tl(t0, t1, t2); - tcg_gen_ext32s_tl(t0, t0); - tcg_gen_xor_tl(t1, t1, t2); - tcg_gen_xor_tl(t2, t0, t2); - tcg_gen_andc_tl(t1, t2, t1); - - /* operands of same sign, result different sign */ - tcg_gen_setcondi_tl(TCG_COND_LT, t0, t1, 0); - gen_store_gpr(t0, rd); - - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free(t2); - } - break; - case NM_MUL: - gen_r6_muldiv(ctx, R6_OPC_MUL, rd, rs, rt); - break; - case NM_MUH: - gen_r6_muldiv(ctx, R6_OPC_MUH, rd, rs, rt); - break; - case NM_MULU: - gen_r6_muldiv(ctx, R6_OPC_MULU, rd, rs, rt); - break; - case NM_MUHU: - gen_r6_muldiv(ctx, R6_OPC_MUHU, rd, rs, rt); - break; - case NM_DIV: - gen_r6_muldiv(ctx, R6_OPC_DIV, rd, rs, rt); - break; - case NM_MOD: - gen_r6_muldiv(ctx, R6_OPC_MOD, rd, rs, rt); - break; - case NM_DIVU: - gen_r6_muldiv(ctx, R6_OPC_DIVU, rd, rs, rt); - break; - case NM_MODU: - gen_r6_muldiv(ctx, R6_OPC_MODU, rd, rs, rt); - break; -#ifndef CONFIG_USER_ONLY - case NM_MFC0: - check_cp0_enabled(ctx); - if (rt == 0) { - /* Treat as NOP. */ - break; - } - gen_mfc0(ctx, cpu_gpr[rt], rs, extract32(ctx->opcode, 11, 3)); - break; - case NM_MTC0: - check_cp0_enabled(ctx); - { - TCGv t0 = tcg_temp_new(); - - gen_load_gpr(t0, rt); - gen_mtc0(ctx, t0, rs, extract32(ctx->opcode, 11, 3)); - tcg_temp_free(t0); - } - break; - case NM_D_E_MT_VPE: - { - uint8_t sc = extract32(ctx->opcode, 10, 1); - TCGv t0 = tcg_temp_new(); - - switch (sc) { - case 0: - if (rs == 1) { - /* DMT */ - check_cp0_mt(ctx); - gen_helper_dmt(t0); - gen_store_gpr(t0, rt); - } else if (rs == 0) { - /* DVPE */ - check_cp0_mt(ctx); - gen_helper_dvpe(t0, cpu_env); - gen_store_gpr(t0, rt); - } else { - gen_reserved_instruction(ctx); - } - break; - case 1: - if (rs == 1) { - /* EMT */ - check_cp0_mt(ctx); - gen_helper_emt(t0); - gen_store_gpr(t0, rt); - } else if (rs == 0) { - /* EVPE */ - check_cp0_mt(ctx); - gen_helper_evpe(t0, cpu_env); - gen_store_gpr(t0, rt); - } else { - gen_reserved_instruction(ctx); - } - break; - } - - tcg_temp_free(t0); - } - break; - case NM_FORK: - check_mt(ctx); - { - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - - gen_load_gpr(t0, rt); - gen_load_gpr(t1, rs); - gen_helper_fork(t0, t1); - tcg_temp_free(t0); - tcg_temp_free(t1); - } - break; - case NM_MFTR: - case NM_MFHTR: - check_cp0_enabled(ctx); - if (rd == 0) { - /* Treat as NOP. */ - return; - } - gen_mftr(env, ctx, rs, rt, extract32(ctx->opcode, 10, 1), - extract32(ctx->opcode, 11, 5), extract32(ctx->opcode, 3, 1)); - break; - case NM_MTTR: - case NM_MTHTR: - check_cp0_enabled(ctx); - gen_mttr(env, ctx, rs, rt, extract32(ctx->opcode, 10, 1), - extract32(ctx->opcode, 11, 5), extract32(ctx->opcode, 3, 1)); - break; - case NM_YIELD: - check_mt(ctx); - { - TCGv t0 = tcg_temp_new(); - - gen_load_gpr(t0, rs); - gen_helper_yield(t0, cpu_env, t0); - gen_store_gpr(t0, rt); - tcg_temp_free(t0); - } - break; -#endif - default: - gen_reserved_instruction(ctx); - break; - } -} - -/* dsp */ -static void gen_pool32axf_1_5_nanomips_insn(DisasContext *ctx, uint32_t opc, - int ret, int v1, int v2) -{ - TCGv_i32 t0; - TCGv v0_t; - TCGv v1_t; - - t0 = tcg_temp_new_i32(); - - v0_t = tcg_temp_new(); - v1_t = tcg_temp_new(); - - tcg_gen_movi_i32(t0, v2 >> 3); - - gen_load_gpr(v0_t, ret); - gen_load_gpr(v1_t, v1); - - switch (opc) { - case NM_MAQ_S_W_PHR: - check_dsp(ctx); - gen_helper_maq_s_w_phr(t0, v1_t, v0_t, cpu_env); - break; - case NM_MAQ_S_W_PHL: - check_dsp(ctx); - gen_helper_maq_s_w_phl(t0, v1_t, v0_t, cpu_env); - break; - case NM_MAQ_SA_W_PHR: - check_dsp(ctx); - gen_helper_maq_sa_w_phr(t0, v1_t, v0_t, cpu_env); - break; - case NM_MAQ_SA_W_PHL: - check_dsp(ctx); - gen_helper_maq_sa_w_phl(t0, v1_t, v0_t, cpu_env); - break; - default: - gen_reserved_instruction(ctx); - break; - } - - tcg_temp_free_i32(t0); - - tcg_temp_free(v0_t); - tcg_temp_free(v1_t); -} - - -static void gen_pool32axf_1_nanomips_insn(DisasContext *ctx, uint32_t opc, - int ret, int v1, int v2) -{ - int16_t imm; - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - TCGv v0_t = tcg_temp_new(); - - gen_load_gpr(v0_t, v1); - - switch (opc) { - case NM_POOL32AXF_1_0: - check_dsp(ctx); - switch (extract32(ctx->opcode, 12, 2)) { - case NM_MFHI: - gen_HILO(ctx, OPC_MFHI, v2 >> 3, ret); - break; - case NM_MFLO: - gen_HILO(ctx, OPC_MFLO, v2 >> 3, ret); - break; - case NM_MTHI: - gen_HILO(ctx, OPC_MTHI, v2 >> 3, v1); - break; - case NM_MTLO: - gen_HILO(ctx, OPC_MTLO, v2 >> 3, v1); - break; - } - break; - case NM_POOL32AXF_1_1: - check_dsp(ctx); - switch (extract32(ctx->opcode, 12, 2)) { - case NM_MTHLIP: - tcg_gen_movi_tl(t0, v2); - gen_helper_mthlip(t0, v0_t, cpu_env); - break; - case NM_SHILOV: - tcg_gen_movi_tl(t0, v2 >> 3); - gen_helper_shilo(t0, v0_t, cpu_env); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_POOL32AXF_1_3: - check_dsp(ctx); - imm = extract32(ctx->opcode, 14, 7); - switch (extract32(ctx->opcode, 12, 2)) { - case NM_RDDSP: - tcg_gen_movi_tl(t0, imm); - gen_helper_rddsp(t0, t0, cpu_env); - gen_store_gpr(t0, ret); - break; - case NM_WRDSP: - gen_load_gpr(t0, ret); - tcg_gen_movi_tl(t1, imm); - gen_helper_wrdsp(t0, t1, cpu_env); - break; - case NM_EXTP: - tcg_gen_movi_tl(t0, v2 >> 3); - tcg_gen_movi_tl(t1, v1); - gen_helper_extp(t0, t0, t1, cpu_env); - gen_store_gpr(t0, ret); - break; - case NM_EXTPDP: - tcg_gen_movi_tl(t0, v2 >> 3); - tcg_gen_movi_tl(t1, v1); - gen_helper_extpdp(t0, t0, t1, cpu_env); - gen_store_gpr(t0, ret); - break; - } - break; - case NM_POOL32AXF_1_4: - check_dsp(ctx); - tcg_gen_movi_tl(t0, v2 >> 2); - switch (extract32(ctx->opcode, 12, 1)) { - case NM_SHLL_QB: - gen_helper_shll_qb(t0, t0, v0_t, cpu_env); - gen_store_gpr(t0, ret); - break; - case NM_SHRL_QB: - gen_helper_shrl_qb(t0, t0, v0_t); - gen_store_gpr(t0, ret); - break; - } - break; - case NM_POOL32AXF_1_5: - opc = extract32(ctx->opcode, 12, 2); - gen_pool32axf_1_5_nanomips_insn(ctx, opc, ret, v1, v2); - break; - case NM_POOL32AXF_1_7: - check_dsp(ctx); - tcg_gen_movi_tl(t0, v2 >> 3); - tcg_gen_movi_tl(t1, v1); - switch (extract32(ctx->opcode, 12, 2)) { - case NM_EXTR_W: - gen_helper_extr_w(t0, t0, t1, cpu_env); - gen_store_gpr(t0, ret); - break; - case NM_EXTR_R_W: - gen_helper_extr_r_w(t0, t0, t1, cpu_env); - gen_store_gpr(t0, ret); - break; - case NM_EXTR_RS_W: - gen_helper_extr_rs_w(t0, t0, t1, cpu_env); - gen_store_gpr(t0, ret); - break; - case NM_EXTR_S_H: - gen_helper_extr_s_h(t0, t0, t1, cpu_env); - gen_store_gpr(t0, ret); - break; - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free(v0_t); -} - -static void gen_pool32axf_2_multiply(DisasContext *ctx, uint32_t opc, - TCGv v0, TCGv v1, int rd) -{ - TCGv_i32 t0; - - t0 = tcg_temp_new_i32(); - - tcg_gen_movi_i32(t0, rd >> 3); - - switch (opc) { - case NM_POOL32AXF_2_0_7: - switch (extract32(ctx->opcode, 9, 3)) { - case NM_DPA_W_PH: - check_dsp_r2(ctx); - gen_helper_dpa_w_ph(t0, v1, v0, cpu_env); - break; - case NM_DPAQ_S_W_PH: - check_dsp(ctx); - gen_helper_dpaq_s_w_ph(t0, v1, v0, cpu_env); - break; - case NM_DPS_W_PH: - check_dsp_r2(ctx); - gen_helper_dps_w_ph(t0, v1, v0, cpu_env); - break; - case NM_DPSQ_S_W_PH: - check_dsp(ctx); - gen_helper_dpsq_s_w_ph(t0, v1, v0, cpu_env); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_POOL32AXF_2_8_15: - switch (extract32(ctx->opcode, 9, 3)) { - case NM_DPAX_W_PH: - check_dsp_r2(ctx); - gen_helper_dpax_w_ph(t0, v0, v1, cpu_env); - break; - case NM_DPAQ_SA_L_W: - check_dsp(ctx); - gen_helper_dpaq_sa_l_w(t0, v0, v1, cpu_env); - break; - case NM_DPSX_W_PH: - check_dsp_r2(ctx); - gen_helper_dpsx_w_ph(t0, v0, v1, cpu_env); - break; - case NM_DPSQ_SA_L_W: - check_dsp(ctx); - gen_helper_dpsq_sa_l_w(t0, v0, v1, cpu_env); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_POOL32AXF_2_16_23: - switch (extract32(ctx->opcode, 9, 3)) { - case NM_DPAU_H_QBL: - check_dsp(ctx); - gen_helper_dpau_h_qbl(t0, v0, v1, cpu_env); - break; - case NM_DPAQX_S_W_PH: - check_dsp_r2(ctx); - gen_helper_dpaqx_s_w_ph(t0, v0, v1, cpu_env); - break; - case NM_DPSU_H_QBL: - check_dsp(ctx); - gen_helper_dpsu_h_qbl(t0, v0, v1, cpu_env); - break; - case NM_DPSQX_S_W_PH: - check_dsp_r2(ctx); - gen_helper_dpsqx_s_w_ph(t0, v0, v1, cpu_env); - break; - case NM_MULSA_W_PH: - check_dsp_r2(ctx); - gen_helper_mulsa_w_ph(t0, v0, v1, cpu_env); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_POOL32AXF_2_24_31: - switch (extract32(ctx->opcode, 9, 3)) { - case NM_DPAU_H_QBR: - check_dsp(ctx); - gen_helper_dpau_h_qbr(t0, v1, v0, cpu_env); - break; - case NM_DPAQX_SA_W_PH: - check_dsp_r2(ctx); - gen_helper_dpaqx_sa_w_ph(t0, v1, v0, cpu_env); - break; - case NM_DPSU_H_QBR: - check_dsp(ctx); - gen_helper_dpsu_h_qbr(t0, v1, v0, cpu_env); - break; - case NM_DPSQX_SA_W_PH: - check_dsp_r2(ctx); - gen_helper_dpsqx_sa_w_ph(t0, v1, v0, cpu_env); - break; - case NM_MULSAQ_S_W_PH: - check_dsp(ctx); - gen_helper_mulsaq_s_w_ph(t0, v1, v0, cpu_env); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - - tcg_temp_free_i32(t0); -} - -static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc, - int rt, int rs, int rd) -{ - int ret = rt; - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - TCGv v0_t = tcg_temp_new(); - TCGv v1_t = tcg_temp_new(); - - gen_load_gpr(v0_t, rt); - gen_load_gpr(v1_t, rs); - - switch (opc) { - case NM_POOL32AXF_2_0_7: - switch (extract32(ctx->opcode, 9, 3)) { - case NM_DPA_W_PH: - case NM_DPAQ_S_W_PH: - case NM_DPS_W_PH: - case NM_DPSQ_S_W_PH: - gen_pool32axf_2_multiply(ctx, opc, v0_t, v1_t, rd); - break; - case NM_BALIGN: - check_dsp_r2(ctx); - if (rt != 0) { - gen_load_gpr(t0, rs); - rd &= 3; - if (rd != 0 && rd != 2) { - tcg_gen_shli_tl(cpu_gpr[ret], cpu_gpr[ret], 8 * rd); - tcg_gen_ext32u_tl(t0, t0); - tcg_gen_shri_tl(t0, t0, 8 * (4 - rd)); - tcg_gen_or_tl(cpu_gpr[ret], cpu_gpr[ret], t0); - } - tcg_gen_ext32s_tl(cpu_gpr[ret], cpu_gpr[ret]); - } - break; - case NM_MADD: - check_dsp(ctx); - { - int acc = extract32(ctx->opcode, 14, 2); - TCGv_i64 t2 = tcg_temp_new_i64(); - TCGv_i64 t3 = tcg_temp_new_i64(); - - gen_load_gpr(t0, rt); - gen_load_gpr(t1, rs); - tcg_gen_ext_tl_i64(t2, t0); - tcg_gen_ext_tl_i64(t3, t1); - tcg_gen_mul_i64(t2, t2, t3); - tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]); - tcg_gen_add_i64(t2, t2, t3); - tcg_temp_free_i64(t3); - gen_move_low32(cpu_LO[acc], t2); - gen_move_high32(cpu_HI[acc], t2); - tcg_temp_free_i64(t2); - } - break; - case NM_MULT: - check_dsp(ctx); - { - int acc = extract32(ctx->opcode, 14, 2); - TCGv_i32 t2 = tcg_temp_new_i32(); - TCGv_i32 t3 = tcg_temp_new_i32(); - - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - tcg_gen_trunc_tl_i32(t2, t0); - tcg_gen_trunc_tl_i32(t3, t1); - tcg_gen_muls2_i32(t2, t3, t2, t3); - tcg_gen_ext_i32_tl(cpu_LO[acc], t2); - tcg_gen_ext_i32_tl(cpu_HI[acc], t3); - tcg_temp_free_i32(t2); - tcg_temp_free_i32(t3); - } - break; - case NM_EXTRV_W: - check_dsp(ctx); - gen_load_gpr(v1_t, rs); - tcg_gen_movi_tl(t0, rd >> 3); - gen_helper_extr_w(t0, t0, v1_t, cpu_env); - gen_store_gpr(t0, ret); - break; - } - break; - case NM_POOL32AXF_2_8_15: - switch (extract32(ctx->opcode, 9, 3)) { - case NM_DPAX_W_PH: - case NM_DPAQ_SA_L_W: - case NM_DPSX_W_PH: - case NM_DPSQ_SA_L_W: - gen_pool32axf_2_multiply(ctx, opc, v0_t, v1_t, rd); - break; - case NM_MADDU: - check_dsp(ctx); - { - int acc = extract32(ctx->opcode, 14, 2); - TCGv_i64 t2 = tcg_temp_new_i64(); - TCGv_i64 t3 = tcg_temp_new_i64(); - - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - tcg_gen_ext32u_tl(t0, t0); - tcg_gen_ext32u_tl(t1, t1); - tcg_gen_extu_tl_i64(t2, t0); - tcg_gen_extu_tl_i64(t3, t1); - tcg_gen_mul_i64(t2, t2, t3); - tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]); - tcg_gen_add_i64(t2, t2, t3); - tcg_temp_free_i64(t3); - gen_move_low32(cpu_LO[acc], t2); - gen_move_high32(cpu_HI[acc], t2); - tcg_temp_free_i64(t2); - } - break; - case NM_MULTU: - check_dsp(ctx); - { - int acc = extract32(ctx->opcode, 14, 2); - TCGv_i32 t2 = tcg_temp_new_i32(); - TCGv_i32 t3 = tcg_temp_new_i32(); - - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - tcg_gen_trunc_tl_i32(t2, t0); - tcg_gen_trunc_tl_i32(t3, t1); - tcg_gen_mulu2_i32(t2, t3, t2, t3); - tcg_gen_ext_i32_tl(cpu_LO[acc], t2); - tcg_gen_ext_i32_tl(cpu_HI[acc], t3); - tcg_temp_free_i32(t2); - tcg_temp_free_i32(t3); - } - break; - case NM_EXTRV_R_W: - check_dsp(ctx); - tcg_gen_movi_tl(t0, rd >> 3); - gen_helper_extr_r_w(t0, t0, v1_t, cpu_env); - gen_store_gpr(t0, ret); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_POOL32AXF_2_16_23: - switch (extract32(ctx->opcode, 9, 3)) { - case NM_DPAU_H_QBL: - case NM_DPAQX_S_W_PH: - case NM_DPSU_H_QBL: - case NM_DPSQX_S_W_PH: - case NM_MULSA_W_PH: - gen_pool32axf_2_multiply(ctx, opc, v0_t, v1_t, rd); - break; - case NM_EXTPV: - check_dsp(ctx); - tcg_gen_movi_tl(t0, rd >> 3); - gen_helper_extp(t0, t0, v1_t, cpu_env); - gen_store_gpr(t0, ret); - break; - case NM_MSUB: - check_dsp(ctx); - { - int acc = extract32(ctx->opcode, 14, 2); - TCGv_i64 t2 = tcg_temp_new_i64(); - TCGv_i64 t3 = tcg_temp_new_i64(); - - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - tcg_gen_ext_tl_i64(t2, t0); - tcg_gen_ext_tl_i64(t3, t1); - tcg_gen_mul_i64(t2, t2, t3); - tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]); - tcg_gen_sub_i64(t2, t3, t2); - tcg_temp_free_i64(t3); - gen_move_low32(cpu_LO[acc], t2); - gen_move_high32(cpu_HI[acc], t2); - tcg_temp_free_i64(t2); - } - break; - case NM_EXTRV_RS_W: - check_dsp(ctx); - tcg_gen_movi_tl(t0, rd >> 3); - gen_helper_extr_rs_w(t0, t0, v1_t, cpu_env); - gen_store_gpr(t0, ret); - break; - } - break; - case NM_POOL32AXF_2_24_31: - switch (extract32(ctx->opcode, 9, 3)) { - case NM_DPAU_H_QBR: - case NM_DPAQX_SA_W_PH: - case NM_DPSU_H_QBR: - case NM_DPSQX_SA_W_PH: - case NM_MULSAQ_S_W_PH: - gen_pool32axf_2_multiply(ctx, opc, v0_t, v1_t, rd); - break; - case NM_EXTPDPV: - check_dsp(ctx); - tcg_gen_movi_tl(t0, rd >> 3); - gen_helper_extpdp(t0, t0, v1_t, cpu_env); - gen_store_gpr(t0, ret); - break; - case NM_MSUBU: - check_dsp(ctx); - { - int acc = extract32(ctx->opcode, 14, 2); - TCGv_i64 t2 = tcg_temp_new_i64(); - TCGv_i64 t3 = tcg_temp_new_i64(); - - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - tcg_gen_ext32u_tl(t0, t0); - tcg_gen_ext32u_tl(t1, t1); - tcg_gen_extu_tl_i64(t2, t0); - tcg_gen_extu_tl_i64(t3, t1); - tcg_gen_mul_i64(t2, t2, t3); - tcg_gen_concat_tl_i64(t3, cpu_LO[acc], cpu_HI[acc]); - tcg_gen_sub_i64(t2, t3, t2); - tcg_temp_free_i64(t3); - gen_move_low32(cpu_LO[acc], t2); - gen_move_high32(cpu_HI[acc], t2); - tcg_temp_free_i64(t2); - } - break; - case NM_EXTRV_S_H: - check_dsp(ctx); - tcg_gen_movi_tl(t0, rd >> 3); - gen_helper_extr_s_h(t0, t0, v0_t, cpu_env); - gen_store_gpr(t0, ret); - break; - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - - tcg_temp_free(t0); - tcg_temp_free(t1); - - tcg_temp_free(v0_t); - tcg_temp_free(v1_t); -} - -static void gen_pool32axf_4_nanomips_insn(DisasContext *ctx, uint32_t opc, - int rt, int rs) -{ - int ret = rt; - TCGv t0 = tcg_temp_new(); - TCGv v0_t = tcg_temp_new(); - - gen_load_gpr(v0_t, rs); - - switch (opc) { - case NM_ABSQ_S_QB: - check_dsp_r2(ctx); - gen_helper_absq_s_qb(v0_t, v0_t, cpu_env); - gen_store_gpr(v0_t, ret); - break; - case NM_ABSQ_S_PH: - check_dsp(ctx); - gen_helper_absq_s_ph(v0_t, v0_t, cpu_env); - gen_store_gpr(v0_t, ret); - break; - case NM_ABSQ_S_W: - check_dsp(ctx); - gen_helper_absq_s_w(v0_t, v0_t, cpu_env); - gen_store_gpr(v0_t, ret); - break; - case NM_PRECEQ_W_PHL: - check_dsp(ctx); - tcg_gen_andi_tl(v0_t, v0_t, 0xFFFF0000); - tcg_gen_ext32s_tl(v0_t, v0_t); - gen_store_gpr(v0_t, ret); - break; - case NM_PRECEQ_W_PHR: - check_dsp(ctx); - tcg_gen_andi_tl(v0_t, v0_t, 0x0000FFFF); - tcg_gen_shli_tl(v0_t, v0_t, 16); - tcg_gen_ext32s_tl(v0_t, v0_t); - gen_store_gpr(v0_t, ret); - break; - case NM_PRECEQU_PH_QBL: - check_dsp(ctx); - gen_helper_precequ_ph_qbl(v0_t, v0_t); - gen_store_gpr(v0_t, ret); - break; - case NM_PRECEQU_PH_QBR: - check_dsp(ctx); - gen_helper_precequ_ph_qbr(v0_t, v0_t); - gen_store_gpr(v0_t, ret); - break; - case NM_PRECEQU_PH_QBLA: - check_dsp(ctx); - gen_helper_precequ_ph_qbla(v0_t, v0_t); - gen_store_gpr(v0_t, ret); - break; - case NM_PRECEQU_PH_QBRA: - check_dsp(ctx); - gen_helper_precequ_ph_qbra(v0_t, v0_t); - gen_store_gpr(v0_t, ret); - break; - case NM_PRECEU_PH_QBL: - check_dsp(ctx); - gen_helper_preceu_ph_qbl(v0_t, v0_t); - gen_store_gpr(v0_t, ret); - break; - case NM_PRECEU_PH_QBR: - check_dsp(ctx); - gen_helper_preceu_ph_qbr(v0_t, v0_t); - gen_store_gpr(v0_t, ret); - break; - case NM_PRECEU_PH_QBLA: - check_dsp(ctx); - gen_helper_preceu_ph_qbla(v0_t, v0_t); - gen_store_gpr(v0_t, ret); - break; - case NM_PRECEU_PH_QBRA: - check_dsp(ctx); - gen_helper_preceu_ph_qbra(v0_t, v0_t); - gen_store_gpr(v0_t, ret); - break; - case NM_REPLV_PH: - check_dsp(ctx); - tcg_gen_ext16u_tl(v0_t, v0_t); - tcg_gen_shli_tl(t0, v0_t, 16); - tcg_gen_or_tl(v0_t, v0_t, t0); - tcg_gen_ext32s_tl(v0_t, v0_t); - gen_store_gpr(v0_t, ret); - break; - case NM_REPLV_QB: - check_dsp(ctx); - tcg_gen_ext8u_tl(v0_t, v0_t); - tcg_gen_shli_tl(t0, v0_t, 8); - tcg_gen_or_tl(v0_t, v0_t, t0); - tcg_gen_shli_tl(t0, v0_t, 16); - tcg_gen_or_tl(v0_t, v0_t, t0); - tcg_gen_ext32s_tl(v0_t, v0_t); - gen_store_gpr(v0_t, ret); - break; - case NM_BITREV: - check_dsp(ctx); - gen_helper_bitrev(v0_t, v0_t); - gen_store_gpr(v0_t, ret); - break; - case NM_INSV: - check_dsp(ctx); - { - TCGv tv0 = tcg_temp_new(); - - gen_load_gpr(tv0, rt); - gen_helper_insv(v0_t, cpu_env, v0_t, tv0); - gen_store_gpr(v0_t, ret); - tcg_temp_free(tv0); - } - break; - case NM_RADDU_W_QB: - check_dsp(ctx); - gen_helper_raddu_w_qb(v0_t, v0_t); - gen_store_gpr(v0_t, ret); - break; - case NM_BITSWAP: - gen_bitswap(ctx, OPC_BITSWAP, ret, rs); - break; - case NM_CLO: - check_nms(ctx); - gen_cl(ctx, OPC_CLO, ret, rs); - break; - case NM_CLZ: - check_nms(ctx); - gen_cl(ctx, OPC_CLZ, ret, rs); - break; - case NM_WSBH: - gen_bshfl(ctx, OPC_WSBH, ret, rs); - break; - default: - gen_reserved_instruction(ctx); - break; - } - - tcg_temp_free(v0_t); - tcg_temp_free(t0); -} - -static void gen_pool32axf_7_nanomips_insn(DisasContext *ctx, uint32_t opc, - int rt, int rs, int rd) -{ - TCGv t0 = tcg_temp_new(); - TCGv rs_t = tcg_temp_new(); - - gen_load_gpr(rs_t, rs); - - switch (opc) { - case NM_SHRA_R_QB: - check_dsp_r2(ctx); - tcg_gen_movi_tl(t0, rd >> 2); - switch (extract32(ctx->opcode, 12, 1)) { - case 0: - /* NM_SHRA_QB */ - gen_helper_shra_qb(t0, t0, rs_t); - gen_store_gpr(t0, rt); - break; - case 1: - /* NM_SHRA_R_QB */ - gen_helper_shra_r_qb(t0, t0, rs_t); - gen_store_gpr(t0, rt); - break; - } - break; - case NM_SHRL_PH: - check_dsp_r2(ctx); - tcg_gen_movi_tl(t0, rd >> 1); - gen_helper_shrl_ph(t0, t0, rs_t); - gen_store_gpr(t0, rt); - break; - case NM_REPL_QB: - check_dsp(ctx); - { - int16_t imm; - target_long result; - imm = extract32(ctx->opcode, 13, 8); - result = (uint32_t)imm << 24 | - (uint32_t)imm << 16 | - (uint32_t)imm << 8 | - (uint32_t)imm; - result = (int32_t)result; - tcg_gen_movi_tl(t0, result); - gen_store_gpr(t0, rt); - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - tcg_temp_free(t0); - tcg_temp_free(rs_t); -} - - -static void gen_pool32axf_nanomips_insn(CPUMIPSState *env, DisasContext *ctx) -{ - int rt = extract32(ctx->opcode, 21, 5); - int rs = extract32(ctx->opcode, 16, 5); - int rd = extract32(ctx->opcode, 11, 5); - - switch (extract32(ctx->opcode, 6, 3)) { - case NM_POOL32AXF_1: - { - int32_t op1 = extract32(ctx->opcode, 9, 3); - gen_pool32axf_1_nanomips_insn(ctx, op1, rt, rs, rd); - } - break; - case NM_POOL32AXF_2: - { - int32_t op1 = extract32(ctx->opcode, 12, 2); - gen_pool32axf_2_nanomips_insn(ctx, op1, rt, rs, rd); - } - break; - case NM_POOL32AXF_4: - { - int32_t op1 = extract32(ctx->opcode, 9, 7); - gen_pool32axf_4_nanomips_insn(ctx, op1, rt, rs); - } - break; - case NM_POOL32AXF_5: - switch (extract32(ctx->opcode, 9, 7)) { -#ifndef CONFIG_USER_ONLY - case NM_TLBP: - gen_cp0(env, ctx, OPC_TLBP, 0, 0); - break; - case NM_TLBR: - gen_cp0(env, ctx, OPC_TLBR, 0, 0); - break; - case NM_TLBWI: - gen_cp0(env, ctx, OPC_TLBWI, 0, 0); - break; - case NM_TLBWR: - gen_cp0(env, ctx, OPC_TLBWR, 0, 0); - break; - case NM_TLBINV: - gen_cp0(env, ctx, OPC_TLBINV, 0, 0); - break; - case NM_TLBINVF: - gen_cp0(env, ctx, OPC_TLBINVF, 0, 0); - break; - case NM_DI: - check_cp0_enabled(ctx); - { - TCGv t0 = tcg_temp_new(); - - save_cpu_state(ctx, 1); - gen_helper_di(t0, cpu_env); - gen_store_gpr(t0, rt); - /* Stop translation as we may have switched the execution mode */ - ctx->base.is_jmp = DISAS_STOP; - tcg_temp_free(t0); - } - break; - case NM_EI: - check_cp0_enabled(ctx); - { - TCGv t0 = tcg_temp_new(); - - save_cpu_state(ctx, 1); - gen_helper_ei(t0, cpu_env); - gen_store_gpr(t0, rt); - /* Stop translation as we may have switched the execution mode */ - ctx->base.is_jmp = DISAS_STOP; - tcg_temp_free(t0); - } - break; - case NM_RDPGPR: - check_cp0_enabled(ctx); - gen_load_srsgpr(rs, rt); - break; - case NM_WRPGPR: - check_cp0_enabled(ctx); - gen_store_srsgpr(rs, rt); - break; - case NM_WAIT: - gen_cp0(env, ctx, OPC_WAIT, 0, 0); - break; - case NM_DERET: - gen_cp0(env, ctx, OPC_DERET, 0, 0); - break; - case NM_ERETX: - gen_cp0(env, ctx, OPC_ERET, 0, 0); - break; -#endif - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_POOL32AXF_7: - { - int32_t op1 = extract32(ctx->opcode, 9, 3); - gen_pool32axf_7_nanomips_insn(ctx, op1, rt, rs, rd); - } - break; - default: - gen_reserved_instruction(ctx); - break; - } -} - -/* Immediate Value Compact Branches */ -static void gen_compute_imm_branch(DisasContext *ctx, uint32_t opc, - int rt, int32_t imm, int32_t offset) -{ - TCGCond cond = TCG_COND_ALWAYS; - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - - gen_load_gpr(t0, rt); - tcg_gen_movi_tl(t1, imm); - ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); - - /* Load needed operands and calculate btarget */ - switch (opc) { - case NM_BEQIC: - if (rt == 0 && imm == 0) { - /* Unconditional branch */ - } else if (rt == 0 && imm != 0) { - /* Treat as NOP */ - goto out; - } else { - cond = TCG_COND_EQ; - } - break; - case NM_BBEQZC: - case NM_BBNEZC: - check_nms(ctx); - if (imm >= 32 && !(ctx->hflags & MIPS_HFLAG_64)) { - gen_reserved_instruction(ctx); - goto out; - } else if (rt == 0 && opc == NM_BBEQZC) { - /* Unconditional branch */ - } else if (rt == 0 && opc == NM_BBNEZC) { - /* Treat as NOP */ - goto out; - } else { - tcg_gen_shri_tl(t0, t0, imm); - tcg_gen_andi_tl(t0, t0, 1); - tcg_gen_movi_tl(t1, 0); - if (opc == NM_BBEQZC) { - cond = TCG_COND_EQ; - } else { - cond = TCG_COND_NE; - } - } - break; - case NM_BNEIC: - if (rt == 0 && imm == 0) { - /* Treat as NOP */ - goto out; - } else if (rt == 0 && imm != 0) { - /* Unconditional branch */ - } else { - cond = TCG_COND_NE; - } - break; - case NM_BGEIC: - if (rt == 0 && imm == 0) { - /* Unconditional branch */ - } else { - cond = TCG_COND_GE; - } - break; - case NM_BLTIC: - cond = TCG_COND_LT; - break; - case NM_BGEIUC: - if (rt == 0 && imm == 0) { - /* Unconditional branch */ - } else { - cond = TCG_COND_GEU; - } - break; - case NM_BLTIUC: - cond = TCG_COND_LTU; - break; - default: - MIPS_INVAL("Immediate Value Compact branch"); - gen_reserved_instruction(ctx); - goto out; - } - - /* branch completion */ - clear_branch_hflags(ctx); - ctx->base.is_jmp = DISAS_NORETURN; - - if (cond == TCG_COND_ALWAYS) { - /* Unconditional compact branch */ - gen_goto_tb(ctx, 0, ctx->btarget); - } else { - /* Conditional compact branch */ - TCGLabel *fs = gen_new_label(); - - tcg_gen_brcond_tl(tcg_invert_cond(cond), t0, t1, fs); - - gen_goto_tb(ctx, 1, ctx->btarget); - gen_set_label(fs); - - gen_goto_tb(ctx, 0, ctx->base.pc_next + 4); - } - -out: - tcg_temp_free(t0); - tcg_temp_free(t1); -} - -/* P.BALRSC type nanoMIPS R6 branches: BALRSC and BRSC */ -static void gen_compute_nanomips_pbalrsc_branch(DisasContext *ctx, int rs, - int rt) -{ - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - - /* load rs */ - gen_load_gpr(t0, rs); - - /* link */ - if (rt != 0) { - tcg_gen_movi_tl(cpu_gpr[rt], ctx->base.pc_next + 4); - } - - /* calculate btarget */ - tcg_gen_shli_tl(t0, t0, 1); - tcg_gen_movi_tl(t1, ctx->base.pc_next + 4); - gen_op_addr_add(ctx, btarget, t1, t0); - - /* branch completion */ - clear_branch_hflags(ctx); - ctx->base.is_jmp = DISAS_NORETURN; - - /* unconditional branch to register */ - tcg_gen_mov_tl(cpu_PC, btarget); - tcg_gen_lookup_and_goto_ptr(); - - tcg_temp_free(t0); - tcg_temp_free(t1); -} - -/* nanoMIPS Branches */ -static void gen_compute_compact_branch_nm(DisasContext *ctx, uint32_t opc, - int rs, int rt, int32_t offset) -{ - int bcond_compute = 0; - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - - /* Load needed operands and calculate btarget */ - switch (opc) { - /* compact branch */ - case OPC_BGEC: - case OPC_BLTC: - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - bcond_compute = 1; - ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); - break; - case OPC_BGEUC: - case OPC_BLTUC: - if (rs == 0 || rs == rt) { - /* OPC_BLEZALC, OPC_BGEZALC */ - /* OPC_BGTZALC, OPC_BLTZALC */ - tcg_gen_movi_tl(cpu_gpr[31], ctx->base.pc_next + 4); - } - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - bcond_compute = 1; - ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); - break; - case OPC_BC: - ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); - break; - case OPC_BEQZC: - if (rs != 0) { - /* OPC_BEQZC, OPC_BNEZC */ - gen_load_gpr(t0, rs); - bcond_compute = 1; - ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); - } else { - /* OPC_JIC, OPC_JIALC */ - TCGv tbase = tcg_temp_new(); - TCGv toffset = tcg_temp_new(); - - gen_load_gpr(tbase, rt); - tcg_gen_movi_tl(toffset, offset); - gen_op_addr_add(ctx, btarget, tbase, toffset); - tcg_temp_free(tbase); - tcg_temp_free(toffset); - } - break; - default: - MIPS_INVAL("Compact branch/jump"); - gen_reserved_instruction(ctx); - goto out; - } - - if (bcond_compute == 0) { - /* Unconditional compact branch */ - switch (opc) { - case OPC_BC: - gen_goto_tb(ctx, 0, ctx->btarget); - break; - default: - MIPS_INVAL("Compact branch/jump"); - gen_reserved_instruction(ctx); - goto out; - } - } else { - /* Conditional compact branch */ - TCGLabel *fs = gen_new_label(); - - switch (opc) { - case OPC_BGEUC: - if (rs == 0 && rt != 0) { - /* OPC_BLEZALC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LE), t1, 0, fs); - } else if (rs != 0 && rt != 0 && rs == rt) { - /* OPC_BGEZALC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GE), t1, 0, fs); - } else { - /* OPC_BGEUC */ - tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_GEU), t0, t1, fs); - } - break; - case OPC_BLTUC: - if (rs == 0 && rt != 0) { - /* OPC_BGTZALC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GT), t1, 0, fs); - } else if (rs != 0 && rt != 0 && rs == rt) { - /* OPC_BLTZALC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LT), t1, 0, fs); - } else { - /* OPC_BLTUC */ - tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_LTU), t0, t1, fs); - } - break; - case OPC_BGEC: - if (rs == 0 && rt != 0) { - /* OPC_BLEZC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LE), t1, 0, fs); - } else if (rs != 0 && rt != 0 && rs == rt) { - /* OPC_BGEZC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GE), t1, 0, fs); - } else { - /* OPC_BGEC */ - tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_GE), t0, t1, fs); - } - break; - case OPC_BLTC: - if (rs == 0 && rt != 0) { - /* OPC_BGTZC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GT), t1, 0, fs); - } else if (rs != 0 && rt != 0 && rs == rt) { - /* OPC_BLTZC */ - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LT), t1, 0, fs); - } else { - /* OPC_BLTC */ - tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_LT), t0, t1, fs); - } - break; - case OPC_BEQZC: - tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_EQ), t0, 0, fs); - break; - default: - MIPS_INVAL("Compact conditional branch/jump"); - gen_reserved_instruction(ctx); - goto out; - } - - /* branch completion */ - clear_branch_hflags(ctx); - ctx->base.is_jmp = DISAS_NORETURN; - - /* Generating branch here as compact branches don't have delay slot */ - gen_goto_tb(ctx, 1, ctx->btarget); - gen_set_label(fs); - - gen_goto_tb(ctx, 0, ctx->base.pc_next + 4); - } - -out: - tcg_temp_free(t0); - tcg_temp_free(t1); -} - - -/* nanoMIPS CP1 Branches */ -static void gen_compute_branch_cp1_nm(DisasContext *ctx, uint32_t op, - int32_t ft, int32_t offset) -{ - target_ulong btarget; - TCGv_i64 t0 = tcg_temp_new_i64(); - - gen_load_fpr64(ctx, t0, ft); - tcg_gen_andi_i64(t0, t0, 1); - - btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); - - switch (op) { - case NM_BC1EQZC: - tcg_gen_xori_i64(t0, t0, 1); - ctx->hflags |= MIPS_HFLAG_BC; - break; - case NM_BC1NEZC: - /* t0 already set */ - ctx->hflags |= MIPS_HFLAG_BC; - break; - default: - MIPS_INVAL("cp1 cond branch"); - gen_reserved_instruction(ctx); - goto out; - } - - tcg_gen_trunc_i64_tl(bcond, t0); - - ctx->btarget = btarget; - -out: - tcg_temp_free_i64(t0); -} - - -static void gen_p_lsx(DisasContext *ctx, int rd, int rs, int rt) -{ - TCGv t0, t1; - t0 = tcg_temp_new(); - t1 = tcg_temp_new(); - - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - - if ((extract32(ctx->opcode, 6, 1)) == 1) { - /* PP.LSXS instructions require shifting */ - switch (extract32(ctx->opcode, 7, 4)) { - case NM_SHXS: - check_nms(ctx); - /* fall through */ - case NM_LHXS: - case NM_LHUXS: - tcg_gen_shli_tl(t0, t0, 1); - break; - case NM_SWXS: - check_nms(ctx); - /* fall through */ - case NM_LWXS: - case NM_LWC1XS: - case NM_SWC1XS: - tcg_gen_shli_tl(t0, t0, 2); - break; - case NM_LDC1XS: - case NM_SDC1XS: - tcg_gen_shli_tl(t0, t0, 3); - break; - } - } - gen_op_addr_add(ctx, t0, t0, t1); - - switch (extract32(ctx->opcode, 7, 4)) { - case NM_LBX: - tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, - MO_SB); - gen_store_gpr(t0, rd); - break; - case NM_LHX: - /*case NM_LHXS:*/ - tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, - MO_TESW); - gen_store_gpr(t0, rd); - break; - case NM_LWX: - /*case NM_LWXS:*/ - tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, - MO_TESL); - gen_store_gpr(t0, rd); - break; - case NM_LBUX: - tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, - MO_UB); - gen_store_gpr(t0, rd); - break; - case NM_LHUX: - /*case NM_LHUXS:*/ - tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, - MO_TEUW); - gen_store_gpr(t0, rd); - break; - case NM_SBX: - check_nms(ctx); - gen_load_gpr(t1, rd); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, - MO_8); - break; - case NM_SHX: - /*case NM_SHXS:*/ - check_nms(ctx); - gen_load_gpr(t1, rd); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, - MO_TEUW); - break; - case NM_SWX: - /*case NM_SWXS:*/ - check_nms(ctx); - gen_load_gpr(t1, rd); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, - MO_TEUL); - break; - case NM_LWC1X: - /*case NM_LWC1XS:*/ - case NM_LDC1X: - /*case NM_LDC1XS:*/ - case NM_SWC1X: - /*case NM_SWC1XS:*/ - case NM_SDC1X: - /*case NM_SDC1XS:*/ - if (ctx->CP0_Config1 & (1 << CP0C1_FP)) { - check_cp1_enabled(ctx); - switch (extract32(ctx->opcode, 7, 4)) { - case NM_LWC1X: - /*case NM_LWC1XS:*/ - gen_flt_ldst(ctx, OPC_LWC1, rd, t0); - break; - case NM_LDC1X: - /*case NM_LDC1XS:*/ - gen_flt_ldst(ctx, OPC_LDC1, rd, t0); - break; - case NM_SWC1X: - /*case NM_SWC1XS:*/ - gen_flt_ldst(ctx, OPC_SWC1, rd, t0); - break; - case NM_SDC1X: - /*case NM_SDC1XS:*/ - gen_flt_ldst(ctx, OPC_SDC1, rd, t0); - break; - } - } else { - generate_exception_err(ctx, EXCP_CpU, 1); - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - - tcg_temp_free(t0); - tcg_temp_free(t1); -} - -static void gen_pool32f_nanomips_insn(DisasContext *ctx) -{ - int rt, rs, rd; - - rt = extract32(ctx->opcode, 21, 5); - rs = extract32(ctx->opcode, 16, 5); - rd = extract32(ctx->opcode, 11, 5); - - if (!(ctx->CP0_Config1 & (1 << CP0C1_FP))) { - gen_reserved_instruction(ctx); - return; - } - check_cp1_enabled(ctx); - switch (extract32(ctx->opcode, 0, 3)) { - case NM_POOL32F_0: - switch (extract32(ctx->opcode, 3, 7)) { - case NM_RINT_S: - gen_farith(ctx, OPC_RINT_S, 0, rt, rs, 0); - break; - case NM_RINT_D: - gen_farith(ctx, OPC_RINT_D, 0, rt, rs, 0); - break; - case NM_CLASS_S: - gen_farith(ctx, OPC_CLASS_S, 0, rt, rs, 0); - break; - case NM_CLASS_D: - gen_farith(ctx, OPC_CLASS_D, 0, rt, rs, 0); - break; - case NM_ADD_S: - gen_farith(ctx, OPC_ADD_S, rt, rs, rd, 0); - break; - case NM_ADD_D: - gen_farith(ctx, OPC_ADD_D, rt, rs, rd, 0); - break; - case NM_SUB_S: - gen_farith(ctx, OPC_SUB_S, rt, rs, rd, 0); - break; - case NM_SUB_D: - gen_farith(ctx, OPC_SUB_D, rt, rs, rd, 0); - break; - case NM_MUL_S: - gen_farith(ctx, OPC_MUL_S, rt, rs, rd, 0); - break; - case NM_MUL_D: - gen_farith(ctx, OPC_MUL_D, rt, rs, rd, 0); - break; - case NM_DIV_S: - gen_farith(ctx, OPC_DIV_S, rt, rs, rd, 0); - break; - case NM_DIV_D: - gen_farith(ctx, OPC_DIV_D, rt, rs, rd, 0); - break; - case NM_SELEQZ_S: - gen_sel_s(ctx, OPC_SELEQZ_S, rd, rt, rs); - break; - case NM_SELEQZ_D: - gen_sel_d(ctx, OPC_SELEQZ_D, rd, rt, rs); - break; - case NM_SELNEZ_S: - gen_sel_s(ctx, OPC_SELNEZ_S, rd, rt, rs); - break; - case NM_SELNEZ_D: - gen_sel_d(ctx, OPC_SELNEZ_D, rd, rt, rs); - break; - case NM_SEL_S: - gen_sel_s(ctx, OPC_SEL_S, rd, rt, rs); - break; - case NM_SEL_D: - gen_sel_d(ctx, OPC_SEL_D, rd, rt, rs); - break; - case NM_MADDF_S: - gen_farith(ctx, OPC_MADDF_S, rt, rs, rd, 0); - break; - case NM_MADDF_D: - gen_farith(ctx, OPC_MADDF_D, rt, rs, rd, 0); - break; - case NM_MSUBF_S: - gen_farith(ctx, OPC_MSUBF_S, rt, rs, rd, 0); - break; - case NM_MSUBF_D: - gen_farith(ctx, OPC_MSUBF_D, rt, rs, rd, 0); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_POOL32F_3: - switch (extract32(ctx->opcode, 3, 3)) { - case NM_MIN_FMT: - switch (extract32(ctx->opcode, 9, 1)) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_MIN_S, rt, rs, rd, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_MIN_D, rt, rs, rd, 0); - break; - } - break; - case NM_MAX_FMT: - switch (extract32(ctx->opcode, 9, 1)) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_MAX_S, rt, rs, rd, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_MAX_D, rt, rs, rd, 0); - break; - } - break; - case NM_MINA_FMT: - switch (extract32(ctx->opcode, 9, 1)) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_MINA_S, rt, rs, rd, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_MINA_D, rt, rs, rd, 0); - break; - } - break; - case NM_MAXA_FMT: - switch (extract32(ctx->opcode, 9, 1)) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_MAXA_S, rt, rs, rd, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_MAXA_D, rt, rs, rd, 0); - break; - } - break; - case NM_POOL32FXF: - switch (extract32(ctx->opcode, 6, 8)) { - case NM_CFC1: - gen_cp1(ctx, OPC_CFC1, rt, rs); - break; - case NM_CTC1: - gen_cp1(ctx, OPC_CTC1, rt, rs); - break; - case NM_MFC1: - gen_cp1(ctx, OPC_MFC1, rt, rs); - break; - case NM_MTC1: - gen_cp1(ctx, OPC_MTC1, rt, rs); - break; - case NM_MFHC1: - gen_cp1(ctx, OPC_MFHC1, rt, rs); - break; - case NM_MTHC1: - gen_cp1(ctx, OPC_MTHC1, rt, rs); - break; - case NM_CVT_S_PL: - gen_farith(ctx, OPC_CVT_S_PL, -1, rs, rt, 0); - break; - case NM_CVT_S_PU: - gen_farith(ctx, OPC_CVT_S_PU, -1, rs, rt, 0); - break; - default: - switch (extract32(ctx->opcode, 6, 9)) { - case NM_CVT_L_S: - gen_farith(ctx, OPC_CVT_L_S, -1, rs, rt, 0); - break; - case NM_CVT_L_D: - gen_farith(ctx, OPC_CVT_L_D, -1, rs, rt, 0); - break; - case NM_CVT_W_S: - gen_farith(ctx, OPC_CVT_W_S, -1, rs, rt, 0); - break; - case NM_CVT_W_D: - gen_farith(ctx, OPC_CVT_W_D, -1, rs, rt, 0); - break; - case NM_RSQRT_S: - gen_farith(ctx, OPC_RSQRT_S, -1, rs, rt, 0); - break; - case NM_RSQRT_D: - gen_farith(ctx, OPC_RSQRT_D, -1, rs, rt, 0); - break; - case NM_SQRT_S: - gen_farith(ctx, OPC_SQRT_S, -1, rs, rt, 0); - break; - case NM_SQRT_D: - gen_farith(ctx, OPC_SQRT_D, -1, rs, rt, 0); - break; - case NM_RECIP_S: - gen_farith(ctx, OPC_RECIP_S, -1, rs, rt, 0); - break; - case NM_RECIP_D: - gen_farith(ctx, OPC_RECIP_D, -1, rs, rt, 0); - break; - case NM_FLOOR_L_S: - gen_farith(ctx, OPC_FLOOR_L_S, -1, rs, rt, 0); - break; - case NM_FLOOR_L_D: - gen_farith(ctx, OPC_FLOOR_L_D, -1, rs, rt, 0); - break; - case NM_FLOOR_W_S: - gen_farith(ctx, OPC_FLOOR_W_S, -1, rs, rt, 0); - break; - case NM_FLOOR_W_D: - gen_farith(ctx, OPC_FLOOR_W_D, -1, rs, rt, 0); - break; - case NM_CEIL_L_S: - gen_farith(ctx, OPC_CEIL_L_S, -1, rs, rt, 0); - break; - case NM_CEIL_L_D: - gen_farith(ctx, OPC_CEIL_L_D, -1, rs, rt, 0); - break; - case NM_CEIL_W_S: - gen_farith(ctx, OPC_CEIL_W_S, -1, rs, rt, 0); - break; - case NM_CEIL_W_D: - gen_farith(ctx, OPC_CEIL_W_D, -1, rs, rt, 0); - break; - case NM_TRUNC_L_S: - gen_farith(ctx, OPC_TRUNC_L_S, -1, rs, rt, 0); - break; - case NM_TRUNC_L_D: - gen_farith(ctx, OPC_TRUNC_L_D, -1, rs, rt, 0); - break; - case NM_TRUNC_W_S: - gen_farith(ctx, OPC_TRUNC_W_S, -1, rs, rt, 0); - break; - case NM_TRUNC_W_D: - gen_farith(ctx, OPC_TRUNC_W_D, -1, rs, rt, 0); - break; - case NM_ROUND_L_S: - gen_farith(ctx, OPC_ROUND_L_S, -1, rs, rt, 0); - break; - case NM_ROUND_L_D: - gen_farith(ctx, OPC_ROUND_L_D, -1, rs, rt, 0); - break; - case NM_ROUND_W_S: - gen_farith(ctx, OPC_ROUND_W_S, -1, rs, rt, 0); - break; - case NM_ROUND_W_D: - gen_farith(ctx, OPC_ROUND_W_D, -1, rs, rt, 0); - break; - case NM_MOV_S: - gen_farith(ctx, OPC_MOV_S, -1, rs, rt, 0); - break; - case NM_MOV_D: - gen_farith(ctx, OPC_MOV_D, -1, rs, rt, 0); - break; - case NM_ABS_S: - gen_farith(ctx, OPC_ABS_S, -1, rs, rt, 0); - break; - case NM_ABS_D: - gen_farith(ctx, OPC_ABS_D, -1, rs, rt, 0); - break; - case NM_NEG_S: - gen_farith(ctx, OPC_NEG_S, -1, rs, rt, 0); - break; - case NM_NEG_D: - gen_farith(ctx, OPC_NEG_D, -1, rs, rt, 0); - break; - case NM_CVT_D_S: - gen_farith(ctx, OPC_CVT_D_S, -1, rs, rt, 0); - break; - case NM_CVT_D_W: - gen_farith(ctx, OPC_CVT_D_W, -1, rs, rt, 0); - break; - case NM_CVT_D_L: - gen_farith(ctx, OPC_CVT_D_L, -1, rs, rt, 0); - break; - case NM_CVT_S_D: - gen_farith(ctx, OPC_CVT_S_D, -1, rs, rt, 0); - break; - case NM_CVT_S_W: - gen_farith(ctx, OPC_CVT_S_W, -1, rs, rt, 0); - break; - case NM_CVT_S_L: - gen_farith(ctx, OPC_CVT_S_L, -1, rs, rt, 0); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - } - break; - } - break; - case NM_POOL32F_5: - switch (extract32(ctx->opcode, 3, 3)) { - case NM_CMP_CONDN_S: - gen_r6_cmp_s(ctx, extract32(ctx->opcode, 6, 5), rt, rs, rd); - break; - case NM_CMP_CONDN_D: - gen_r6_cmp_d(ctx, extract32(ctx->opcode, 6, 5), rt, rs, rd); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - default: - gen_reserved_instruction(ctx); - break; - } -} - -static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc, - int rd, int rs, int rt) -{ - int ret = rd; - TCGv t0 = tcg_temp_new(); - TCGv v1_t = tcg_temp_new(); - TCGv v2_t = tcg_temp_new(); - - gen_load_gpr(v1_t, rs); - gen_load_gpr(v2_t, rt); - - switch (opc) { - case NM_CMP_EQ_PH: - check_dsp(ctx); - gen_helper_cmp_eq_ph(v1_t, v2_t, cpu_env); - break; - case NM_CMP_LT_PH: - check_dsp(ctx); - gen_helper_cmp_lt_ph(v1_t, v2_t, cpu_env); - break; - case NM_CMP_LE_PH: - check_dsp(ctx); - gen_helper_cmp_le_ph(v1_t, v2_t, cpu_env); - break; - case NM_CMPU_EQ_QB: - check_dsp(ctx); - gen_helper_cmpu_eq_qb(v1_t, v2_t, cpu_env); - break; - case NM_CMPU_LT_QB: - check_dsp(ctx); - gen_helper_cmpu_lt_qb(v1_t, v2_t, cpu_env); - break; - case NM_CMPU_LE_QB: - check_dsp(ctx); - gen_helper_cmpu_le_qb(v1_t, v2_t, cpu_env); - break; - case NM_CMPGU_EQ_QB: - check_dsp(ctx); - gen_helper_cmpgu_eq_qb(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case NM_CMPGU_LT_QB: - check_dsp(ctx); - gen_helper_cmpgu_lt_qb(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case NM_CMPGU_LE_QB: - check_dsp(ctx); - gen_helper_cmpgu_le_qb(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case NM_CMPGDU_EQ_QB: - check_dsp_r2(ctx); - gen_helper_cmpgu_eq_qb(v1_t, v1_t, v2_t); - tcg_gen_deposit_tl(cpu_dspctrl, cpu_dspctrl, v1_t, 24, 4); - gen_store_gpr(v1_t, ret); - break; - case NM_CMPGDU_LT_QB: - check_dsp_r2(ctx); - gen_helper_cmpgu_lt_qb(v1_t, v1_t, v2_t); - tcg_gen_deposit_tl(cpu_dspctrl, cpu_dspctrl, v1_t, 24, 4); - gen_store_gpr(v1_t, ret); - break; - case NM_CMPGDU_LE_QB: - check_dsp_r2(ctx); - gen_helper_cmpgu_le_qb(v1_t, v1_t, v2_t); - tcg_gen_deposit_tl(cpu_dspctrl, cpu_dspctrl, v1_t, 24, 4); - gen_store_gpr(v1_t, ret); - break; - case NM_PACKRL_PH: - check_dsp(ctx); - gen_helper_packrl_ph(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case NM_PICK_QB: - check_dsp(ctx); - gen_helper_pick_qb(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_PICK_PH: - check_dsp(ctx); - gen_helper_pick_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_ADDQ_S_W: - check_dsp(ctx); - gen_helper_addq_s_w(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_SUBQ_S_W: - check_dsp(ctx); - gen_helper_subq_s_w(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_ADDSC: - check_dsp(ctx); - gen_helper_addsc(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_ADDWC: - check_dsp(ctx); - gen_helper_addwc(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_ADDQ_S_PH: - check_dsp(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* ADDQ_PH */ - gen_helper_addq_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* ADDQ_S_PH */ - gen_helper_addq_s_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_ADDQH_R_PH: - check_dsp_r2(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* ADDQH_PH */ - gen_helper_addqh_ph(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* ADDQH_R_PH */ - gen_helper_addqh_r_ph(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_ADDQH_R_W: - check_dsp_r2(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* ADDQH_W */ - gen_helper_addqh_w(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* ADDQH_R_W */ - gen_helper_addqh_r_w(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_ADDU_S_QB: - check_dsp(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* ADDU_QB */ - gen_helper_addu_qb(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* ADDU_S_QB */ - gen_helper_addu_s_qb(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_ADDU_S_PH: - check_dsp_r2(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* ADDU_PH */ - gen_helper_addu_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* ADDU_S_PH */ - gen_helper_addu_s_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_ADDUH_R_QB: - check_dsp_r2(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* ADDUH_QB */ - gen_helper_adduh_qb(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* ADDUH_R_QB */ - gen_helper_adduh_r_qb(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_SHRAV_R_PH: - check_dsp(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* SHRAV_PH */ - gen_helper_shra_ph(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* SHRAV_R_PH */ - gen_helper_shra_r_ph(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_SHRAV_R_QB: - check_dsp_r2(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* SHRAV_QB */ - gen_helper_shra_qb(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* SHRAV_R_QB */ - gen_helper_shra_r_qb(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_SUBQ_S_PH: - check_dsp(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* SUBQ_PH */ - gen_helper_subq_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* SUBQ_S_PH */ - gen_helper_subq_s_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_SUBQH_R_PH: - check_dsp_r2(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* SUBQH_PH */ - gen_helper_subqh_ph(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* SUBQH_R_PH */ - gen_helper_subqh_r_ph(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_SUBQH_R_W: - check_dsp_r2(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* SUBQH_W */ - gen_helper_subqh_w(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* SUBQH_R_W */ - gen_helper_subqh_r_w(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_SUBU_S_QB: - check_dsp(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* SUBU_QB */ - gen_helper_subu_qb(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* SUBU_S_QB */ - gen_helper_subu_s_qb(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_SUBU_S_PH: - check_dsp_r2(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* SUBU_PH */ - gen_helper_subu_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* SUBU_S_PH */ - gen_helper_subu_s_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_SUBUH_R_QB: - check_dsp_r2(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* SUBUH_QB */ - gen_helper_subuh_qb(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* SUBUH_R_QB */ - gen_helper_subuh_r_qb(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_SHLLV_S_PH: - check_dsp(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* SHLLV_PH */ - gen_helper_shll_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* SHLLV_S_PH */ - gen_helper_shll_s_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_PRECR_SRA_R_PH_W: - check_dsp_r2(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* PRECR_SRA_PH_W */ - { - TCGv_i32 sa_t = tcg_const_i32(rd); - gen_helper_precr_sra_ph_w(v1_t, sa_t, v1_t, - cpu_gpr[rt]); - gen_store_gpr(v1_t, rt); - tcg_temp_free_i32(sa_t); - } - break; - case 1: - /* PRECR_SRA_R_PH_W */ - { - TCGv_i32 sa_t = tcg_const_i32(rd); - gen_helper_precr_sra_r_ph_w(v1_t, sa_t, v1_t, - cpu_gpr[rt]); - gen_store_gpr(v1_t, rt); - tcg_temp_free_i32(sa_t); - } - break; - } - break; - case NM_MULEU_S_PH_QBL: - check_dsp(ctx); - gen_helper_muleu_s_ph_qbl(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_MULEU_S_PH_QBR: - check_dsp(ctx); - gen_helper_muleu_s_ph_qbr(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_MULQ_RS_PH: - check_dsp(ctx); - gen_helper_mulq_rs_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_MULQ_S_PH: - check_dsp_r2(ctx); - gen_helper_mulq_s_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_MULQ_RS_W: - check_dsp_r2(ctx); - gen_helper_mulq_rs_w(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_MULQ_S_W: - check_dsp_r2(ctx); - gen_helper_mulq_s_w(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_APPEND: - check_dsp_r2(ctx); - gen_load_gpr(t0, rs); - if (rd != 0) { - tcg_gen_deposit_tl(cpu_gpr[rt], t0, cpu_gpr[rt], rd, 32 - rd); - } - tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); - break; - case NM_MODSUB: - check_dsp(ctx); - gen_helper_modsub(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case NM_SHRAV_R_W: - check_dsp(ctx); - gen_helper_shra_r_w(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case NM_SHRLV_PH: - check_dsp_r2(ctx); - gen_helper_shrl_ph(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case NM_SHRLV_QB: - check_dsp(ctx); - gen_helper_shrl_qb(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case NM_SHLLV_QB: - check_dsp(ctx); - gen_helper_shll_qb(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_SHLLV_S_W: - check_dsp(ctx); - gen_helper_shll_s_w(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_SHILO: - check_dsp(ctx); - { - TCGv tv0 = tcg_temp_new(); - TCGv tv1 = tcg_temp_new(); - int16_t imm = extract32(ctx->opcode, 16, 7); - - tcg_gen_movi_tl(tv0, rd >> 3); - tcg_gen_movi_tl(tv1, imm); - gen_helper_shilo(tv0, tv1, cpu_env); - tcg_temp_free(tv1); - tcg_temp_free(tv0); - } - break; - case NM_MULEQ_S_W_PHL: - check_dsp(ctx); - gen_helper_muleq_s_w_phl(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_MULEQ_S_W_PHR: - check_dsp(ctx); - gen_helper_muleq_s_w_phr(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_MUL_S_PH: - check_dsp_r2(ctx); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* MUL_PH */ - gen_helper_mul_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case 1: - /* MUL_S_PH */ - gen_helper_mul_s_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - } - break; - case NM_PRECR_QB_PH: - check_dsp_r2(ctx); - gen_helper_precr_qb_ph(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case NM_PRECRQ_QB_PH: - check_dsp(ctx); - gen_helper_precrq_qb_ph(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case NM_PRECRQ_PH_W: - check_dsp(ctx); - gen_helper_precrq_ph_w(v1_t, v1_t, v2_t); - gen_store_gpr(v1_t, ret); - break; - case NM_PRECRQ_RS_PH_W: - check_dsp(ctx); - gen_helper_precrq_rs_ph_w(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_PRECRQU_S_QB_PH: - check_dsp(ctx); - gen_helper_precrqu_s_qb_ph(v1_t, v1_t, v2_t, cpu_env); - gen_store_gpr(v1_t, ret); - break; - case NM_SHRA_R_W: - check_dsp(ctx); - tcg_gen_movi_tl(t0, rd); - gen_helper_shra_r_w(v1_t, t0, v1_t); - gen_store_gpr(v1_t, rt); - break; - case NM_SHRA_R_PH: - check_dsp(ctx); - tcg_gen_movi_tl(t0, rd >> 1); - switch (extract32(ctx->opcode, 10, 1)) { - case 0: - /* SHRA_PH */ - gen_helper_shra_ph(v1_t, t0, v1_t); - gen_store_gpr(v1_t, rt); - break; - case 1: - /* SHRA_R_PH */ - gen_helper_shra_r_ph(v1_t, t0, v1_t); - gen_store_gpr(v1_t, rt); - break; - } - break; - case NM_SHLL_S_PH: - check_dsp(ctx); - tcg_gen_movi_tl(t0, rd >> 1); - switch (extract32(ctx->opcode, 10, 2)) { - case 0: - /* SHLL_PH */ - gen_helper_shll_ph(v1_t, t0, v1_t, cpu_env); - gen_store_gpr(v1_t, rt); - break; - case 2: - /* SHLL_S_PH */ - gen_helper_shll_s_ph(v1_t, t0, v1_t, cpu_env); - gen_store_gpr(v1_t, rt); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_SHLL_S_W: - check_dsp(ctx); - tcg_gen_movi_tl(t0, rd); - gen_helper_shll_s_w(v1_t, t0, v1_t, cpu_env); - gen_store_gpr(v1_t, rt); - break; - case NM_REPL_PH: - check_dsp(ctx); - { - int16_t imm; - imm = sextract32(ctx->opcode, 11, 11); - imm = (int16_t)(imm << 6) >> 6; - if (rt != 0) { - tcg_gen_movi_tl(cpu_gpr[rt], dup_const(MO_16, imm)); - } - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - - tcg_temp_free(v2_t); - tcg_temp_free(v1_t); - tcg_temp_free(t0); -} - -static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) -{ - uint16_t insn; - uint32_t op; - int rt, rs, rd; - int offset; - int imm; - - insn = translator_lduw(env, ctx->base.pc_next + 2); - ctx->opcode = (ctx->opcode << 16) | insn; - - rt = extract32(ctx->opcode, 21, 5); - rs = extract32(ctx->opcode, 16, 5); - rd = extract32(ctx->opcode, 11, 5); - - op = extract32(ctx->opcode, 26, 6); - switch (op) { - case NM_P_ADDIU: - if (rt == 0) { - /* P.RI */ - switch (extract32(ctx->opcode, 19, 2)) { - case NM_SIGRIE: - default: - gen_reserved_instruction(ctx); - break; - case NM_P_SYSCALL: - if ((extract32(ctx->opcode, 18, 1)) == NM_SYSCALL) { - generate_exception_end(ctx, EXCP_SYSCALL); - } else { - gen_reserved_instruction(ctx); - } - break; - case NM_BREAK: - generate_exception_end(ctx, EXCP_BREAK); - break; - case NM_SDBBP: - if (is_uhi(extract32(ctx->opcode, 0, 19))) { - gen_helper_do_semihosting(cpu_env); - } else { - if (ctx->hflags & MIPS_HFLAG_SBRI) { - gen_reserved_instruction(ctx); - } else { - generate_exception_end(ctx, EXCP_DBp); - } - } - break; - } - } else { - /* NM_ADDIU */ - imm = extract32(ctx->opcode, 0, 16); - if (rs != 0) { - tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rs], imm); - } else { - tcg_gen_movi_tl(cpu_gpr[rt], imm); - } - tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); - } - break; - case NM_ADDIUPC: - if (rt != 0) { - offset = sextract32(ctx->opcode, 0, 1) << 21 | - extract32(ctx->opcode, 1, 20) << 1; - target_long addr = addr_add(ctx, ctx->base.pc_next + 4, offset); - tcg_gen_movi_tl(cpu_gpr[rt], addr); - } - break; - case NM_POOL32A: - switch (ctx->opcode & 0x07) { - case NM_POOL32A0: - gen_pool32a0_nanomips_insn(env, ctx); - break; - case NM_POOL32A5: - { - int32_t op1 = extract32(ctx->opcode, 3, 7); - gen_pool32a5_nanomips_insn(ctx, op1, rd, rs, rt); - } - break; - case NM_POOL32A7: - switch (extract32(ctx->opcode, 3, 3)) { - case NM_P_LSX: - gen_p_lsx(ctx, rd, rs, rt); - break; - case NM_LSA: - /* - * In nanoMIPS, the shift field directly encodes the shift - * amount, meaning that the supported shift values are in - * the range 0 to 3 (instead of 1 to 4 in MIPSR6). - */ - gen_lsa(ctx, rd, rt, rs, extract32(ctx->opcode, 9, 2) - 1); - break; - case NM_EXTW: - gen_ext(ctx, 32, rd, rs, rt, extract32(ctx->opcode, 6, 5)); - break; - case NM_POOL32AXF: - gen_pool32axf_nanomips_insn(env, ctx); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_P_GP_W: - switch (ctx->opcode & 0x03) { - case NM_ADDIUGP_W: - if (rt != 0) { - offset = extract32(ctx->opcode, 0, 21); - gen_op_addr_addi(ctx, cpu_gpr[rt], cpu_gpr[28], offset); - } - break; - case NM_LWGP: - gen_ld(ctx, OPC_LW, rt, 28, extract32(ctx->opcode, 2, 19) << 2); - break; - case NM_SWGP: - gen_st(ctx, OPC_SW, rt, 28, extract32(ctx->opcode, 2, 19) << 2); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_P48I: - { - insn = translator_lduw(env, ctx->base.pc_next + 4); - target_long addr_off = extract32(ctx->opcode, 0, 16) | insn << 16; - switch (extract32(ctx->opcode, 16, 5)) { - case NM_LI48: - check_nms(ctx); - if (rt != 0) { - tcg_gen_movi_tl(cpu_gpr[rt], addr_off); - } - break; - case NM_ADDIU48: - check_nms(ctx); - if (rt != 0) { - tcg_gen_addi_tl(cpu_gpr[rt], cpu_gpr[rt], addr_off); - tcg_gen_ext32s_tl(cpu_gpr[rt], cpu_gpr[rt]); - } - break; - case NM_ADDIUGP48: - check_nms(ctx); - if (rt != 0) { - gen_op_addr_addi(ctx, cpu_gpr[rt], cpu_gpr[28], addr_off); - } - break; - case NM_ADDIUPC48: - check_nms(ctx); - if (rt != 0) { - target_long addr = addr_add(ctx, ctx->base.pc_next + 6, - addr_off); - - tcg_gen_movi_tl(cpu_gpr[rt], addr); - } - break; - case NM_LWPC48: - check_nms(ctx); - if (rt != 0) { - TCGv t0; - t0 = tcg_temp_new(); - - target_long addr = addr_add(ctx, ctx->base.pc_next + 6, - addr_off); - - tcg_gen_movi_tl(t0, addr); - tcg_gen_qemu_ld_tl(cpu_gpr[rt], t0, ctx->mem_idx, MO_TESL); - tcg_temp_free(t0); - } - break; - case NM_SWPC48: - check_nms(ctx); - { - TCGv t0, t1; - t0 = tcg_temp_new(); - t1 = tcg_temp_new(); - - target_long addr = addr_add(ctx, ctx->base.pc_next + 6, - addr_off); - - tcg_gen_movi_tl(t0, addr); - gen_load_gpr(t1, rt); - - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); - - tcg_temp_free(t0); - tcg_temp_free(t1); - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - return 6; - } - case NM_P_U12: - switch (extract32(ctx->opcode, 12, 4)) { - case NM_ORI: - gen_logic_imm(ctx, OPC_ORI, rt, rs, extract32(ctx->opcode, 0, 12)); - break; - case NM_XORI: - gen_logic_imm(ctx, OPC_XORI, rt, rs, extract32(ctx->opcode, 0, 12)); - break; - case NM_ANDI: - gen_logic_imm(ctx, OPC_ANDI, rt, rs, extract32(ctx->opcode, 0, 12)); - break; - case NM_P_SR: - switch (extract32(ctx->opcode, 20, 1)) { - case NM_PP_SR: - switch (ctx->opcode & 3) { - case NM_SAVE: - gen_save(ctx, rt, extract32(ctx->opcode, 16, 4), - extract32(ctx->opcode, 2, 1), - extract32(ctx->opcode, 3, 9) << 3); - break; - case NM_RESTORE: - case NM_RESTORE_JRC: - gen_restore(ctx, rt, extract32(ctx->opcode, 16, 4), - extract32(ctx->opcode, 2, 1), - extract32(ctx->opcode, 3, 9) << 3); - if ((ctx->opcode & 3) == NM_RESTORE_JRC) { - gen_compute_branch_nm(ctx, OPC_JR, 2, 31, 0, 0); - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_P_SR_F: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_SLTI: - gen_slt_imm(ctx, OPC_SLTI, rt, rs, extract32(ctx->opcode, 0, 12)); - break; - case NM_SLTIU: - gen_slt_imm(ctx, OPC_SLTIU, rt, rs, extract32(ctx->opcode, 0, 12)); - break; - case NM_SEQI: - { - TCGv t0 = tcg_temp_new(); - - imm = extract32(ctx->opcode, 0, 12); - gen_load_gpr(t0, rs); - tcg_gen_setcondi_tl(TCG_COND_EQ, t0, t0, imm); - gen_store_gpr(t0, rt); - - tcg_temp_free(t0); - } - break; - case NM_ADDIUNEG: - imm = (int16_t) extract32(ctx->opcode, 0, 12); - gen_arith_imm(ctx, OPC_ADDIU, rt, rs, -imm); - break; - case NM_P_SHIFT: - { - int shift = extract32(ctx->opcode, 0, 5); - switch (extract32(ctx->opcode, 5, 4)) { - case NM_P_SLL: - if (rt == 0 && shift == 0) { - /* NOP */ - } else if (rt == 0 && shift == 3) { - /* EHB - treat as NOP */ - } else if (rt == 0 && shift == 5) { - /* PAUSE - treat as NOP */ - } else if (rt == 0 && shift == 6) { - /* SYNC */ - gen_sync(extract32(ctx->opcode, 16, 5)); - } else { - /* SLL */ - gen_shift_imm(ctx, OPC_SLL, rt, rs, - extract32(ctx->opcode, 0, 5)); - } - break; - case NM_SRL: - gen_shift_imm(ctx, OPC_SRL, rt, rs, - extract32(ctx->opcode, 0, 5)); - break; - case NM_SRA: - gen_shift_imm(ctx, OPC_SRA, rt, rs, - extract32(ctx->opcode, 0, 5)); - break; - case NM_ROTR: - gen_shift_imm(ctx, OPC_ROTR, rt, rs, - extract32(ctx->opcode, 0, 5)); - break; - } - } - break; - case NM_P_ROTX: - check_nms(ctx); - if (rt != 0) { - TCGv t0 = tcg_temp_new(); - TCGv_i32 shift = tcg_const_i32(extract32(ctx->opcode, 0, 5)); - TCGv_i32 shiftx = tcg_const_i32(extract32(ctx->opcode, 7, 4) - << 1); - TCGv_i32 stripe = tcg_const_i32(extract32(ctx->opcode, 6, 1)); - - gen_load_gpr(t0, rs); - gen_helper_rotx(cpu_gpr[rt], t0, shift, shiftx, stripe); - tcg_temp_free(t0); - - tcg_temp_free_i32(shift); - tcg_temp_free_i32(shiftx); - tcg_temp_free_i32(stripe); - } - break; - case NM_P_INS: - switch (((ctx->opcode >> 10) & 2) | - (extract32(ctx->opcode, 5, 1))) { - case NM_INS: - check_nms(ctx); - gen_bitops(ctx, OPC_INS, rt, rs, extract32(ctx->opcode, 0, 5), - extract32(ctx->opcode, 6, 5)); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_P_EXT: - switch (((ctx->opcode >> 10) & 2) | - (extract32(ctx->opcode, 5, 1))) { - case NM_EXT: - check_nms(ctx); - gen_bitops(ctx, OPC_EXT, rt, rs, extract32(ctx->opcode, 0, 5), - extract32(ctx->opcode, 6, 5)); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_POOL32F: - gen_pool32f_nanomips_insn(ctx); - break; - case NM_POOL32S: - break; - case NM_P_LUI: - switch (extract32(ctx->opcode, 1, 1)) { - case NM_LUI: - if (rt != 0) { - tcg_gen_movi_tl(cpu_gpr[rt], - sextract32(ctx->opcode, 0, 1) << 31 | - extract32(ctx->opcode, 2, 10) << 21 | - extract32(ctx->opcode, 12, 9) << 12); - } - break; - case NM_ALUIPC: - if (rt != 0) { - offset = sextract32(ctx->opcode, 0, 1) << 31 | - extract32(ctx->opcode, 2, 10) << 21 | - extract32(ctx->opcode, 12, 9) << 12; - target_long addr; - addr = ~0xFFF & addr_add(ctx, ctx->base.pc_next + 4, offset); - tcg_gen_movi_tl(cpu_gpr[rt], addr); - } - break; - } - break; - case NM_P_GP_BH: - { - uint32_t u = extract32(ctx->opcode, 0, 18); - - switch (extract32(ctx->opcode, 18, 3)) { - case NM_LBGP: - gen_ld(ctx, OPC_LB, rt, 28, u); - break; - case NM_SBGP: - gen_st(ctx, OPC_SB, rt, 28, u); - break; - case NM_LBUGP: - gen_ld(ctx, OPC_LBU, rt, 28, u); - break; - case NM_ADDIUGP_B: - if (rt != 0) { - gen_op_addr_addi(ctx, cpu_gpr[rt], cpu_gpr[28], u); - } - break; - case NM_P_GP_LH: - u &= ~1; - switch (ctx->opcode & 1) { - case NM_LHGP: - gen_ld(ctx, OPC_LH, rt, 28, u); - break; - case NM_LHUGP: - gen_ld(ctx, OPC_LHU, rt, 28, u); - break; - } - break; - case NM_P_GP_SH: - u &= ~1; - switch (ctx->opcode & 1) { - case NM_SHGP: - gen_st(ctx, OPC_SH, rt, 28, u); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_P_GP_CP1: - u &= ~0x3; - switch (ctx->opcode & 0x3) { - case NM_LWC1GP: - gen_cop1_ldst(ctx, OPC_LWC1, rt, 28, u); - break; - case NM_LDC1GP: - gen_cop1_ldst(ctx, OPC_LDC1, rt, 28, u); - break; - case NM_SWC1GP: - gen_cop1_ldst(ctx, OPC_SWC1, rt, 28, u); - break; - case NM_SDC1GP: - gen_cop1_ldst(ctx, OPC_SDC1, rt, 28, u); - break; - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - } - break; - case NM_P_LS_U12: - { - uint32_t u = extract32(ctx->opcode, 0, 12); - - switch (extract32(ctx->opcode, 12, 4)) { - case NM_P_PREFU12: - if (rt == 31) { - /* SYNCI */ - /* - * Break the TB to be able to sync copied instructions - * immediately. - */ - ctx->base.is_jmp = DISAS_STOP; - } else { - /* PREF */ - /* Treat as NOP. */ - } - break; - case NM_LB: - gen_ld(ctx, OPC_LB, rt, rs, u); - break; - case NM_LH: - gen_ld(ctx, OPC_LH, rt, rs, u); - break; - case NM_LW: - gen_ld(ctx, OPC_LW, rt, rs, u); - break; - case NM_LBU: - gen_ld(ctx, OPC_LBU, rt, rs, u); - break; - case NM_LHU: - gen_ld(ctx, OPC_LHU, rt, rs, u); - break; - case NM_SB: - gen_st(ctx, OPC_SB, rt, rs, u); - break; - case NM_SH: - gen_st(ctx, OPC_SH, rt, rs, u); - break; - case NM_SW: - gen_st(ctx, OPC_SW, rt, rs, u); - break; - case NM_LWC1: - gen_cop1_ldst(ctx, OPC_LWC1, rt, rs, u); - break; - case NM_LDC1: - gen_cop1_ldst(ctx, OPC_LDC1, rt, rs, u); - break; - case NM_SWC1: - gen_cop1_ldst(ctx, OPC_SWC1, rt, rs, u); - break; - case NM_SDC1: - gen_cop1_ldst(ctx, OPC_SDC1, rt, rs, u); - break; - default: - gen_reserved_instruction(ctx); - break; - } - } - break; - case NM_P_LS_S9: - { - int32_t s = (sextract32(ctx->opcode, 15, 1) << 8) | - extract32(ctx->opcode, 0, 8); - - switch (extract32(ctx->opcode, 8, 3)) { - case NM_P_LS_S0: - switch (extract32(ctx->opcode, 11, 4)) { - case NM_LBS9: - gen_ld(ctx, OPC_LB, rt, rs, s); - break; - case NM_LHS9: - gen_ld(ctx, OPC_LH, rt, rs, s); - break; - case NM_LWS9: - gen_ld(ctx, OPC_LW, rt, rs, s); - break; - case NM_LBUS9: - gen_ld(ctx, OPC_LBU, rt, rs, s); - break; - case NM_LHUS9: - gen_ld(ctx, OPC_LHU, rt, rs, s); - break; - case NM_SBS9: - gen_st(ctx, OPC_SB, rt, rs, s); - break; - case NM_SHS9: - gen_st(ctx, OPC_SH, rt, rs, s); - break; - case NM_SWS9: - gen_st(ctx, OPC_SW, rt, rs, s); - break; - case NM_LWC1S9: - gen_cop1_ldst(ctx, OPC_LWC1, rt, rs, s); - break; - case NM_LDC1S9: - gen_cop1_ldst(ctx, OPC_LDC1, rt, rs, s); - break; - case NM_SWC1S9: - gen_cop1_ldst(ctx, OPC_SWC1, rt, rs, s); - break; - case NM_SDC1S9: - gen_cop1_ldst(ctx, OPC_SDC1, rt, rs, s); - break; - case NM_P_PREFS9: - if (rt == 31) { - /* SYNCI */ - /* - * Break the TB to be able to sync copied instructions - * immediately. - */ - ctx->base.is_jmp = DISAS_STOP; - } else { - /* PREF */ - /* Treat as NOP. */ - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_P_LS_S1: - switch (extract32(ctx->opcode, 11, 4)) { - case NM_UALH: - case NM_UASH: - check_nms(ctx); - { - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - - gen_base_offset_addr(ctx, t0, rs, s); - - switch (extract32(ctx->opcode, 11, 4)) { - case NM_UALH: - tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW | - MO_UNALN); - gen_store_gpr(t0, rt); - break; - case NM_UASH: - gen_load_gpr(t1, rt); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW | - MO_UNALN); - break; - } - tcg_temp_free(t0); - tcg_temp_free(t1); - } - break; - case NM_P_LL: - switch (ctx->opcode & 0x03) { - case NM_LL: - gen_ld(ctx, OPC_LL, rt, rs, s); - break; - case NM_LLWP: - check_xnp(ctx); - gen_llwp(ctx, rs, 0, rt, extract32(ctx->opcode, 3, 5)); - break; - } - break; - case NM_P_SC: - switch (ctx->opcode & 0x03) { - case NM_SC: - gen_st_cond(ctx, rt, rs, s, MO_TESL, false); - break; - case NM_SCWP: - check_xnp(ctx); - gen_scwp(ctx, rs, 0, rt, extract32(ctx->opcode, 3, 5), - false); - break; - } - break; - case NM_CACHE: - check_cp0_enabled(ctx); - if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) { - gen_cache_operation(ctx, rt, rs, s); - } - break; - } - break; - case NM_P_LS_E0: - switch (extract32(ctx->opcode, 11, 4)) { - case NM_LBE: - check_eva(ctx); - check_cp0_enabled(ctx); - gen_ld(ctx, OPC_LBE, rt, rs, s); - break; - case NM_SBE: - check_eva(ctx); - check_cp0_enabled(ctx); - gen_st(ctx, OPC_SBE, rt, rs, s); - break; - case NM_LBUE: - check_eva(ctx); - check_cp0_enabled(ctx); - gen_ld(ctx, OPC_LBUE, rt, rs, s); - break; - case NM_P_PREFE: - if (rt == 31) { - /* case NM_SYNCIE */ - check_eva(ctx); - check_cp0_enabled(ctx); - /* - * Break the TB to be able to sync copied instructions - * immediately. - */ - ctx->base.is_jmp = DISAS_STOP; - } else { - /* case NM_PREFE */ - check_eva(ctx); - check_cp0_enabled(ctx); - /* Treat as NOP. */ - } - break; - case NM_LHE: - check_eva(ctx); - check_cp0_enabled(ctx); - gen_ld(ctx, OPC_LHE, rt, rs, s); - break; - case NM_SHE: - check_eva(ctx); - check_cp0_enabled(ctx); - gen_st(ctx, OPC_SHE, rt, rs, s); - break; - case NM_LHUE: - check_eva(ctx); - check_cp0_enabled(ctx); - gen_ld(ctx, OPC_LHUE, rt, rs, s); - break; - case NM_CACHEE: - check_eva(ctx); - check_cp0_enabled(ctx); - check_nms_dl_il_sl_tl_l2c(ctx); - gen_cache_operation(ctx, rt, rs, s); - break; - case NM_LWE: - check_eva(ctx); - check_cp0_enabled(ctx); - gen_ld(ctx, OPC_LWE, rt, rs, s); - break; - case NM_SWE: - check_eva(ctx); - check_cp0_enabled(ctx); - gen_st(ctx, OPC_SWE, rt, rs, s); - break; - case NM_P_LLE: - switch (extract32(ctx->opcode, 2, 2)) { - case NM_LLE: - check_xnp(ctx); - check_eva(ctx); - check_cp0_enabled(ctx); - gen_ld(ctx, OPC_LLE, rt, rs, s); - break; - case NM_LLWPE: - check_xnp(ctx); - check_eva(ctx); - check_cp0_enabled(ctx); - gen_llwp(ctx, rs, 0, rt, extract32(ctx->opcode, 3, 5)); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_P_SCE: - switch (extract32(ctx->opcode, 2, 2)) { - case NM_SCE: - check_xnp(ctx); - check_eva(ctx); - check_cp0_enabled(ctx); - gen_st_cond(ctx, rt, rs, s, MO_TESL, true); - break; - case NM_SCWPE: - check_xnp(ctx); - check_eva(ctx); - check_cp0_enabled(ctx); - gen_scwp(ctx, rs, 0, rt, extract32(ctx->opcode, 3, 5), - true); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - } - break; - case NM_P_LS_WM: - case NM_P_LS_UAWM: - check_nms(ctx); - { - int count = extract32(ctx->opcode, 12, 3); - int counter = 0; - - offset = sextract32(ctx->opcode, 15, 1) << 8 | - extract32(ctx->opcode, 0, 8); - TCGv va = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - MemOp memop = (extract32(ctx->opcode, 8, 3)) == - NM_P_LS_UAWM ? MO_UNALN : 0; - - count = (count == 0) ? 8 : count; - while (counter != count) { - int this_rt = ((rt + counter) & 0x1f) | (rt & 0x10); - int this_offset = offset + (counter << 2); - - gen_base_offset_addr(ctx, va, rs, this_offset); - - switch (extract32(ctx->opcode, 11, 1)) { - case NM_LWM: - tcg_gen_qemu_ld_tl(t1, va, ctx->mem_idx, - memop | MO_TESL); - gen_store_gpr(t1, this_rt); - if ((this_rt == rs) && - (counter != (count - 1))) { - /* UNPREDICTABLE */ - } - break; - case NM_SWM: - this_rt = (rt == 0) ? 0 : this_rt; - gen_load_gpr(t1, this_rt); - tcg_gen_qemu_st_tl(t1, va, ctx->mem_idx, - memop | MO_TEUL); - break; - } - counter++; - } - tcg_temp_free(va); - tcg_temp_free(t1); - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - } - break; - case NM_MOVE_BALC: - check_nms(ctx); - { - TCGv t0 = tcg_temp_new(); - int32_t s = sextract32(ctx->opcode, 0, 1) << 21 | - extract32(ctx->opcode, 1, 20) << 1; - rd = (extract32(ctx->opcode, 24, 1)) == 0 ? 4 : 5; - rt = decode_gpr_gpr4_zero(extract32(ctx->opcode, 25, 1) << 3 | - extract32(ctx->opcode, 21, 3)); - gen_load_gpr(t0, rt); - tcg_gen_mov_tl(cpu_gpr[rd], t0); - gen_compute_branch_nm(ctx, OPC_BGEZAL, 4, 0, 0, s); - tcg_temp_free(t0); - } - break; - case NM_P_BAL: - { - int32_t s = sextract32(ctx->opcode, 0, 1) << 25 | - extract32(ctx->opcode, 1, 24) << 1; - - if ((extract32(ctx->opcode, 25, 1)) == 0) { - /* BC */ - gen_compute_branch_nm(ctx, OPC_BEQ, 4, 0, 0, s); - } else { - /* BALC */ - gen_compute_branch_nm(ctx, OPC_BGEZAL, 4, 0, 0, s); - } - } - break; - case NM_P_J: - switch (extract32(ctx->opcode, 12, 4)) { - case NM_JALRC: - case NM_JALRC_HB: - gen_compute_branch_nm(ctx, OPC_JALR, 4, rs, rt, 0); - break; - case NM_P_BALRSC: - gen_compute_nanomips_pbalrsc_branch(ctx, rs, rt); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_P_BR1: - { - int32_t s = sextract32(ctx->opcode, 0, 1) << 14 | - extract32(ctx->opcode, 1, 13) << 1; - switch (extract32(ctx->opcode, 14, 2)) { - case NM_BEQC: - check_nms(ctx); - gen_compute_branch_nm(ctx, OPC_BEQ, 4, rs, rt, s); - break; - case NM_P_BR3A: - s = sextract32(ctx->opcode, 0, 1) << 14 | - extract32(ctx->opcode, 1, 13) << 1; - check_cp1_enabled(ctx); - switch (extract32(ctx->opcode, 16, 5)) { - case NM_BC1EQZC: - gen_compute_branch_cp1_nm(ctx, OPC_BC1EQZ, rt, s); - break; - case NM_BC1NEZC: - gen_compute_branch_cp1_nm(ctx, OPC_BC1NEZ, rt, s); - break; - case NM_BPOSGE32C: - check_dsp_r3(ctx); - { - int32_t imm = extract32(ctx->opcode, 1, 13) | - extract32(ctx->opcode, 0, 1) << 13; - - gen_compute_branch_nm(ctx, OPC_BPOSGE32, 4, -1, -2, - imm << 1); - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_BGEC: - if (rs == rt) { - gen_compute_compact_branch_nm(ctx, OPC_BC, rs, rt, s); - } else { - gen_compute_compact_branch_nm(ctx, OPC_BGEC, rs, rt, s); - } - break; - case NM_BGEUC: - if (rs == rt || rt == 0) { - gen_compute_compact_branch_nm(ctx, OPC_BC, 0, 0, s); - } else if (rs == 0) { - gen_compute_compact_branch_nm(ctx, OPC_BEQZC, rt, 0, s); - } else { - gen_compute_compact_branch_nm(ctx, OPC_BGEUC, rs, rt, s); - } - break; - } - } - break; - case NM_P_BR2: - { - int32_t s = sextract32(ctx->opcode, 0, 1) << 14 | - extract32(ctx->opcode, 1, 13) << 1; - switch (extract32(ctx->opcode, 14, 2)) { - case NM_BNEC: - check_nms(ctx); - gen_compute_branch_nm(ctx, OPC_BNE, 4, rs, rt, s); - break; - case NM_BLTC: - if (rs != 0 && rt != 0 && rs == rt) { - /* NOP */ - ctx->hflags |= MIPS_HFLAG_FBNSLOT; - } else { - gen_compute_compact_branch_nm(ctx, OPC_BLTC, rs, rt, s); - } - break; - case NM_BLTUC: - if (rs == 0 || rs == rt) { - /* NOP */ - ctx->hflags |= MIPS_HFLAG_FBNSLOT; - } else { - gen_compute_compact_branch_nm(ctx, OPC_BLTUC, rs, rt, s); - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - } - break; - case NM_P_BRI: - { - int32_t s = sextract32(ctx->opcode, 0, 1) << 11 | - extract32(ctx->opcode, 1, 10) << 1; - uint32_t u = extract32(ctx->opcode, 11, 7); - - gen_compute_imm_branch(ctx, extract32(ctx->opcode, 18, 3), - rt, u, s); - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - return 4; -} - -static int decode_nanomips_opc(CPUMIPSState *env, DisasContext *ctx) -{ - uint32_t op; - int rt = decode_gpr_gpr3(NANOMIPS_EXTRACT_RT3(ctx->opcode)); - int rs = decode_gpr_gpr3(NANOMIPS_EXTRACT_RS3(ctx->opcode)); - int rd = decode_gpr_gpr3(NANOMIPS_EXTRACT_RD3(ctx->opcode)); - int offset; - int imm; - - /* make sure instructions are on a halfword boundary */ - if (ctx->base.pc_next & 0x1) { - TCGv tmp = tcg_const_tl(ctx->base.pc_next); - tcg_gen_st_tl(tmp, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr)); - tcg_temp_free(tmp); - generate_exception_end(ctx, EXCP_AdEL); - return 2; - } - - op = extract32(ctx->opcode, 10, 6); - switch (op) { - case NM_P16_MV: - rt = NANOMIPS_EXTRACT_RD5(ctx->opcode); - if (rt != 0) { - /* MOVE */ - rs = NANOMIPS_EXTRACT_RS5(ctx->opcode); - gen_arith(ctx, OPC_ADDU, rt, rs, 0); - } else { - /* P16.RI */ - switch (extract32(ctx->opcode, 3, 2)) { - case NM_P16_SYSCALL: - if (extract32(ctx->opcode, 2, 1) == 0) { - generate_exception_end(ctx, EXCP_SYSCALL); - } else { - gen_reserved_instruction(ctx); - } - break; - case NM_BREAK16: - generate_exception_end(ctx, EXCP_BREAK); - break; - case NM_SDBBP16: - if (is_uhi(extract32(ctx->opcode, 0, 3))) { - gen_helper_do_semihosting(cpu_env); - } else { - if (ctx->hflags & MIPS_HFLAG_SBRI) { - gen_reserved_instruction(ctx); - } else { - generate_exception_end(ctx, EXCP_DBp); - } - } - break; - default: - gen_reserved_instruction(ctx); - break; - } - } - break; - case NM_P16_SHIFT: - { - int shift = extract32(ctx->opcode, 0, 3); - uint32_t opc = 0; - shift = (shift == 0) ? 8 : shift; - - switch (extract32(ctx->opcode, 3, 1)) { - case NM_SLL16: - opc = OPC_SLL; - break; - case NM_SRL16: - opc = OPC_SRL; - break; - } - gen_shift_imm(ctx, opc, rt, rs, shift); - } - break; - case NM_P16C: - switch (ctx->opcode & 1) { - case NM_POOL16C_0: - gen_pool16c_nanomips_insn(ctx); - break; - case NM_LWXS16: - gen_ldxs(ctx, rt, rs, rd); - break; - } - break; - case NM_P16_A1: - switch (extract32(ctx->opcode, 6, 1)) { - case NM_ADDIUR1SP: - imm = extract32(ctx->opcode, 0, 6) << 2; - gen_arith_imm(ctx, OPC_ADDIU, rt, 29, imm); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_P16_A2: - switch (extract32(ctx->opcode, 3, 1)) { - case NM_ADDIUR2: - imm = extract32(ctx->opcode, 0, 3) << 2; - gen_arith_imm(ctx, OPC_ADDIU, rt, rs, imm); - break; - case NM_P_ADDIURS5: - rt = extract32(ctx->opcode, 5, 5); - if (rt != 0) { - /* imm = sign_extend(s[3] . s[2:0] , from_nbits = 4) */ - imm = (sextract32(ctx->opcode, 4, 1) << 3) | - (extract32(ctx->opcode, 0, 3)); - gen_arith_imm(ctx, OPC_ADDIU, rt, rt, imm); - } - break; - } - break; - case NM_P16_ADDU: - switch (ctx->opcode & 0x1) { - case NM_ADDU16: - gen_arith(ctx, OPC_ADDU, rd, rs, rt); - break; - case NM_SUBU16: - gen_arith(ctx, OPC_SUBU, rd, rs, rt); - break; - } - break; - case NM_P16_4X4: - rt = (extract32(ctx->opcode, 9, 1) << 3) | - extract32(ctx->opcode, 5, 3); - rs = (extract32(ctx->opcode, 4, 1) << 3) | - extract32(ctx->opcode, 0, 3); - rt = decode_gpr_gpr4(rt); - rs = decode_gpr_gpr4(rs); - switch ((extract32(ctx->opcode, 7, 2) & 0x2) | - (extract32(ctx->opcode, 3, 1))) { - case NM_ADDU4X4: - check_nms(ctx); - gen_arith(ctx, OPC_ADDU, rt, rs, rt); - break; - case NM_MUL4X4: - check_nms(ctx); - gen_r6_muldiv(ctx, R6_OPC_MUL, rt, rs, rt); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_LI16: - { - int imm = extract32(ctx->opcode, 0, 7); - imm = (imm == 0x7f ? -1 : imm); - if (rt != 0) { - tcg_gen_movi_tl(cpu_gpr[rt], imm); - } - } - break; - case NM_ANDI16: - { - uint32_t u = extract32(ctx->opcode, 0, 4); - u = (u == 12) ? 0xff : - (u == 13) ? 0xffff : u; - gen_logic_imm(ctx, OPC_ANDI, rt, rs, u); - } - break; - case NM_P16_LB: - offset = extract32(ctx->opcode, 0, 2); - switch (extract32(ctx->opcode, 2, 2)) { - case NM_LB16: - gen_ld(ctx, OPC_LB, rt, rs, offset); - break; - case NM_SB16: - rt = decode_gpr_gpr3_src_store( - NANOMIPS_EXTRACT_RT3(ctx->opcode)); - gen_st(ctx, OPC_SB, rt, rs, offset); - break; - case NM_LBU16: - gen_ld(ctx, OPC_LBU, rt, rs, offset); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_P16_LH: - offset = extract32(ctx->opcode, 1, 2) << 1; - switch ((extract32(ctx->opcode, 3, 1) << 1) | (ctx->opcode & 1)) { - case NM_LH16: - gen_ld(ctx, OPC_LH, rt, rs, offset); - break; - case NM_SH16: - rt = decode_gpr_gpr3_src_store( - NANOMIPS_EXTRACT_RT3(ctx->opcode)); - gen_st(ctx, OPC_SH, rt, rs, offset); - break; - case NM_LHU16: - gen_ld(ctx, OPC_LHU, rt, rs, offset); - break; - default: - gen_reserved_instruction(ctx); - break; - } - break; - case NM_LW16: - offset = extract32(ctx->opcode, 0, 4) << 2; - gen_ld(ctx, OPC_LW, rt, rs, offset); - break; - case NM_LWSP16: - rt = NANOMIPS_EXTRACT_RD5(ctx->opcode); - offset = extract32(ctx->opcode, 0, 5) << 2; - gen_ld(ctx, OPC_LW, rt, 29, offset); - break; - case NM_LW4X4: - check_nms(ctx); - rt = (extract32(ctx->opcode, 9, 1) << 3) | - extract32(ctx->opcode, 5, 3); - rs = (extract32(ctx->opcode, 4, 1) << 3) | - extract32(ctx->opcode, 0, 3); - offset = (extract32(ctx->opcode, 3, 1) << 3) | - (extract32(ctx->opcode, 8, 1) << 2); - rt = decode_gpr_gpr4(rt); - rs = decode_gpr_gpr4(rs); - gen_ld(ctx, OPC_LW, rt, rs, offset); - break; - case NM_SW4X4: - check_nms(ctx); - rt = (extract32(ctx->opcode, 9, 1) << 3) | - extract32(ctx->opcode, 5, 3); - rs = (extract32(ctx->opcode, 4, 1) << 3) | - extract32(ctx->opcode, 0, 3); - offset = (extract32(ctx->opcode, 3, 1) << 3) | - (extract32(ctx->opcode, 8, 1) << 2); - rt = decode_gpr_gpr4_zero(rt); - rs = decode_gpr_gpr4(rs); - gen_st(ctx, OPC_SW, rt, rs, offset); - break; - case NM_LWGP16: - offset = extract32(ctx->opcode, 0, 7) << 2; - gen_ld(ctx, OPC_LW, rt, 28, offset); - break; - case NM_SWSP16: - rt = NANOMIPS_EXTRACT_RD5(ctx->opcode); - offset = extract32(ctx->opcode, 0, 5) << 2; - gen_st(ctx, OPC_SW, rt, 29, offset); - break; - case NM_SW16: - rt = decode_gpr_gpr3_src_store( - NANOMIPS_EXTRACT_RT3(ctx->opcode)); - rs = decode_gpr_gpr3(NANOMIPS_EXTRACT_RS3(ctx->opcode)); - offset = extract32(ctx->opcode, 0, 4) << 2; - gen_st(ctx, OPC_SW, rt, rs, offset); - break; - case NM_SWGP16: - rt = decode_gpr_gpr3_src_store( - NANOMIPS_EXTRACT_RT3(ctx->opcode)); - offset = extract32(ctx->opcode, 0, 7) << 2; - gen_st(ctx, OPC_SW, rt, 28, offset); - break; - case NM_BC16: - gen_compute_branch_nm(ctx, OPC_BEQ, 2, 0, 0, - (sextract32(ctx->opcode, 0, 1) << 10) | - (extract32(ctx->opcode, 1, 9) << 1)); - break; - case NM_BALC16: - gen_compute_branch_nm(ctx, OPC_BGEZAL, 2, 0, 0, - (sextract32(ctx->opcode, 0, 1) << 10) | - (extract32(ctx->opcode, 1, 9) << 1)); - break; - case NM_BEQZC16: - gen_compute_branch_nm(ctx, OPC_BEQ, 2, rt, 0, - (sextract32(ctx->opcode, 0, 1) << 7) | - (extract32(ctx->opcode, 1, 6) << 1)); - break; - case NM_BNEZC16: - gen_compute_branch_nm(ctx, OPC_BNE, 2, rt, 0, - (sextract32(ctx->opcode, 0, 1) << 7) | - (extract32(ctx->opcode, 1, 6) << 1)); - break; - case NM_P16_BR: - switch (ctx->opcode & 0xf) { - case 0: - /* P16.JRC */ - switch (extract32(ctx->opcode, 4, 1)) { - case NM_JRC: - gen_compute_branch_nm(ctx, OPC_JR, 2, - extract32(ctx->opcode, 5, 5), 0, 0); - break; - case NM_JALRC16: - gen_compute_branch_nm(ctx, OPC_JALR, 2, - extract32(ctx->opcode, 5, 5), 31, 0); - break; - } - break; - default: - { - /* P16.BRI */ - uint32_t opc = extract32(ctx->opcode, 4, 3) < - extract32(ctx->opcode, 7, 3) ? OPC_BEQ : OPC_BNE; - gen_compute_branch_nm(ctx, opc, 2, rs, rt, - extract32(ctx->opcode, 0, 4) << 1); - } - break; - } - break; - case NM_P16_SR: - { - int count = extract32(ctx->opcode, 0, 4); - int u = extract32(ctx->opcode, 4, 4) << 4; - - rt = 30 + extract32(ctx->opcode, 9, 1); - switch (extract32(ctx->opcode, 8, 1)) { - case NM_SAVE16: - gen_save(ctx, rt, count, 0, u); - break; - case NM_RESTORE_JRC16: - gen_restore(ctx, rt, count, 0, u); - gen_compute_branch_nm(ctx, OPC_JR, 2, 31, 0, 0); - break; - } - } - break; - case NM_MOVEP: - case NM_MOVEPREV: - check_nms(ctx); - { - static const int gpr2reg1[] = {4, 5, 6, 7}; - static const int gpr2reg2[] = {5, 6, 7, 8}; - int re; - int rd2 = extract32(ctx->opcode, 3, 1) << 1 | - extract32(ctx->opcode, 8, 1); - int r1 = gpr2reg1[rd2]; - int r2 = gpr2reg2[rd2]; - int r3 = extract32(ctx->opcode, 4, 1) << 3 | - extract32(ctx->opcode, 0, 3); - int r4 = extract32(ctx->opcode, 9, 1) << 3 | - extract32(ctx->opcode, 5, 3); - TCGv t0 = tcg_temp_new(); - TCGv t1 = tcg_temp_new(); - if (op == NM_MOVEP) { - rd = r1; - re = r2; - rs = decode_gpr_gpr4_zero(r3); - rt = decode_gpr_gpr4_zero(r4); - } else { - rd = decode_gpr_gpr4(r3); - re = decode_gpr_gpr4(r4); - rs = r1; - rt = r2; - } - gen_load_gpr(t0, rs); - gen_load_gpr(t1, rt); - tcg_gen_mov_tl(cpu_gpr[rd], t0); - tcg_gen_mov_tl(cpu_gpr[re], t1); - tcg_temp_free(t0); - tcg_temp_free(t1); - } - break; - default: - return decode_nanomips_32_48_opc(env, ctx); - } - - return 2; -} +#include "micromips_translate.c.inc" +#include "nanomips_translate.c.inc" /* MIPSDSP functions. */ static void gen_mipsdsp_ld(DisasContext *ctx, uint32_t opc, @@ -25482,17 +16231,17 @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) is_slot = ctx->hflags & MIPS_HFLAG_BMASK; if (ctx->insn_flags & ISA_NANOMIPS32) { ctx->opcode = translator_lduw(env, ctx->base.pc_next); - insn_bytes = decode_nanomips_opc(env, ctx); + insn_bytes = decode_isa_nanomips(env, ctx); } else if (!(ctx->hflags & MIPS_HFLAG_M16)) { ctx->opcode = translator_ldl(env, ctx->base.pc_next); insn_bytes = 4; decode_opc(env, ctx); } else if (ctx->insn_flags & ASE_MICROMIPS) { ctx->opcode = translator_lduw(env, ctx->base.pc_next); - insn_bytes = decode_micromips_opc(env, ctx); + insn_bytes = decode_isa_micromips(env, ctx); } else if (ctx->insn_flags & ASE_MIPS16) { ctx->opcode = translator_lduw(env, ctx->base.pc_next); - insn_bytes = decode_mips16_opc(env, ctx); + insn_bytes = decode_ase_mips16e(env, ctx); } else { gen_reserved_instruction(ctx); g_assert(ctx->base.is_jmp == DISAS_NORETURN); diff --git a/target/mips/tcg/translate.h b/target/mips/tcg/translate.h index 6144259..c25fad5 100644 --- a/target/mips/tcg/translate.h +++ b/target/mips/tcg/translate.h @@ -146,6 +146,11 @@ void gen_store_fpr32(DisasContext *ctx, TCGv_i32 t, int reg); void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg); int get_fp_bit(int cc); +void gen_ldxs(DisasContext *ctx, int base, int index, int rd); +void gen_align(DisasContext *ctx, int wordsz, int rd, int rs, int rt, int bp); +void gen_addiupc(DisasContext *ctx, int rx, int imm, + int is_64_bit, int extended); + /* * Address Computation and Large Constant Instructions */ diff --git a/tests/acceptance/machine_mips_fuloong2e.py b/tests/acceptance/machine_mips_fuloong2e.py new file mode 100644 index 0000000..0ac285e --- /dev/null +++ b/tests/acceptance/machine_mips_fuloong2e.py @@ -0,0 +1,42 @@ +# Functional tests for the Lemote Fuloong-2E machine. +# +# Copyright (c) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org> +# +# This work is licensed under the terms of the GNU GPL, version 2 or later. +# See the COPYING file in the top-level directory. +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import os + +from avocado import skipUnless +from avocado_qemu import Test +from avocado_qemu import wait_for_console_pattern + +class MipsFuloong2e(Test): + + timeout = 60 + + @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code') + @skipUnless(os.getenv('RESCUE_YL_PATH'), 'RESCUE_YL_PATH not available') + def test_linux_kernel_isa_serial(self): + """ + :avocado: tags=arch:mips64el + :avocado: tags=machine:fuloong2e + :avocado: tags=endian:little + :avocado: tags=device:bonito64 + :avocado: tags=device:via686b + """ + # Recovery system for the Yeeloong laptop + # (enough to test the fuloong2e southbridge, accessing its ISA bus) + # http://dev.lemote.com/files/resource/download/rescue/rescue-yl + kernel_hash = 'ec4d1bd89a8439c41033ca63db60160cc6d6f09a' + kernel_path = self.fetch_asset('file://' + os.getenv('RESCUE_YL_PATH'), + asset_hash=kernel_hash) + + self.vm.set_console() + self.vm.add_args('-kernel', kernel_path) + self.vm.launch() + wait_for_console_pattern(self, 'Linux version 2.6.27.7lemote') + cpu_revision = 'CPU revision is: 00006302 (ICT Loongson-2)' + wait_for_console_pattern(self, cpu_revision) |