@@ -59,6 +59,8 @@ int graphic_depth = 32;
#define QEMU_ARCH QEMU_ARCH_MICROBLAZE
#elif defined(TARGET_MIPS)
#define QEMU_ARCH QEMU_ARCH_MIPS
+#elif defined(TARGET_RISCV)
+#define QEMU_ARCH QEMU_ARCH_RISCV
#elif defined(TARGET_MOXIE)
#define QEMU_ARCH QEMU_ARCH_MOXIE
#elif defined(TARGET_OPENRISC)
@@ -518,6 +518,8 @@ elif check_define _ARCH_PPC ; then
fi
elif check_define __mips__ ; then
cpu="mips"
+elif check_define __riscv__ ; then
+ cpu="riscv"
elif check_define __ia64__ ; then
cpu="ia64"
elif check_define __s390__ ; then
@@ -558,6 +560,9 @@ case "$cpu" in
mips*)
cpu="mips"
;;
+ riscv*)
+ cpu="riscv"
+ ;;
sparc|sun4[cdmuv])
cpu="sparc"
;;
@@ -5600,6 +5605,10 @@ case "$target_name" in
TARGET_BASE_ARCH=mips
echo "TARGET_ABI_MIPSN64=y" >> $config_target_mak
;;
+ riscv)
+ TARGET_ARCH=riscv
+ echo "TARGET_ABI_RISCV=y" >> $config_target_mak
+ ;;
moxie)
;;
or32)
@@ -5804,6 +5813,10 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
ppc*)
disas_config "PPC"
;;
+ riscv*)
+ echo "CONFIG_RISCV_DIS=y" >> $config_target_mak
+ echo "CONFIG_RISCV_DIS=y" >> config-all-disas.mak
+ ;;
s390*)
disas_config "S390"
;;
@@ -1540,6 +1540,9 @@ CpuInfoList *qmp_query_cpus(Error **errp)
#elif defined(TARGET_SPARC)
SPARCCPU *sparc_cpu = SPARC_CPU(cpu);
CPUSPARCState *env = &sparc_cpu->env;
+#elif defined(TARGET_RISCV)
+ RISCVCPU *riscv_cpu = RISCV_CPU(cpu);
+ CPURISCVState *env = &riscv_cpu->env;
#elif defined(TARGET_MIPS)
MIPSCPU *mips_cpu = MIPS_CPU(cpu);
CPUMIPSState *env = &mips_cpu->env;
@@ -1574,6 +1577,9 @@ CpuInfoList *qmp_query_cpus(Error **errp)
#elif defined(TARGET_TRICORE)
info->value->has_PC = true;
info->value->PC = env->PC;
+#elif defined(TARGET_RISCV)
+ info->value->has_PC = true;
+ info->value->PC = env->active_tc.PC;
#endif
/* XXX: waiting for the qapi to support GSList */
new file mode 100644
@@ -0,0 +1 @@
+# Default configuration for riscv-linux-user
new file mode 100644
@@ -0,0 +1,38 @@
+# Default configuration for riscv-softmmu
+
+#include pci.mak
+#include sound.mak
+#include usb.mak
+#CONFIG_ESP=y
+#CONFIG_VGA=y
+#CONFIG_VGA_PCI=y
+#CONFIG_VGA_ISA=y
+#CONFIG_VGA_ISA_MM=y
+#CONFIG_VGA_CIRRUS=y
+#CONFIG_VMWARE_VGA=y
+CONFIG_SERIAL=y
+#CONFIG_PARALLEL=y
+#CONFIG_I8254=y
+#CONFIG_PCSPK=y
+#CONFIG_PCKBD=y
+#CONFIG_FDC=y
+#CONFIG_ACPI=y
+#CONFIG_APM=y
+#CONFIG_I8257=y
+#CONFIG_PIIX4=y
+#CONFIG_IDE_ISA=y
+#CONFIG_IDE_PIIX=y
+#CONFIG_NE2000_ISA=y
+#CONFIG_RC4030=y
+#CONFIG_DP8393X=y
+#CONFIG_DS1225Y=y
+#CONFIG_MIPSNET=y
+#CONFIG_PFLASH_CFI01=y
+#CONFIG_G364FB=y
+CONFIG_I8259=y
+#CONFIG_JAZZ_LED=y
+#CONFIG_MC146818RTC=y
+#CONFIG_VT82C686=y
+#CONFIG_ISA_TESTDEV=y
+#CONFIG_EMPTY_SLOT=y
+CONFIG_VIRTIO=y
@@ -315,6 +315,8 @@ void disas(FILE *out, void *code, unsigned long size)
print_insn = print_insn_hppa;
#elif defined(__ia64__)
print_insn = print_insn_ia64;
+#elif defined(__riscv__)
+ print_insn = print_insn_riscv;
#endif
if (print_insn == NULL) {
print_insn = print_insn_od_host;
@@ -18,6 +18,7 @@ common-obj-$(CONFIG_S390_DIS) += s390.o
common-obj-$(CONFIG_SH4_DIS) += sh4.o
common-obj-$(CONFIG_SPARC_DIS) += sparc.o
common-obj-$(CONFIG_LM32_DIS) += lm32.o
+common-obj-$(CONFIG_RISCV_DIS) += riscv.o
# TODO: As long as the TCG interpreter and its generated code depend
# on the QEMU target, we cannot compile the disassembler here.
new file mode 100644
@@ -0,0 +1,46 @@
+#include "disas/bfd.h"
+
+#define USE_SPIKE_DASM
+
+int print_insn_riscv(bfd_vma pc, disassemble_info *info)
+{
+ int i, n = info->buffer_length;
+ int j;
+ uint8_t *buf = g_malloc(n);
+
+ #ifdef USE_SPIKE_DASM
+ int buflen = 100;
+ char * runbuf = g_malloc(buflen); // TODO len
+ #endif
+
+ info->read_memory_func(pc, buf, n, info);
+
+ const char *prefix = "RISC-V Inst";
+
+ for (j = 0; j < n; j += 4) {
+ info->fprintf_func(info->stream, "\n%s: 0x", prefix);
+
+ // little-endian
+ for (i = 3; i >= 0; --i) {
+ info->fprintf_func(info->stream, "%02x", buf[j+i]);
+ }
+
+ // use spike-dasm
+ #ifdef USE_SPIKE_DASM
+ info->fprintf_func(info->stream, "\n");
+ snprintf(runbuf, buflen, "echo 'DASM(%02x%02x%02x%02x)\n' | spike-dasm 1>&2",
+ buf[j+3], buf[j+2], buf[j+1], buf[j+0]);
+ int res = system(runbuf);
+ if (res) {
+ printf("spike-dasm error\n");
+ exit(1);
+ }
+ #endif
+ }
+
+ g_free(runbuf);
+ g_free(buf);
+ return n;
+}
+
+
new file mode 100644
@@ -0,0 +1,5 @@
+obj-y += riscv_board.o
+obj-y += cputimer.o riscv_int.o
+obj-y += htif/htif.o
+obj-y += htif/frontend.o
+obj-y += softint.o
new file mode 100644
@@ -0,0 +1,170 @@
+/*
+ * QEMU RISC-V timer, instret counter support
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/riscv/cpudevs.h"
+#include "hw/riscv/cputimer.h"
+#include "qemu/timer.h"
+
+//#define TIMER_DEBUGGING_RISCV
+
+static uint64_t written_delta;
+static uint64_t instret_delta;
+
+// this is the "right value" for defaults in pk/linux
+// see pk/sbi_entry.S and arch/riscv/kernel/time.c call to
+// clockevents_config_and_register
+#define TIMER_FREQ 10 * 1000 * 1000
+// CPU_FREQ is for instret approximation - say we're running at 1 BIPS
+#define CPU_FREQ 1000 * 1000 * 1000
+
+inline uint64_t rtc_read(CPURISCVState *env) {
+ return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), TIMER_FREQ, get_ticks_per_sec());
+}
+
+inline uint64_t rtc_read_with_delta(CPURISCVState *env) {
+ return rtc_read(env) + written_delta;
+}
+
+inline uint64_t instret_read(CPURISCVState *env) {
+ return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), CPU_FREQ, get_ticks_per_sec());
+}
+
+inline uint64_t instret_read_with_delta(CPURISCVState *env) {
+ return instret_read(env) + instret_delta;
+}
+
+/*
+ * Called when mtimecmp is written to update the QEMU timer or immediately
+ * trigger timer interrupt if mtimecmp <= current timer value.
+ */
+static inline void cpu_riscv_timer_update(CPURISCVState *env)
+{
+ uint64_t next;
+ uint64_t diff;
+
+ uint64_t rtc_r = rtc_read_with_delta(env);
+
+ #ifdef TIMER_DEBUGGING_RISCV
+ printf("timer update: mtimecmp %016lx, timew %016lx\n",
+ env->csr[NEW_CSR_MTIMECMP], rtc_r);
+ #endif
+
+ if (env->csr[NEW_CSR_MTIMECMP] <= rtc_r) {
+ // if we're setting an MTIMECMP value in the "past", immediately raise
+ // the timer interrupt
+ env->csr[NEW_CSR_MIP] |= MIP_MTIP;
+ qemu_irq_raise(env->irq[7]);
+ return;
+ }
+
+ // otherwise, set up the future timer interrupt
+ diff = env->csr[NEW_CSR_MTIMECMP] - rtc_r;
+ // back to ns (note args switched in muldiv64)
+ next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ muldiv64(diff, get_ticks_per_sec(), TIMER_FREQ);
+ timer_mod(env->timer, next);
+}
+
+/*
+ * Called by the callback used when the timer set using timer_mod expires.
+ * Should raise the timer interrupt line
+ */
+static inline void cpu_riscv_timer_expire(CPURISCVState *env)
+{
+ // do not call update here
+ env->csr[NEW_CSR_MIP] |= MIP_MTIP;
+ qemu_irq_raise(env->irq[7]);
+}
+
+
+inline void cpu_riscv_store_timew(CPURISCVState *env, uint64_t val_to_write) {
+ #ifdef TIMER_DEBUGGING_RISCV
+ printf("write timew: 0x%016lx\n", val_to_write);
+ #endif
+
+ written_delta = val_to_write - rtc_read(env);
+}
+
+inline void cpu_riscv_store_instretw(CPURISCVState *env, uint64_t val_to_write) {
+ #ifdef TIMER_DEBUGGING_RISCV
+ printf("write instretw: 0x%016lx\n", val_to_write);
+ #endif
+
+ written_delta = val_to_write - instret_read(env);
+}
+
+inline uint64_t cpu_riscv_read_instretw(CPURISCVState *env) {
+ uint64_t retval = instret_read_with_delta(env);
+ return retval;
+}
+
+inline uint64_t cpu_riscv_read_mtime(CPURISCVState *env) {
+ uint64_t retval = rtc_read(env);
+ return retval;
+}
+
+inline uint64_t cpu_riscv_read_stime(CPURISCVState *env) {
+ uint64_t retval = rtc_read(env);
+ return retval;
+}
+
+inline uint64_t cpu_riscv_read_time(CPURISCVState *env) {
+ uint64_t retval = rtc_read_with_delta(env);
+ return retval;
+}
+
+inline void cpu_riscv_store_compare (CPURISCVState *env, uint64_t value)
+{
+ #ifdef TIMER_DEBUGGING_RISCV
+ uint64_t rtc_r = rtc_read_with_delta(env);
+ printf("wrote mtimecmp %016lx, timew %016lx\n", value, rtc_r);
+ #endif
+
+ env->csr[NEW_CSR_MTIMECMP] = value;
+ env->csr[NEW_CSR_MIP] &= ~MIP_MTIP;
+ cpu_riscv_timer_update(env);
+}
+
+/*
+ * Callback used when the timer set using timer_mod expires.
+ */
+static void riscv_timer_cb (void *opaque)
+{
+ CPURISCVState *env;
+ env = opaque;
+ cpu_riscv_timer_expire(env);
+}
+
+/*
+ * Initialize clock mechanism.
+ */
+void cpu_riscv_clock_init (CPURISCVState *env)
+{
+ env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_timer_cb, env);
+ env->csr[NEW_CSR_MTIMECMP] = 0;
+ cpu_riscv_store_timew(env, 1);
+ written_delta = 0;
+ instret_delta = 0;
+}
new file mode 100644
@@ -0,0 +1,215 @@
+/*
+ * QEMU RISC-V Syscall Proxy Emulation
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * This provides a set of functions used by the HTIF Syscall Proxy device.
+ * This is used by bbl and pk. Currently, only syscalls needed by bbl to
+ * boot Linux are supported.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/riscv/htif/htif.h"
+#include "hw/riscv/htif/frontend.h"
+#include <inttypes.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+//#define DEBUG_FRONTEND_RISCV
+
+// only supports one fd right now, for the kernel we load
+int real_kernelfd = -1;
+
+#define BBL_AT_FDCWD (-100)
+
+uint64_t sys_openat(HTIFState *htifstate, uint64_t dirfd, uint64_t pname,
+ uint64_t len, uint64_t flags, uint64_t mode) {
+
+ void * base = htifstate->main_mem_ram_ptr + (uintptr_t)pname;
+
+ char name[len];
+ int i;
+ for (i = 0; i < len; i++) {
+ name[i] = ldub_p((void*)(base + i));
+ }
+
+ // in case host OS has different val for AT_FDCWD, e.g. OS X
+ dirfd = dirfd == BBL_AT_FDCWD ? AT_FDCWD : dirfd;
+
+ #ifdef DEBUG_FRONTEND_RISCV
+ fprintf(stderr, "openat: %s\n"
+ "dirfd %ld, flags %ld, mode %ld\n", name, dirfd, flags, mode);
+ #endif
+
+ real_kernelfd = openat(dirfd, name, flags, mode);
+
+ #ifdef DEBUG_FRONTEND_RISCV
+ fprintf(stderr, "got real fd: %d\n", real_kernelfd);
+ #endif
+
+ if (real_kernelfd != -1) {
+ // always give fd 3 to bbl, until we have a better tracking mechanism
+ return 3;
+ }
+ return -1;
+}
+
+
+uint64_t sys_close(HTIFState *htifstate, uint64_t fd) {
+ if (fd != 3) {
+ fprintf(stderr, "INVALID close fd: %ld. only 3 allowed\n", fd);
+ fprintf(stderr, "Did you supply the right kernel using -append?\n");
+ exit(1);
+ }
+
+ if (close(real_kernelfd) < 0) {
+ return -1;
+ }
+ real_kernelfd = -1;
+ return 0;
+}
+
+/*
+ * Used by bbl to print.
+ */
+uint64_t sys_write(HTIFState *htifstate, uint64_t fd, uint64_t pbuf, uint64_t len) {
+
+ int i;
+ char * printbuf = malloc(sizeof(char)*(len+1));
+ printbuf[len] = '\0'; // null term for easy printing
+ void * base = htifstate->main_mem_ram_ptr + (uintptr_t)pbuf;
+ for (i = 0; i < len; i++) {
+ printbuf[i] = ldub_p((void*)(base + i));
+ }
+
+ switch(fd) {
+ case 1:
+ case 2:
+ printf("%s", printbuf);
+ break;
+ default:
+ fprintf(stderr, "INVALID SYS_WRITE\n");
+ exit(1);
+ }
+ free(printbuf);
+ return len;
+}
+
+uint64_t sys_pread(HTIFState *htifstate, uint64_t fd, uint64_t pbuf, uint64_t len, uint64_t off) {
+ #ifdef DEBUG_FRONTEND_RISCV
+ fprintf(stderr, "read fd: %ld, len: %ld, off: %ld\n", fd, len, off);
+ #endif
+ if (fd != 3) {
+ fprintf(stderr, "INVALID pread fd: %ld. only 3 allowed\n", fd);
+ exit(1);
+ }
+
+ char * buf = malloc(sizeof(char)*len);
+ size_t bytes_read = pread(real_kernelfd, buf, len, off);
+
+ void * base = htifstate->main_mem_ram_ptr + (uintptr_t)pbuf;
+ int i;
+ for (i = 0; i < bytes_read; i++) {
+ stb_p((void*)(base + i), buf[i]);
+ }
+ free(buf);
+ return bytes_read;
+}
+
+uint64_t sys_exit(HTIFState *htifstate, uint64_t code) {
+ printf("sys_exit. code: %ld\n", code << 1 | 1);
+ exit(code << 1 | 1);
+}
+
+uint64_t sys_getmainvars(HTIFState * htifstate, uint64_t pbuf, uint64_t limit) {
+ #ifdef DEBUG_FRONTEND_RISCV
+ fprintf(stderr, "%s\n", htifstate->kernel_cmdline);
+ #endif
+
+ void * base = htifstate->main_mem_ram_ptr + (uintptr_t)pbuf;
+
+ // assume args are bbl + some kernel for now
+ // later, do the right thing
+ const char * arg0 = "bbl";
+ const char * arg1 = htifstate->kernel_cmdline;
+
+ #define WORDS_LEN 5
+ #define START_ARGS (WORDS_LEN*8)
+ uint64_t words[WORDS_LEN] = {2, START_ARGS+pbuf, START_ARGS+pbuf+4, 0, 0};
+ int i;
+ for (i = 0; i < WORDS_LEN; i++) {
+ stq_p((void*)(base+i*8), words[i]);
+ }
+ for (i = 0; i < 4; i++) {
+ stb_p((void*)(base + START_ARGS + i), arg0[i]);
+ }
+ for (i = 0; i < strlen(arg1)+1; i++) {
+ stb_p((void*)(base + START_ARGS+4 + i), arg1[i]);
+ }
+ // currently no support for > 2 args
+ return 0;
+}
+
+
+int handle_frontend_syscall(HTIFState *htifstate, uint64_t payload) {
+
+ uint64_t mm[8];
+ int i;
+ void * base = htifstate->main_mem_ram_ptr + (uintptr_t)payload;
+ for (i = 0; i < 8; i++) {
+ mm[i] = ldq_p((void*)(base + i*8));
+ }
+
+ #ifdef DEBUG_FRONTEND_RISCV
+ for (i = 0; i < 8; i++) {
+ fprintf(stderr, "elem %d, val 0x%016lx\n", i, mm[i]);
+ }
+ #endif
+
+ uint64_t retval = -1;
+ switch(mm[0]) {
+ case RV_FSYSCALL_sys_openat:
+ retval = sys_openat(htifstate, mm[1], mm[2], mm[3], mm[4], mm[5]);
+ break;
+ case RV_FSYSCALL_sys_close:
+ retval = sys_close(htifstate, mm[1]);
+ break;
+ case RV_FSYSCALL_sys_write:
+ retval = sys_write(htifstate, mm[1], mm[2], mm[3]);
+ break;
+ case RV_FSYSCALL_sys_pread:
+ retval = sys_pread(htifstate, mm[1], mm[2], mm[3], mm[4]);
+ break;
+ case RV_FSYSCALL_sys_exit:
+ retval = sys_exit(htifstate, mm[1]);
+ break;
+ case RV_FSYSCALL_sys_getmainvars:
+ retval = sys_getmainvars(htifstate, mm[1], mm[2]);
+ break;
+ default:
+ fprintf(stderr, "FRONTEND SYSCALL %ld NOT IMPLEMENTED\n", mm[0]);
+ exit(1);
+ }
+
+ // write retval to mm
+ stq_p((void*)base, retval);
+ return 1;
+}
new file mode 100644
@@ -0,0 +1,459 @@
+/*
+ * QEMU RISC-V Host Target Interface (HTIF) Emulation
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * This provides HTIF device emulation for QEMU. At the moment this allows
+ * for identical copies of bbl/linux to run on both spike and QEMU.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/char/serial.h"
+#include "sysemu/char.h"
+#include "hw/riscv/htif/htif.h"
+#include "hw/riscv/htif/frontend.h"
+#include "qemu/timer.h"
+#include "exec/address-spaces.h"
+#include "qemu/error-report.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+
+
+#define ENABLE_CHARDEV
+//#define DEBUG_CHARDEV
+//#define DEBUG_BLKDEV
+//#define DEBUG_HTIF
+
+
+#ifdef ENABLE_CHARDEV
+/*
+ * Called by the char dev to see if HTIF is ready to accept input.
+ */
+static int htif_can_recv(void *opaque)
+{
+ return 1;
+}
+
+/*
+ * Called by the char dev to supply input to HTIF console.
+ * We assume that we will receive one character at a time.
+ */
+static void htif_recv(void *opaque, const uint8_t *buf, int size)
+{
+ if (size != 1) {
+ return;
+ }
+
+ HTIFState *htifstate = opaque;
+
+ #ifdef DEBUG_CHARDEV
+ if (htifstate->env->csr[NEW_CSR_MFROMHOST] != 0x0) {
+ fprintf(stderr, "recv handler: fromhost was not ready to accept input\n");
+ fprintf(stderr, "recv handler: prev value was: %016lx\n", htifstate->env->csr[NEW_CSR_MFROMHOST]);
+ }
+ #endif
+
+ uint64_t val_written = htifstate->pending_read;
+ uint64_t resp = 0x100 | *buf;
+
+ htifstate->env->csr[NEW_CSR_MFROMHOST] = (val_written >> 48 << 48) | (resp << 16 >> 16);
+ qemu_irq_raise(htifstate->irq);
+}
+
+/*
+ * Called by the char dev to supply special events to the HTIF console.
+ * Not used for HTIF.
+ */
+static void htif_event(void *opaque, int event)
+{
+ #ifdef DEBUG_CHARDEV
+ fprintf(stderr, "GOT EVENT: %d\n", event);
+ #endif
+}
+#endif
+
+static void htif_pre_save(void *opaque)
+{
+ return;
+}
+
+static int htif_post_load(void *opaque, int version_id)
+{
+ return 0;
+}
+
+const VMStateDescription vmstate_htif = {
+ .name = "htif",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = htif_pre_save,
+ .post_load = htif_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT64(tohost_addr, HTIFState),
+ VMSTATE_UINT64(fromhost_addr, HTIFState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void dma_strcopy(HTIFState *htifstate, char *str, hwaddr phys_addr) {
+ int i = 0;
+ void* base_copy_addr = htifstate->main_mem_ram_ptr+phys_addr;
+ while(*(str+i)) {
+ stb_p((void*)(base_copy_addr + i), *(str + i));
+ i++;
+ }
+ stb_p((void*)(base_copy_addr + i), 0); // store null term
+}
+
+static int htif_block_device_read(HTIFState *htifstate, uint64_t payload) {
+ request_t req;
+ int i;
+ uint8_t* reqptr = (uint8_t*)&req;
+ void *base = htifstate->main_mem_ram_ptr+payload;
+ for (i = 0; i < sizeof(req); i++) {
+ *(reqptr + i) = ldub_p((void*)(base + i));
+ }
+
+ #ifdef DEBUG_BLKDEV
+ fprintf(stderr, "HTIF Block device read:\n");
+ fprintf(stderr, "-addr: %016lx\n", req.addr);
+ fprintf(stderr, "-offset: %016lx\n", req.offset);
+ fprintf(stderr, "-size: %016lx\n", req.size);
+ fprintf(stderr, "-tag: %016lx\n", req.tag);
+ #endif
+
+ uint8_t * copybuf = malloc(req.size * sizeof(uint8_t));
+ if (pread(htifstate->block_fd, copybuf, req.size, req.offset) != req.size) {
+ printf("FAILED READ\n");
+ exit(1);
+ }
+
+ base = htifstate->main_mem_ram_ptr + req.addr;
+
+ for (i = 0; i < req.size; i++) {
+ stb_p((void*)(base + i), copybuf[i]);
+ }
+ free(copybuf);
+ return req.tag;
+}
+
+static int htif_block_device_write(HTIFState *htifstate, uint64_t payload) {
+ request_t req;
+ int i;
+ uint8_t* reqptr = (uint8_t*)&req;
+ void* base = htifstate->main_mem_ram_ptr + payload;
+ for (i = 0; i < sizeof(req); i++) {
+ *(reqptr + i) = ldub_p((void*)(base + i));
+ }
+
+ uint8_t * copybuf = malloc(req.size * sizeof(uint8_t));
+
+ base = htifstate->main_mem_ram_ptr + req.addr;
+ for (i = 0; i < req.size; i++) {
+ copybuf[i] = ldub_p((void*)(base + i));
+ }
+
+ if (pwrite(htifstate->block_fd, copybuf, req.size, req.offset) != req.size) {
+ printf("FAILED WRITE\n");
+ exit(1);
+ }
+
+ free(copybuf);
+ return req.tag;
+}
+
+static void htif_handle_tohost_write(HTIFState *htifstate, uint64_t val_written) {
+
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "TOHOST WRITE WITH val 0x%016lx\n", val_written);
+ #endif
+
+ uint8_t device = val_written >> 56;
+ uint8_t cmd = val_written >> 48;
+ uint64_t payload = val_written & 0xFFFFFFFFFFFFULL;
+
+ uint64_t addr = payload >> 8;
+ hwaddr real_addr = (hwaddr)addr;
+ uint8_t what = payload & 0xFF;
+ int resp;
+
+ resp = 0; // stop gcc complaining
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "mtohost write:\n-device: %d\n-cmd: %d\n-what: %02lx\n-payload: %016lx\n", device, cmd, payload & 0xFF, payload);
+ #endif
+
+ /*
+ * Currently, there is a fixed mapping of devices:
+ * 0: Syscall Proxy
+ * 1: Console
+ * 2: Block Device
+ */
+ if (unlikely(device == 0x0)) {
+ // frontend syscall handler
+ if (cmd == 0x0) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "frontend syscall handler\n");
+ #endif
+ if (payload & 0x1) {
+ // test result
+ if (payload >> 1) {
+ printf("*** FAILED *** (exitcode = %016lx)\n", payload >> 1);
+ } else {
+ printf("TEST PASSED\n");
+ }
+ exit(payload >> 1);
+ }
+ resp = handle_frontend_syscall(htifstate, payload);
+ } else if (cmd == 0xFF) {
+ // use what
+ if (what == 0xFF) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering name\n");
+ #endif
+ dma_strcopy(htifstate, (char*)"syscall_proxy", real_addr);
+ } else if (what == 0x0) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering syscall cmd\n");
+ #endif
+ dma_strcopy(htifstate, (char*)"syscall", real_addr);
+ } else {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering end of cmds list\n");
+ #endif
+ dma_strcopy(htifstate, (char*)"", real_addr);
+ }
+ resp = 0x1; // write to indicate device name placed
+ } else {
+ fprintf(stderr, "HTIF device %d: UNKNOWN COMMAND\n", device);
+ exit(1);
+ }
+ } else if (likely(device == 0x1)) {
+ // HTIF Console
+ if (cmd == 0x0) {
+ // this should be a queue, but not yet implemented as such
+ htifstate->pending_read = val_written;
+ htifstate->env->csr[NEW_CSR_MTOHOST] = 0; // clear to indicate we read
+ return;
+ } else if (cmd == 0x1) {
+ #ifdef ENABLE_CHARDEV
+ qemu_chr_fe_write(htifstate->chr, (uint8_t*)&payload, 1);
+ #endif
+ resp = 0x100 | (uint8_t)payload;
+ } else if (cmd == 0xFF) {
+ // use what
+ if (what == 0xFF) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering name\n");
+ #endif
+ dma_strcopy(htifstate, (char*)"bcd", real_addr);
+ } else if (what == 0x0) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering read cmd\n");
+ #endif
+ dma_strcopy(htifstate, (char*)"read", real_addr);
+ } else if (what == 0x1) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering write cmd\n");
+ #endif
+ dma_strcopy(htifstate, (char*)"write", real_addr);
+ } else {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering end of cmds list\n");
+ #endif
+ dma_strcopy(htifstate, (char*)"", real_addr);
+ }
+ resp = 0x1; // write to indicate device name placed
+ } else {
+ fprintf(stderr, "HTIF device %d: UNKNOWN COMMAND\n", device);
+ exit(1);
+ }
+ } else if (device == 0x2 && htifstate->block_dev_present) {
+ // HTIF Block Device
+ if (unlikely(cmd == 0xFF)) {
+ if (what == 0xFF) { // register
+ dma_strcopy(htifstate, htifstate->real_name, real_addr);
+ } else if (what == 0x0) {
+ dma_strcopy(htifstate, (char*)"read", real_addr);
+ } else if (what == 0x1) {
+ dma_strcopy(htifstate, (char*)"write", real_addr);
+ } else {
+ dma_strcopy(htifstate, (char*)"", real_addr);
+ }
+ resp = 0x1; // write to indicate device name placed
+ } else if (cmd == 0x0) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "DOING DISK READ\n");
+ #endif
+ resp = htif_block_device_read(htifstate, payload);
+ } else if (cmd == 0x1) {
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "DOING DISK WRITE\n");
+ #endif
+ resp = htif_block_device_write(htifstate, payload);
+ } else {
+ fprintf(stderr, "HTIF device %d: UNKNOWN COMMAND\n", device);
+ exit(1);
+ }
+ } else if (device == 0x3 && cmd == 0xFF && what == 0xFF) { // all other devices
+ #ifdef DEBUG_HTIF
+ fprintf(stderr, "registering no device as last\n");
+ #endif
+ stb_p((void*)(htifstate->main_mem_ram_ptr+real_addr), 0);
+ resp = 0x1; // write to indicate device name placed
+ } else {
+ fprintf(stderr, "HTIF UNKNOWN DEVICE OR COMMAND!\n");
+ fprintf(stderr, "-device: %d\n-cmd: %d\n-what: %02lx\n-payload: %016lx\n", device, cmd, payload & 0xFF, payload);
+ exit(1);
+ }
+ while (!htifstate->fromhost_inprogress && htifstate->env->csr[NEW_CSR_MFROMHOST] != 0x0) {
+ // wait
+ }
+ htifstate->env->csr[NEW_CSR_MFROMHOST] = (val_written >> 48 << 48) | (resp << 16 >> 16);
+ htifstate->env->csr[NEW_CSR_MTOHOST] = 0; // clear to indicate we read
+ if (htifstate->env->csr[NEW_CSR_MFROMHOST] != 0) {
+ // raise HTIF interrupt
+ qemu_irq_raise(htifstate->irq);
+ }
+}
+
+// CPU wants to read an HTIF register
+static uint64_t htif_mm_read(void *opaque, hwaddr addr, unsigned size)
+{
+ HTIFState *htifstate = opaque;
+ if (addr == 0x0) {
+ return htifstate->env->csr[NEW_CSR_MTOHOST] & 0xFFFFFFFF;
+ } else if (addr == 0x4) {
+ return (htifstate->env->csr[NEW_CSR_MTOHOST] >> 32) & 0xFFFFFFFF;
+ } else if (addr == 0x8) {
+ return htifstate->env->csr[NEW_CSR_MFROMHOST] & 0xFFFFFFFF;
+ } else if (addr == 0xc) {
+ return (htifstate->env->csr[NEW_CSR_MFROMHOST] >> 32) & 0xFFFFFFFF;
+ } else {
+ printf("Invalid htif register address %016lx\n", (uint64_t)addr);
+ exit(1);
+ }
+}
+
+// CPU wrote to an HTIF register
+static void htif_mm_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ HTIFState *htifstate = opaque;
+ if (addr == 0x0) {
+ if (htifstate->env->csr[NEW_CSR_MTOHOST] == 0x0) {
+ htifstate->allow_tohost = 1;
+ htifstate->env->csr[NEW_CSR_MTOHOST] = value & 0xFFFFFFFF;
+ } else {
+ htifstate->allow_tohost = 0;
+ }
+ } else if (addr == 0x4) {
+ if (htifstate->allow_tohost) {
+ htifstate->env->csr[NEW_CSR_MTOHOST] |= value << 32;
+ htif_handle_tohost_write(htifstate, htifstate->env->csr[NEW_CSR_MTOHOST]);
+ }
+ } else if (addr == 0x8) {
+ htifstate->fromhost_inprogress = 1;
+ htifstate->env->csr[NEW_CSR_MFROMHOST] = value & 0xFFFFFFFF;
+ } else if (addr == 0xc) {
+ htifstate->env->csr[NEW_CSR_MFROMHOST] |= value << 32;
+ if (htifstate->env->csr[NEW_CSR_MFROMHOST] == 0x0) {
+ qemu_irq_lower(htifstate->irq);
+ }
+ htifstate->fromhost_inprogress = 0;
+ } else {
+ printf("Invalid htif register address %016lx\n", (uint64_t)addr);
+ exit(1);
+ }
+}
+
+static const MemoryRegionOps htif_mm_ops[3] = {
+ [DEVICE_LITTLE_ENDIAN] = {
+ .read = htif_mm_read,
+ .write = htif_mm_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ },
+};
+
+HTIFState *htif_mm_init(MemoryRegion *address_space, hwaddr base, qemu_irq irq,
+ MemoryRegion *main_mem, const char* htifbd_fname,
+ const char *kernel_cmdline,
+ CPURISCVState *env,
+ CharDriverState *chr)
+{
+ // TODO: cleanup the constant buffer sizes
+ HTIFState *htifstate;
+ size_t size;
+ char *rname;
+ char size_str_buf[400];
+
+ htifstate = g_malloc0(sizeof(HTIFState));
+ rname = g_malloc0(sizeof(char)*500);
+ htifstate->tohost_addr = base;
+ htifstate->fromhost_addr = base + 0x8;
+ htifstate->irq = irq;
+ htifstate->address_space = address_space;
+ htifstate->main_mem = main_mem;
+ htifstate->main_mem_ram_ptr = memory_region_get_ram_ptr(main_mem);
+ htifstate->env = env;
+ htifstate->chr = chr;
+ htifstate->pending_read = 0;
+ htifstate->allow_tohost = 0;
+ htifstate->fromhost_inprogress = 0;
+
+#ifdef ENABLE_CHARDEV
+ qemu_chr_add_handlers(htifstate->chr, htif_can_recv, htif_recv, htif_event, htifstate);
+#endif
+
+ vmstate_register(NULL, base, &vmstate_htif, htifstate);
+
+ memory_region_init_io(&htifstate->io, NULL, &htif_mm_ops[DEVICE_LITTLE_ENDIAN],
+ htifstate, "htif", 16 /* 2 64-bit registers */);
+ memory_region_add_subregion(address_space, base, &htifstate->io);
+
+ // save kernel_cmdline for sys_getmainvars
+ htifstate->kernel_cmdline = malloc(strlen(kernel_cmdline)+1);
+ strcpy(htifstate->kernel_cmdline, kernel_cmdline);
+
+ if (NULL == htifbd_fname) { // NULL means no -hda specified
+ htifstate->block_dev_present = 0;
+ return htifstate;
+ }
+
+ htifstate->block_fname = htifbd_fname;
+ htifstate->block_fd = open(htifstate->block_fname, O_RDWR);
+
+ struct stat st;
+ if (fstat(htifstate->block_fd, &st) < 0) {
+ fprintf(stderr, "WARN: Could not stat %s, continuing without block device.\n",
+ htifstate->block_fname);
+ htifstate->block_dev_present = 0;
+ return htifstate;
+ }
+ size = st.st_size;
+ strcpy(rname, "disk size=");
+ snprintf(size_str_buf, sizeof(size_str_buf), "%zu", size);
+ strcat(rname, size_str_buf);
+ htifstate->real_name = rname;
+ htifstate->block_dev_present = 1;
+ return htifstate;
+}
new file mode 100644
@@ -0,0 +1,330 @@
+/*
+ * QEMU RISC-V Generic Board Support
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * This provides a RISC-V Board with the following devices:
+ *
+ * 0) HTIF Syscall Proxy
+ * 1) HTIF Console
+ * 2) HTIF Block Device
+ *
+ * These are created by htif_mm_init below.
+ *
+ * The following "Shim" devices allow support for interrupts triggered by the
+ * processor itself (writes to the MIP/SIP CSRs):
+ *
+ * softint0 - SSIP
+ * softint1 - STIP
+ * softint2 - MSIP
+ *
+ * These are created by softint_mm_init below.
+ *
+ * This board currently uses a hardcoded devicetree that indicates one hart
+ * and 2048 MB of memory.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/char/serial.h"
+#include "hw/riscv/softint.h"
+#include "hw/riscv/htif/htif.h"
+#include "hw/riscv/htif/frontend.h"
+#include "hw/block/fdc.h"
+#include "net/net.h"
+#include "hw/boards.h"
+#include "hw/i2c/smbus.h"
+#include "block/block.h"
+#include "hw/block/flash.h"
+#include "block/block_int.h" // move later
+#include "hw/riscv/riscv.h"
+#include "hw/riscv/cpudevs.h"
+#include "hw/pci/pci.h"
+#include "sysemu/char.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/arch_init.h"
+#include "qemu/log.h"
+#include "hw/riscv/bios.h"
+#include "hw/ide.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "hw/timer/mc146818rtc.h"
+#include "hw/timer/i8254.h"
+#include "sysemu/blockdev.h"
+#include "exec/address-spaces.h"
+#include "hw/sysbus.h" /* SysBusDevice */
+#include "qemu/host-utils.h"
+#include "sysemu/qtest.h"
+#include "qemu/error-report.h"
+#include "hw/empty_slot.h"
+#include "qemu/error-report.h"
+#include "sysemu/block-backend.h"
+
+#define TYPE_RISCV_BOARD "riscv-board"
+#define RISCV_BOARD(obj) OBJECT_CHECK(BoardState, (obj), TYPE_RISCV_BOARD)
+
+// TODO: once device tree format is finalized, don't hardcode
+#define DEVTREE_LEN 65944
+char devtree[DEVTREE_LEN] = {
+0xd0,
+0x0d, 0xfe, 0xed, 0x00, 0x00, 0x01, 0x98, 0x00, 0x00, 0x00,
+0x38, 0x00, 0x00, 0x01, 0x58, 0x00, 0x00, 0x00, 0x28, 0x00,
+0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x01, 0x20, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00,
+0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x53, 0x70, 0x69,
+0x6b, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x6d,
+0x65, 0x6d, 0x6f, 0x72, 0x79, 0x40, 0x30, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00,
+0x00, 0x00, 0x21, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00,
+0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x63, 0x70, 0x75,
+0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
+0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00,
+0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+0x01, 0x63, 0x70, 0x75, 0x40, 0x38, 0x30, 0x30, 0x30, 0x31,
+0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x21, 0x63,
+0x70, 0x75, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+0x06, 0x00, 0x00, 0x00, 0x31, 0x72, 0x69, 0x73, 0x63, 0x76,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+0x0b, 0x00, 0x00, 0x00, 0x3c, 0x72, 0x76, 0x36, 0x34, 0x69,
+0x6d, 0x61, 0x66, 0x64, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x2d, 0x00,
+0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00,
+0x00, 0x00, 0x09, 0x23, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
+0x73, 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x23, 0x73,
+0x69, 0x7a, 0x65, 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00,
+0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x00, 0x64, 0x65, 0x76, 0x69,
+0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x00, 0x72, 0x65,
+0x67, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62,
+0x6c, 0x65, 0x00, 0x69, 0x73, 0x61, 0x00,
+};
+
+
+
+typedef struct {
+ SysBusDevice parent_obj;
+} BoardState;
+
+static struct _loaderparams {
+ int ram_size;
+ const char *kernel_filename;
+ const char *kernel_cmdline;
+ const char *initrd_filename;
+} loaderparams;
+
+uint64_t identity_translate(void *opaque, uint64_t addr)
+{
+ return addr;
+}
+
+static int64_t load_kernel (void)
+{
+ int64_t kernel_entry, kernel_high;
+ int big_endian;
+ big_endian = 0;
+
+ if (load_elf(loaderparams.kernel_filename, identity_translate, NULL,
+ (uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high,
+ big_endian, ELF_MACHINE, 1) < 0) {
+ fprintf(stderr, "qemu: could not load kernel '%s'\n",
+ loaderparams.kernel_filename);
+ exit(1);
+ }
+ return kernel_entry;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+ RISCVCPU *cpu = opaque;
+ cpu_reset(CPU(cpu));
+}
+
+/* hack for now to set memory size without implementing devicetree generation
+ * modifies memory size and addresses */
+static void set_devtree_memsize(uint64_t memsize)
+{
+
+ uint64_t addr1 = memsize | 0x1000;
+
+ if (memsize <= 0x1000) {
+ fprintf(stderr, "Warning: Insufficient memsize for bbl. If you are not "
+ "using bbl, you may disregard this message\n");
+ }
+
+ int i;
+ for (i = 0; i < 8; i++) {
+ devtree[179-i] = (memsize >> (i*8)) & 0xFF;
+ devtree[327-i] = (addr1 >> (i*8)) & 0xFF;
+ }
+}
+
+static void riscv_board_init(MachineState *args)
+{
+ ram_addr_t ram_size = args->ram_size;
+ const char *cpu_model = args->cpu_model;
+ const char *kernel_filename = args->kernel_filename;
+ const char *kernel_cmdline = args->kernel_cmdline;
+ const char *initrd_filename = args->initrd_filename;
+ MemoryRegion *system_memory = get_system_memory();
+ MemoryRegion *main_mem = g_new(MemoryRegion, 1);
+ RISCVCPU *cpu;
+ CPURISCVState *env;
+ int i;
+
+ DriveInfo *htifbd_drive;
+ const char *htifbd_fname; // htif block device filename
+
+ DeviceState *dev = qdev_create(NULL, TYPE_RISCV_BOARD);
+
+ object_property_set_bool(OBJECT(dev), true, "realized", NULL);
+
+ /* Make sure the first 3 serial ports are associated with a device. */
+ for(i = 0; i < 3; i++) {
+ if (!serial_hds[i]) {
+ char label[32];
+ snprintf(label, sizeof(label), "serial%d", i);
+ serial_hds[i] = qemu_chr_new(label, "null", NULL);
+ }
+ }
+
+ /* init CPUs */
+ if (cpu_model == NULL) {
+ cpu_model = "riscv-generic";
+ }
+
+ for (i = 0; i < smp_cpus; i++) {
+ cpu = cpu_riscv_init(cpu_model);
+ if (cpu == NULL) {
+ fprintf(stderr, "Unable to find CPU definition\n");
+ exit(1);
+ }
+ env = &cpu->env;
+
+ /* Init internal devices */
+ cpu_riscv_irq_init_cpu(env);
+ cpu_riscv_clock_init(env);
+ qemu_register_reset(main_cpu_reset, cpu);
+ }
+ cpu = RISCV_CPU(first_cpu);
+ env = &cpu->env;
+
+ /* register system main memory (actual RAM) */
+ memory_region_init_ram(main_mem, NULL, "riscv_board.ram", ram_size + DEVTREE_LEN, &error_fatal);
+ // for CSR_MIOBASE
+ env->memsize = ram_size;
+ vmstate_register_ram_global(main_mem);
+ memory_region_add_subregion(system_memory, 0x0, main_mem);
+
+ if (kernel_filename) {
+ loaderparams.ram_size = ram_size;
+ loaderparams.kernel_filename = kernel_filename;
+ loaderparams.kernel_cmdline = kernel_cmdline;
+ loaderparams.initrd_filename = initrd_filename;
+ load_kernel();
+ }
+
+ // TODO: still necessary?
+ // write memory amount in MiB to 0x0
+ //stl_p(memory_region_get_ram_ptr(main_mem), ram_size >> 20);
+
+ // set memory size in devicetree
+ set_devtree_memsize(ram_size);
+
+ // copy in the devtree
+ int q;
+ for (q = 0; q < DEVTREE_LEN; q++) {
+ stb_p(memory_region_get_ram_ptr(main_mem)+ram_size+q, devtree[q]);
+ }
+
+ // add serial device 0x3f8-0x3ff
+ // serial_mm_init(system_memory, 0xF0000400, 0, env->irq[5], 1843200/16,
+ // serial_hds[0], DEVICE_NATIVE_ENDIAN);
+
+ // setup HTIF Block Device if one is specified as -hda FILENAME
+ htifbd_drive = drive_get_by_index(IF_IDE, 0);
+ if (NULL == htifbd_drive) {
+ htifbd_fname = NULL;
+ } else {
+ htifbd_fname = blk_bs(blk_by_legacy_dinfo(htifbd_drive))->filename;
+ // get rid of orphaned drive warning, until htif uses the real blockdev
+ htifbd_drive->is_default = true;
+ }
+
+ // add htif device at 0xFFFFFFFFF0000000
+ htif_mm_init(system_memory, 0xFFFFFFFFF0000000L, env->irq[4], main_mem,
+ htifbd_fname, kernel_cmdline, env, serial_hds[0]);
+
+ // Softint "devices" for cleaner handling of CPU-triggered interrupts
+ softint_mm_init(system_memory, 0xFFFFFFFFF0000020L, env->irq[1], main_mem,
+ env, "SSIP");
+ softint_mm_init(system_memory, 0xFFFFFFFFF0000040L, env->irq[2], main_mem,
+ env, "STIP");
+ softint_mm_init(system_memory, 0xFFFFFFFFF0000060L, env->irq[3], main_mem,
+ env, "MSIP");
+
+ // TODO: VIRTIO
+}
+
+static int riscv_board_sysbus_device_init(SysBusDevice *sysbusdev)
+{
+ return 0;
+}
+
+static void riscv_board_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ k->init = riscv_board_sysbus_device_init;
+}
+
+static const TypeInfo riscv_board_device = {
+ .name = TYPE_RISCV_BOARD,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(BoardState),
+ .class_init = riscv_board_class_init,
+};
+
+static void riscv_board_machine_init(MachineClass *mc)
+{
+ mc->desc = "RISC-V Generic Board";
+ mc->init = riscv_board_init;
+ mc->max_cpus = 1;
+ mc->is_default = 1;
+}
+
+DEFINE_MACHINE("riscv", riscv_board_machine_init)
+
+static void riscv_board_register_types(void)
+{
+ type_register_static(&riscv_board_device);
+}
+
+type_init(riscv_board_register_types)
new file mode 100644
@@ -0,0 +1,84 @@
+/*
+ * QEMU RISC-V - QEMU IRQ Support
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/riscv/cpudevs.h"
+#include "cpu.h"
+
+/* irq request function, called in hw/irq.h by qemu_irq_raise (level = 1),
+ * qemu_irq_lower (level = 0), qemu_irq_pulse (level = 1, then 0)
+ *
+ * The device will call this once to raise the interrupt line and once to
+ * lower the interrupt line for level-trigerring
+ *
+ */
+static void cpu_riscv_irq_request(void *opaque, int irq, int level)
+{
+ // This "irq" number is not a real irq number, just some set of numbers
+ // we choose. These are not the same irq numbers visible to the processor.
+
+ RISCVCPU *cpu = opaque;
+ CPURISCVState *env = &cpu->env;
+ CPUState *cs = CPU(cpu);
+
+ // current irqs:
+ // 7: Machine Timer. MIP_MTIP should have already been set
+ // 4: Host Interrupt. mfromhost should have a nonzero value
+ // 3, 2, 1: Interrupts triggered by the CPU. At least one of
+ // MIP_STIP, MIP_SSIP, MIP_MSIP should already be set
+ if (unlikely(irq != 7 && !(irq < 5 && irq > 0))) {
+ fprintf(stderr, "Unused IRQ was raised.\n");
+ exit(1);
+ }
+
+ if (level) {
+ cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ } else {
+ if (!env->csr[NEW_CSR_MIP] && !env->csr[NEW_CSR_MFROMHOST]) {
+ // no interrupts pending, no host interrupt for HTIF, reset
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+ }
+ }
+}
+
+void cpu_riscv_irq_init_cpu(CPURISCVState *env)
+{
+ qemu_irq *qi;
+ int i;
+
+ qi = qemu_allocate_irqs(cpu_riscv_irq_request, riscv_env_get_cpu(env), 8);
+ for (i = 0; i < 8; i++) {
+ env->irq[i] = qi[i];
+ }
+}
+
+void cpu_riscv_soft_irq(CPURISCVState *env, int irq, int level)
+{
+ printf("NOT USED for RISC-V\n");
+ exit(1);
+ if (irq != 0) {
+ return;
+ }
+ qemu_set_irq(env->irq[irq], level);
+}
new file mode 100644
@@ -0,0 +1,121 @@
+/*
+ * QEMU RISC-V Soft Interrupt Emulation
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * This module provides shim devices that allow support for interrupts
+ * triggered by the RISC-V processor itself (writes to the MIP/SIP CSRs):
+ *
+ * The following instantiations are enabled by default in riscv_board:
+ *
+ * softint0 - SSIP
+ * softint1 - STIP
+ * softint2 - MSIP
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/riscv/softint.h"
+#include "exec/address-spaces.h"
+#include "qemu/error-report.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+
+
+static void softint_pre_save(void *opaque)
+{
+ return;
+}
+
+static int softint_post_load(void *opaque, int version_id)
+{
+ return 0;
+}
+
+const VMStateDescription vmstate_softint = {
+ .name = "softint",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = softint_pre_save,
+ .post_load = softint_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+// CPU wants to read an Softint register. Should not happen.
+static uint64_t softint_mm_read(void *opaque, hwaddr addr, unsigned size)
+{
+ fprintf(stderr, "Unimplemented read softint\n");
+ exit(1);
+}
+
+// CPU wrote to an Softint register
+static void softint_mm_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ SoftintState *softintstate = opaque;
+
+ if (addr == 0x0) {
+ if (value != 0) {
+ qemu_irq_raise(softintstate->irq);
+ } else {
+ qemu_irq_lower(softintstate->irq);
+ }
+ } else {
+ fprintf(stderr, "Invalid softint register address %016lx\n", (uint64_t)addr);
+ exit(1);
+ }
+}
+
+static const MemoryRegionOps softint_mm_ops[3] = {
+ [DEVICE_LITTLE_ENDIAN] = {
+ .read = softint_mm_read,
+ .write = softint_mm_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ },
+};
+
+SoftintState *softint_mm_init(MemoryRegion *address_space, hwaddr base, qemu_irq irq,
+ MemoryRegion *main_mem, CPURISCVState *env, const char * name)
+{
+ // TODO: cleanup the constant buffer sizes
+ SoftintState *softintstate;
+
+ softintstate = g_malloc0(sizeof(SoftintState));
+ softintstate->irq = irq;
+ softintstate->address_space = address_space;
+ softintstate->env = env;
+
+ char * badbuf = g_malloc0(sizeof(char)*100);
+ sprintf(badbuf, "%s%s", "softint", name);
+ softintstate->name = badbuf;
+
+ vmstate_register(NULL, base, &vmstate_softint, softintstate);
+
+ memory_region_init_io(&softintstate->io, NULL,
+ &softint_mm_ops[DEVICE_LITTLE_ENDIAN],
+ softintstate, badbuf, 4 /* 1 32-bit register */);
+ memory_region_add_subregion(address_space, base, &softintstate->io);
+
+ return softintstate;
+}
@@ -415,6 +415,7 @@ int print_insn_crisv10 (bfd_vma, disassemble_info*);
int print_insn_microblaze (bfd_vma, disassemble_info*);
int print_insn_ia64 (bfd_vma, disassemble_info*);
int print_insn_lm32 (bfd_vma, disassemble_info*);
+int print_insn_riscv (bfd_vma, disassemble_info*);
#if 0
/* Fetch the disassembler for a given BFD, if that support is available. */
@@ -112,6 +112,8 @@ typedef int64_t Elf64_Sxword;
#define EM_UNICORE32 110 /* UniCore32 */
+#define EM_RISCV 243 /* RISC-V */
+
/*
* This is an interim value that we will use until the committee comes
* up with a final number.
@@ -19,6 +19,7 @@
#pragma GCC poison TARGET_PPCEMB
#pragma GCC poison TARGET_PPC64
#pragma GCC poison TARGET_ABI32
+#pragma GCC poison TARGET_RISCV
#pragma GCC poison TARGET_SH4
#pragma GCC poison TARGET_SPARC
#pragma GCC poison TARGET_SPARC64
@@ -121,7 +121,7 @@ static inline int thunk_type_size(const argtype *type_ptr, int is_host)
#if defined(TARGET_X86_64)
return 8;
#elif defined(TARGET_ALPHA) || defined(TARGET_IA64) || defined(TARGET_MIPS) || \
- defined(TARGET_PARISC) || defined(TARGET_SPARC64)
+ defined(TARGET_PARISC) || defined(TARGET_SPARC64) || defined(TARGET_RISCV)
return 4;
#elif defined(TARGET_PPC)
return TARGET_ABI_BITS / 8;
new file mode 100644
@@ -0,0 +1,4 @@
+#include "cpu.h"
+
+#define BIOS_SIZE (4 * 1024 * 1024)
+#define BIOS_FILENAME "riscv_bios.bin"
new file mode 100644
@@ -0,0 +1,14 @@
+#ifndef HW_RISCV_CPUDEVS_H
+#define HW_RISCV_CPUDEVS_H
+/* Definitions for RISCV CPU internal devices. */
+
+/* riscv_board.c */
+uint64_t identity_translate(void *opaque, uint64_t addr);
+
+/* riscv_int.c */
+void cpu_riscv_irq_init_cpu(CPURISCVState *env);
+
+/* cputimer.c */
+void cpu_riscv_clock_init(CPURISCVState *);
+
+#endif
new file mode 100644
@@ -0,0 +1,4 @@
+uint64_t rtc_read(CPURISCVState *env);
+uint64_t rtc_read_with_delta(CPURISCVState *env);
+uint64_t instret_read(CPURISCVState *env);
+inline uint64_t instret_read_with_delta(CPURISCVState *env);
new file mode 100644
@@ -0,0 +1,30 @@
+#ifndef HW_RISCV_FRONTEND_H
+#define HW_RISCV_FRONTEND_H 1
+
+#include "hw/hw.h"
+#include "sysemu/sysemu.h"
+#include "exec/memory.h"
+
+
+#define RV_FSYSCALL_sys_openat 56
+#define RV_FSYSCALL_sys_close 57
+#define RV_FSYSCALL_sys_write 64
+#define RV_FSYSCALL_sys_pread 67
+#define RV_FSYSCALL_sys_exit 93
+#define RV_FSYSCALL_sys_getmainvars 2011
+
+uint64_t sys_openat(HTIFState *htifstate, uint64_t dirfd, uint64_t pname, uint64_t len, uint64_t flags, uint64_t mode);
+
+uint64_t sys_close(HTIFState *htifstate, uint64_t fd);
+
+uint64_t sys_write(HTIFState *htifstate, uint64_t fd, uint64_t pbuf, uint64_t len);
+
+uint64_t sys_pread(HTIFState *htifstate, uint64_t fd, uint64_t pbuf, uint64_t len, uint64_t off);
+
+uint64_t sys_exit(HTIFState *htifstate, uint64_t code);
+
+int handle_frontend_syscall(HTIFState * htifstate, uint64_t payload);
+
+uint64_t sys_getmainvars(HTIFState * htifstate, uint64_t pbuf, uint64_t limit);
+
+#endif
new file mode 100644
@@ -0,0 +1,76 @@
+/*
+ * QEMU RISCV Host Target Interface (HTIF) Emulation
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef HW_RISCV_HTIF_H
+#define HW_RISCV_HTIF_H 1
+
+#include "hw/hw.h"
+#include "sysemu/sysemu.h"
+#include "exec/memory.h"
+
+typedef struct HTIFState HTIFState;
+
+struct HTIFState {
+ int allow_tohost;
+ int fromhost_inprogress;
+
+ hwaddr tohost_addr;
+ hwaddr fromhost_addr;
+ qemu_irq irq; // host interrupt line
+ MemoryRegion io;
+ MemoryRegion* address_space;
+ MemoryRegion* main_mem;
+ void* main_mem_ram_ptr;
+
+ CPURISCVState *env;
+ CharDriverState *chr;
+ uint64_t pending_read;
+
+
+ int block_dev_present;
+ // TODO: eventually move the following to a separate HTIF block device driver
+ const char *block_fname;
+ int block_fd;
+ char *real_name;
+ char *kernel_cmdline; // for sys_getmainvars
+};
+
+typedef struct request_t request_t;
+
+struct request_t
+{
+ uint64_t addr;
+ uint64_t offset;
+ uint64_t size;
+ uint64_t tag;
+};
+
+extern const VMStateDescription vmstate_htif;
+extern const MemoryRegionOps htif_io_ops;
+
+/* legacy pre qom */
+HTIFState *htif_mm_init(MemoryRegion *address_space, hwaddr base,
+ qemu_irq irq, MemoryRegion *main_mem, const char *htifbd_fname,
+ const char *kernel_cmdline, CPURISCVState *env,
+ CharDriverState *chr);
+
+#endif
new file mode 100644
@@ -0,0 +1,10 @@
+#ifndef HW_RISCV_H
+#define HW_RISCV_H
+/* Definitions for riscv board emulation. */
+
+/* Kernels can be configured with 64KB pages */
+#define INITRD_PAGE_MASK (~((1 << 16) - 1))
+
+#include "exec/memory.h"
+
+#endif
new file mode 100644
@@ -0,0 +1,50 @@
+/*
+ * QEMU RISCV Soft Interrupt Emulation
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef HW_RISCV_SOFTINT_H
+#define HW_RISCV_SOFTINT_H 1
+
+#include "hw/hw.h"
+#include "sysemu/sysemu.h"
+#include "exec/memory.h"
+
+typedef struct SoftintState SoftintState;
+
+struct SoftintState {
+ qemu_irq irq; // host interrupt line
+ MemoryRegion io;
+ MemoryRegion* address_space;
+
+ CPURISCVState *env;
+ CharDriverState *chr;
+ char * name;
+};
+
+extern const VMStateDescription vmstate_softint;
+extern const MemoryRegionOps softint_io_ops;
+
+/* legacy pre qom */
+SoftintState *softint_mm_init(MemoryRegion *address_space, hwaddr base,
+ qemu_irq irq, MemoryRegion *main_mem, CPURISCVState *env,
+ const char * name);
+
+#endif
@@ -23,6 +23,7 @@ enum {
QEMU_ARCH_UNICORE32 = (1 << 14),
QEMU_ARCH_MOXIE = (1 << 15),
QEMU_ARCH_TRICORE = (1 << 16),
+ QEMU_ARCH_RISCV = (1 << 17),
};
extern const uint32_t arch_type;
new file mode 100644
@@ -0,0 +1,114 @@
+obj-y += fpu-custom-riscv/f32_add.o
+obj-y += fpu-custom-riscv/f32_classify.o
+obj-y += fpu-custom-riscv/f32_div.o
+obj-y += fpu-custom-riscv/f32_eq.o
+obj-y += fpu-custom-riscv/f32_eq_signaling.o
+obj-y += fpu-custom-riscv/f32_isSignalingNaN.o
+obj-y += fpu-custom-riscv/f32_le.o
+obj-y += fpu-custom-riscv/f32_le_quiet.o
+obj-y += fpu-custom-riscv/f32_lt.o
+obj-y += fpu-custom-riscv/f32_lt_quiet.o
+obj-y += fpu-custom-riscv/f32_mulAdd.o
+obj-y += fpu-custom-riscv/f32_mul.o
+obj-y += fpu-custom-riscv/f32_rem.o
+obj-y += fpu-custom-riscv/f32_roundToInt.o
+obj-y += fpu-custom-riscv/f32_sqrt.o
+obj-y += fpu-custom-riscv/f32_sub.o
+obj-y += fpu-custom-riscv/f32_to_f64.o
+obj-y += fpu-custom-riscv/f32_to_i32.o
+obj-y += fpu-custom-riscv/f32_to_i32_r_minMag.o
+obj-y += fpu-custom-riscv/f32_to_i64.o
+obj-y += fpu-custom-riscv/f32_to_i64_r_minMag.o
+obj-y += fpu-custom-riscv/f32_to_ui32.o
+obj-y += fpu-custom-riscv/f32_to_ui32_r_minMag.o
+obj-y += fpu-custom-riscv/f32_to_ui64.o
+obj-y += fpu-custom-riscv/f32_to_ui64_r_minMag.o
+obj-y += fpu-custom-riscv/f64_add.o
+obj-y += fpu-custom-riscv/f64_classify.o
+obj-y += fpu-custom-riscv/f64_div.o
+obj-y += fpu-custom-riscv/f64_eq.o
+obj-y += fpu-custom-riscv/f64_eq_signaling.o
+obj-y += fpu-custom-riscv/f64_isSignalingNaN.o
+obj-y += fpu-custom-riscv/f64_le.o
+obj-y += fpu-custom-riscv/f64_le_quiet.o
+obj-y += fpu-custom-riscv/f64_lt.o
+obj-y += fpu-custom-riscv/f64_lt_quiet.o
+obj-y += fpu-custom-riscv/f64_mulAdd.o
+obj-y += fpu-custom-riscv/f64_mul.o
+obj-y += fpu-custom-riscv/f64_rem.o
+obj-y += fpu-custom-riscv/f64_roundToInt.o
+obj-y += fpu-custom-riscv/f64_sqrt.o
+obj-y += fpu-custom-riscv/f64_sub.o
+obj-y += fpu-custom-riscv/f64_to_f32.o
+obj-y += fpu-custom-riscv/f64_to_i32.o
+obj-y += fpu-custom-riscv/f64_to_i32_r_minMag.o
+obj-y += fpu-custom-riscv/f64_to_i64.o
+obj-y += fpu-custom-riscv/f64_to_i64_r_minMag.o
+obj-y += fpu-custom-riscv/f64_to_ui32.o
+obj-y += fpu-custom-riscv/f64_to_ui32_r_minMag.o
+obj-y += fpu-custom-riscv/f64_to_ui64.o
+obj-y += fpu-custom-riscv/f64_to_ui64_r_minMag.o
+obj-y += fpu-custom-riscv/i32_to_f32.o
+obj-y += fpu-custom-riscv/i32_to_f64.o
+obj-y += fpu-custom-riscv/i64_to_f32.o
+obj-y += fpu-custom-riscv/i64_to_f64.o
+obj-y += fpu-custom-riscv/s_add128.o
+obj-y += fpu-custom-riscv/s_add192.o
+obj-y += fpu-custom-riscv/s_addMagsF32.o
+obj-y += fpu-custom-riscv/s_addMagsF64.o
+obj-y += fpu-custom-riscv/s_commonNaNToF32UI.o
+obj-y += fpu-custom-riscv/s_commonNaNToF64UI.o
+obj-y += fpu-custom-riscv/s_countLeadingZeros32.o
+obj-y += fpu-custom-riscv/s_countLeadingZeros64.o
+obj-y += fpu-custom-riscv/s_countLeadingZeros8.o
+obj-y += fpu-custom-riscv/s_eq128.o
+obj-y += fpu-custom-riscv/s_estimateDiv128To64.o
+obj-y += fpu-custom-riscv/s_estimateSqrt32.o
+obj-y += fpu-custom-riscv/s_f32UIToCommonNaN.o
+obj-y += fpu-custom-riscv/s_f64UIToCommonNaN.o
+obj-y += fpu-custom-riscv/s_isSigNaNF32UI.o
+obj-y += fpu-custom-riscv/s_isSigNaNF64UI.o
+obj-y += fpu-custom-riscv/s_le128.o
+obj-y += fpu-custom-riscv/s_lt128.o
+obj-y += fpu-custom-riscv/s_mul128By64To192.o
+obj-y += fpu-custom-riscv/s_mul128To256.o
+obj-y += fpu-custom-riscv/s_mul64To128.o
+obj-y += fpu-custom-riscv/s_mulAddF32.o
+obj-y += fpu-custom-riscv/s_mulAddF64.o
+obj-y += fpu-custom-riscv/s_normRoundPackToF32.o
+obj-y += fpu-custom-riscv/s_normRoundPackToF64.o
+obj-y += fpu-custom-riscv/s_normSubnormalF32Sig.o
+obj-y += fpu-custom-riscv/s_normSubnormalF64Sig.o
+obj-y += fpu-custom-riscv/softfloat_raiseFlags.o
+obj-y += fpu-custom-riscv/softfloat_state.o
+obj-y += fpu-custom-riscv/s_propagateNaNF32UI.o
+obj-y += fpu-custom-riscv/s_propagateNaNF64UI.o
+obj-y += fpu-custom-riscv/s_roundPackToF32.o
+obj-y += fpu-custom-riscv/s_roundPackToF64.o
+obj-y += fpu-custom-riscv/s_roundPackToI32.o
+obj-y += fpu-custom-riscv/s_roundPackToI64.o
+obj-y += fpu-custom-riscv/s_roundPackToUI32.o
+obj-y += fpu-custom-riscv/s_roundPackToUI64.o
+obj-y += fpu-custom-riscv/s_shift128ExtraRightJam.o
+obj-y += fpu-custom-riscv/s_shift128RightJam.o
+obj-y += fpu-custom-riscv/s_shift32RightJam.o
+obj-y += fpu-custom-riscv/s_shift64ExtraRightJam.o
+obj-y += fpu-custom-riscv/s_shift64RightJam.o
+obj-y += fpu-custom-riscv/s_shortShift128ExtraRightJam.o
+obj-y += fpu-custom-riscv/s_shortShift128Left.o
+obj-y += fpu-custom-riscv/s_shortShift128Right.o
+obj-y += fpu-custom-riscv/s_shortShift192Left.o
+obj-y += fpu-custom-riscv/s_shortShift32Right1Jam.o
+obj-y += fpu-custom-riscv/s_shortShift64ExtraRightJam.o
+obj-y += fpu-custom-riscv/s_shortShift64RightJam.o
+obj-y += fpu-custom-riscv/s_sub128.o
+obj-y += fpu-custom-riscv/s_sub192.o
+obj-y += fpu-custom-riscv/s_subMagsF32.o
+obj-y += fpu-custom-riscv/s_subMagsF64.o
+obj-y += fpu-custom-riscv/ui32_to_f32.o
+obj-y += fpu-custom-riscv/ui32_to_f64.o
+obj-y += fpu-custom-riscv/ui64_to_f32.o
+obj-y += fpu-custom-riscv/ui64_to_f64.o
+obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += gdbstub.o
+obj-$(CONFIG_SOFTMMU) += machine.o
new file mode 100644
@@ -0,0 +1,17 @@
+Notes for RISCV, updated priv spec version
+-----------------------------------------------
+
+General
+-------
+- fpu-custom-riscv aka softfloat is taken directly from spike (riscv-isa-sim)
+ the current version is from 853391c2bb814451ad88b8dbff2aec8616fc6a12 of
+ spike
+
+
+OLD, left as notes:
+-------------------
+- In include/exec/cpu-defs.h, CPU_TLB_BITS has been set to zero for
+ debugging purposes, increase for performance
+ - this sets the TLBs to only hold one entry
+
+
new file mode 100644
@@ -0,0 +1,86 @@
+/*
+ * QEMU RISC-V CPU
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_RISCV_CPU_QOM_H
+#define QEMU_RISCV_CPU_QOM_H
+
+#include "qom/cpu.h"
+
+#define TYPE_RISCV_CPU "riscv-cpu"
+
+#define RISCV_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(RISCVCPUClass, (klass), TYPE_RISCV_CPU)
+#define RISCV_CPU(obj) \
+ OBJECT_CHECK(RISCVCPU, (obj), TYPE_RISCV_CPU)
+#define RISCV_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(RISCVCPUClass, (obj), TYPE_RISCV_CPU)
+
+/**
+ * RISCVCPUClass:
+ * @parent_realize: The parent class' realize handler.
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A RISCV CPU model.
+ */
+typedef struct RISCVCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ DeviceRealize parent_realize;
+ void (*parent_reset)(CPUState *cpu);
+} RISCVCPUClass;
+
+/**
+ * RISCVCPU:
+ * @env: #CPURISCVState
+ *
+ * A RISCV CPU.
+ */
+typedef struct RISCVCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPURISCVState env;
+} RISCVCPU;
+
+static inline RISCVCPU *riscv_env_get_cpu(CPURISCVState *env)
+{
+ return container_of(env, RISCVCPU, env);
+}
+
+#define ENV_GET_CPU(e) CPU(riscv_env_get_cpu(e))
+
+#define ENV_OFFSET offsetof(RISCVCPU, env)
+
+void riscv_cpu_do_interrupt(CPUState *cpu);
+void riscv_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
+ int flags);
+hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
+void riscv_cpu_do_unaligned_access(CPUState *cs,
+ target_ulong addr, int rw,
+ int is_user, uintptr_t retaddr);
+
+
+#endif
new file mode 100644
@@ -0,0 +1,143 @@
+/*
+ * QEMU RISC-V CPU
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "cpu.h"
+#include "qemu-common.h"
+
+static void riscv_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ env->active_tc.PC = value;
+}
+
+static void riscv_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ env->active_tc.PC = tb->pc;
+}
+
+static bool riscv_cpu_has_work(CPUState *cs)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ bool has_work = false;
+
+ if (cs->interrupt_request & CPU_INTERRUPT_HARD) {
+ int interruptno = cpu_riscv_hw_interrupts_pending(env);
+ if (interruptno + 1) {
+ has_work = true;
+ }
+ }
+
+ return has_work;
+}
+
+static void riscv_cpu_reset(CPUState *s)
+{
+ RISCVCPU *cpu = RISCV_CPU(s);
+ RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
+ CPURISCVState *env = &cpu->env;
+
+ mcc->parent_reset(s);
+ tlb_flush(s, 1);
+ cpu_state_reset(env);
+}
+
+static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) {
+ info->print_insn = print_insn_riscv;
+}
+
+static void riscv_cpu_realizefn(DeviceState *dev, Error **errp)
+{
+ CPUState *cs = CPU(dev);
+ RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
+
+ cpu_reset(cs);
+ qemu_init_vcpu(cs);
+
+ mcc->parent_realize(dev, errp);
+}
+
+static void riscv_cpu_initfn(Object *obj)
+{
+ CPUState *cs = CPU(obj);
+ RISCVCPU *cpu = RISCV_CPU(obj);
+ CPURISCVState *env = &cpu->env;
+
+ cs->env_ptr = env;
+ cpu_exec_init(cs, &error_abort);
+
+ if (tcg_enabled()) {
+ riscv_tcg_init();
+ }
+}
+
+static void riscv_cpu_class_init(ObjectClass *c, void *data)
+{
+ RISCVCPUClass *mcc = RISCV_CPU_CLASS(c);
+ CPUClass *cc = CPU_CLASS(c);
+ DeviceClass *dc = DEVICE_CLASS(c);
+
+ mcc->parent_realize = dc->realize;
+ dc->realize = riscv_cpu_realizefn;
+
+ mcc->parent_reset = cc->reset;
+ cc->reset = riscv_cpu_reset;
+
+ cc->has_work = riscv_cpu_has_work;
+ cc->do_interrupt = riscv_cpu_do_interrupt;
+ cc->cpu_exec_interrupt = riscv_cpu_exec_interrupt;
+ cc->dump_state = riscv_cpu_dump_state;
+ cc->set_pc = riscv_cpu_set_pc;
+ cc->synchronize_from_tb = riscv_cpu_synchronize_from_tb;
+ cc->gdb_read_register = riscv_cpu_gdb_read_register;
+ cc->gdb_write_register = riscv_cpu_gdb_write_register;
+#ifdef CONFIG_USER_ONLY
+ cc->handle_mmu_fault = riscv_cpu_handle_mmu_fault;
+#else
+ cc->do_unassigned_access = riscv_cpu_unassigned_access;
+ cc->do_unaligned_access = riscv_cpu_do_unaligned_access;
+ cc->get_phys_page_debug = riscv_cpu_get_phys_page_debug;
+ // cc->vmsd = &vmstate_riscv_cpu;
+#endif
+
+ cc->disas_set_info = riscv_cpu_disas_set_info;
+ cc->gdb_num_core_regs = 132;
+ cc->gdb_stop_before_watchpoint = true;
+}
+
+static const TypeInfo riscv_cpu_type_info = {
+ .name = TYPE_RISCV_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(RISCVCPU),
+ .instance_init = riscv_cpu_initfn,
+ .abstract = false,
+ .class_size = sizeof(RISCVCPUClass),
+ .class_init = riscv_cpu_class_init,
+};
+
+static void riscv_cpu_register_types(void)
+{
+ type_register_static(&riscv_cpu_type_info);
+}
+
+type_init(riscv_cpu_register_types)
new file mode 100644
@@ -0,0 +1,449 @@
+#if !defined (__RISCV_CPU_H__)
+#define __RISCV_CPU_H__
+
+//#define DEBUG_OP
+
+#define TARGET_HAS_ICE 1
+
+#define ELF_MACHINE EM_RISCV
+
+#define CPUArchState struct CPURISCVState
+
+#define RISCV_START_PC 0x200
+
+#define ALIGNED_ONLY
+
+#include "config.h"
+#include "qemu-common.h"
+#include "riscv-defs.h"
+#include "exec/cpu-defs.h"
+
+#define TRANSLATE_FAIL -1
+#define TRANSLATE_SUCCESS 0
+
+#define NB_MMU_MODES 4
+
+struct CPURISCVState;
+
+#define PGSHIFT 12
+
+// uncomment for lots of debug printing
+//#define RISCV_DEBUG_PRINT
+
+#define get_field(reg, mask) (((reg) & (target_ulong)(mask)) / ((mask) & ~((mask) << 1)))
+#define set_field(reg, mask, val) (((reg) & ~(target_ulong)(mask)) | (((target_ulong)(val) * ((mask) & ~((mask) << 1))) & (target_ulong)(mask)))
+
+
+#define FP_RD_NE 0
+#define FP_RD_0 1
+#define FP_RD_DN 2
+#define FP_RD_UP 3
+#define FP_RD_NMM 4
+
+#define FSR_RD_SHIFT 5
+#define FSR_RD (0x7 << FSR_RD_SHIFT)
+
+#define FPEXC_NX 0x01
+#define FPEXC_UF 0x02
+#define FPEXC_OF 0x04
+#define FPEXC_DZ 0x08
+#define FPEXC_NV 0x10
+
+#define FSR_AEXC_SHIFT 0
+#define FSR_NVA (FPEXC_NV << FSR_AEXC_SHIFT)
+#define FSR_OFA (FPEXC_OF << FSR_AEXC_SHIFT)
+#define FSR_UFA (FPEXC_UF << FSR_AEXC_SHIFT)
+#define FSR_DZA (FPEXC_DZ << FSR_AEXC_SHIFT)
+#define FSR_NXA (FPEXC_NX << FSR_AEXC_SHIFT)
+#define FSR_AEXC (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA)
+
+#define NEW_CSR_FFLAGS 0x1
+#define NEW_CSR_FRM 0x2
+#define NEW_CSR_FCSR 0x3
+#define NEW_CSR_CYCLE 0xc00
+#define NEW_CSR_TIME 0xc01
+#define NEW_CSR_INSTRET 0xc02
+#define NEW_CSR_STATS 0xc0
+#define NEW_CSR_UARCH0 0xcc0
+#define NEW_CSR_UARCH1 0xcc1
+#define NEW_CSR_UARCH2 0xcc2
+#define NEW_CSR_UARCH3 0xcc3
+#define NEW_CSR_UARCH4 0xcc4
+#define NEW_CSR_UARCH5 0xcc5
+#define NEW_CSR_UARCH6 0xcc6
+#define NEW_CSR_UARCH7 0xcc7
+#define NEW_CSR_UARCH8 0xcc8
+#define NEW_CSR_UARCH9 0xcc9
+#define NEW_CSR_UARCH10 0xcca
+#define NEW_CSR_UARCH11 0xccb
+#define NEW_CSR_UARCH12 0xccc
+#define NEW_CSR_UARCH13 0xccd
+#define NEW_CSR_UARCH14 0xcce
+#define NEW_CSR_UARCH15 0xccf
+#define NEW_CSR_SSTATUS 0x100
+#define NEW_CSR_STVEC 0x101
+#define NEW_CSR_SIE 0x104
+#define NEW_CSR_SSCRATCH 0x140
+#define NEW_CSR_SEPC 0x141
+#define NEW_CSR_SIP 0x144
+#define NEW_CSR_SPTBR 0x180
+#define NEW_CSR_SASID 0x181
+#define NEW_CSR_CYCLEW 0x900
+#define NEW_CSR_TIMEW 0x901
+#define NEW_CSR_INSTRETW 0x902
+#define NEW_CSR_STIME 0xd01
+#define NEW_CSR_SCAUSE 0xd42
+#define NEW_CSR_SBADADDR 0xd43
+#define NEW_CSR_STIMEW 0xa01
+#define NEW_CSR_MSTATUS 0x300
+#define NEW_CSR_MTVEC 0x301
+#define NEW_CSR_MTDELEG 0x302
+#define NEW_CSR_MIE 0x304
+#define NEW_CSR_MTIMECMP 0x321
+#define NEW_CSR_MSCRATCH 0x340
+#define NEW_CSR_MEPC 0x341
+#define NEW_CSR_MCAUSE 0x342
+#define NEW_CSR_MBADADDR 0x343
+#define NEW_CSR_MIP 0x344
+#define NEW_CSR_MTIME 0x701
+#define NEW_CSR_MCPUID 0xf00
+#define NEW_CSR_MIMPID 0xf01
+#define NEW_CSR_MHARTID 0xf10
+#define NEW_CSR_MTOHOST 0x780
+#define NEW_CSR_MFROMHOST 0x781
+#define NEW_CSR_MRESET 0x782
+#define NEW_CSR_MIPI 0x783
+#define NEW_CSR_MIOBASE 0x784
+#define NEW_CSR_CYCLEH 0xc80
+#define NEW_CSR_TIMEH 0xc81
+#define NEW_CSR_INSTRETH 0xc82
+#define NEW_CSR_CYCLEHW 0x980
+#define NEW_CSR_TIMEHW 0x981
+#define NEW_CSR_INSTRETHW 0x982
+#define NEW_CSR_STIMEH 0xd81
+#define NEW_CSR_STIMEHW 0xa81
+#define NEW_CSR_MTIMECMPH 0x361
+#define NEW_CSR_MTIMEH 0x741
+
+
+// RISCV Exception Codes
+#define EXCP_NONE -1 // not a real RISCV exception code
+#define NEW_RISCV_EXCP_INST_ADDR_MIS 0x0
+#define NEW_RISCV_EXCP_INST_ACCESS_FAULT 0x1
+#define NEW_RISCV_EXCP_ILLEGAL_INST 0x2
+#define NEW_RISCV_EXCP_BREAKPOINT 0x3
+#define NEW_RISCV_EXCP_LOAD_ADDR_MIS 0x4
+#define NEW_RISCV_EXCP_LOAD_ACCESS_FAULT 0x5
+#define NEW_RISCV_EXCP_STORE_AMO_ADDR_MIS 0x6
+#define NEW_RISCV_EXCP_STORE_AMO_ACCESS_FAULT 0x7
+#define NEW_RISCV_EXCP_U_ECALL 0x8 // for convenience, report all
+ // ECALLs as this, handler fixes
+#define NEW_RISCV_EXCP_S_ECALL 0x9
+#define NEW_RISCV_EXCP_H_ECALL 0xa
+#define NEW_RISCV_EXCP_M_ECALL 0xb
+// >= 12 reserved
+// interrupts not listed here
+
+#define IS_RV_INTERRUPT(ival) (ival & (0x1 << 31))
+
+#define MSTATUS_IE 0x00000001
+#define MSTATUS_PRV 0x00000006
+#define MSTATUS_IE1 0x00000008
+#define MSTATUS_PRV1 0x00000030
+#define MSTATUS_IE2 0x00000040
+#define MSTATUS_PRV2 0x00000180
+#define MSTATUS_IE3 0x00000200
+#define MSTATUS_PRV3 0x00000C00
+#define MSTATUS_FS 0x00003000
+#define MSTATUS_XS 0x0000C000
+#define MSTATUS_MPRV 0x00010000
+#define MSTATUS_VM 0x003E0000
+#define MSTATUS32_SD 0x80000000
+#define MSTATUS64_SD 0x8000000000000000
+
+#define SSTATUS_IE 0x00000001
+#define SSTATUS_PIE 0x00000008
+#define SSTATUS_PS 0x00000010
+#define SSTATUS_FS 0x00003000
+#define SSTATUS_XS 0x0000C000
+#define SSTATUS_MPRV 0x00010000
+#define SSTATUS_TIE 0x01000000
+#define SSTATUS32_SD 0x80000000
+#define SSTATUS64_SD 0x8000000000000000
+
+#define MIP_SSIP 0x00000002
+#define MIP_HSIP 0x00000004
+#define MIP_MSIP 0x00000008
+#define MIP_STIP 0x00000020
+#define MIP_HTIP 0x00000040
+#define MIP_MTIP 0x00000080
+
+#define SIP_SSIP MIP_SSIP
+#define SIP_STIP MIP_STIP
+
+#define PRV_U 0
+#define PRV_S 1
+#define PRV_H 2
+#define PRV_M 3
+
+#define VM_MBARE 0
+#define VM_MBB 1
+#define VM_MBBID 2
+#define VM_SV32 8
+#define VM_SV39 9
+#define VM_SV48 10
+
+#define UA_RV32 0
+#define UA_RV64 4
+#define UA_RV128 8
+
+#define IRQ_SOFT 0
+#define IRQ_TIMER 1
+#define IRQ_HOST 2
+#define IRQ_COP 3
+
+#define IMPL_ROCKET 1
+
+#define DEFAULT_MTVEC 0x100
+
+// page table entry (PTE) fields
+#define PTE_V 0x001 // Valid
+#define PTE_TYPE 0x01E // Type
+#define PTE_R 0x020 // Referenced
+#define PTE_D 0x040 // Dirty
+#define PTE_SOFT 0x380 // Reserved for Software
+
+#define PTE_TYPE_TABLE 0x00
+#define PTE_TYPE_TABLE_GLOBAL 0x02
+#define PTE_TYPE_URX_SR 0x04
+#define PTE_TYPE_URWX_SRW 0x06
+#define PTE_TYPE_UR_SR 0x08
+#define PTE_TYPE_URW_SRW 0x0A
+#define PTE_TYPE_URX_SRX 0x0C
+#define PTE_TYPE_URWX_SRWX 0x0E
+#define PTE_TYPE_SR 0x10
+#define PTE_TYPE_SRW 0x12
+#define PTE_TYPE_SRX 0x14
+#define PTE_TYPE_SRWX 0x16
+#define PTE_TYPE_SR_GLOBAL 0x18
+#define PTE_TYPE_SRW_GLOBAL 0x1A
+#define PTE_TYPE_SRX_GLOBAL 0x1C
+#define PTE_TYPE_SRWX_GLOBAL 0x1E
+
+#define PTE_PPN_SHIFT 10
+
+#define PTE_TABLE(PTE) ((0x0000000AU >> ((PTE) & 0x1F)) & 1)
+#define PTE_UR(PTE) ((0x0000AAA0U >> ((PTE) & 0x1F)) & 1)
+#define PTE_UW(PTE) ((0x00008880U >> ((PTE) & 0x1F)) & 1)
+#define PTE_UX(PTE) ((0x0000A0A0U >> ((PTE) & 0x1F)) & 1)
+#define PTE_SR(PTE) ((0xAAAAAAA0U >> ((PTE) & 0x1F)) & 1)
+#define PTE_SW(PTE) ((0x88888880U >> ((PTE) & 0x1F)) & 1)
+#define PTE_SX(PTE) ((0xA0A0A000U >> ((PTE) & 0x1F)) & 1)
+
+#define PTE_CHECK_PERM(PTE, SUPERVISOR, STORE, FETCH) \
+ ((STORE) ? ((SUPERVISOR) ? PTE_SW(PTE) : PTE_UW(PTE)) : \
+ (FETCH) ? ((SUPERVISOR) ? PTE_SX(PTE) : PTE_UX(PTE)) : \
+ ((SUPERVISOR) ? PTE_SR(PTE) : PTE_UR(PTE)))
+
+typedef struct riscv_def_t riscv_def_t;
+
+typedef struct TCState TCState;
+struct TCState {
+ target_ulong gpr[32];
+ target_ulong fpr[32];
+ target_ulong PC;
+ target_ulong load_reservation;
+};
+
+typedef struct CPURISCVState CPURISCVState;
+struct CPURISCVState {
+ TCState active_tc;
+ uint32_t current_tc;
+ uint32_t SEGBITS;
+ uint32_t PABITS;
+
+ uint64_t csr[4096]; // RISCV CSR registers
+
+ /* QEMU */
+ CPU_COMMON
+
+ /* Fields from here on are preserved across CPU reset. */
+ const riscv_def_t *cpu_model;
+ size_t memsize;
+ void *irq[8];
+ QEMUTimer *timer; /* Internal timer */
+};
+
+#include "cpu-qom.h"
+
+#if !defined(CONFIG_USER_ONLY)
+void riscv_cpu_unassigned_access(CPUState *cpu, hwaddr addr, bool is_write,
+ bool is_exec, int unused, unsigned size);
+#endif
+
+void riscv_cpu_list (FILE *f, fprintf_function cpu_fprintf);
+
+#define cpu_exec cpu_riscv_exec
+#define cpu_signal_handler cpu_riscv_signal_handler
+#define cpu_list riscv_cpu_list
+
+#define CPU_SAVE_VERSION 3
+
+static inline int cpu_mmu_index (CPURISCVState *env, bool ifetch)
+{
+ int mode = get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS_PRV);
+
+ // This should only apply to non-instruction fetches
+ // FIXED, but untested, so leave the print/exit
+ if (!ifetch && get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS_MPRV)) {
+ printf("USED 0 cpu_mmu_index\n");
+ exit(1);
+ mode = get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS_PRV1);
+ }
+ if (get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS_VM) == VM_MBARE) {
+ mode = PRV_M;
+ }
+
+ return mode;
+}
+
+/*
+ * Return RISC-V IRQ number if an interrupt should be taken, else -1.
+ * Used in cpu-exec.c
+ */
+static inline int cpu_riscv_hw_interrupts_pending(CPURISCVState *env)
+{
+
+ int priv = get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS_PRV);
+ int ie = get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS_IE);
+ target_ulong interrupts = env->csr[NEW_CSR_MIE] & env->csr[NEW_CSR_MIP];
+
+ #ifdef RISCV_DEBUG_PRINT
+ printf("checking interrupts: ie %d, priv %d, interrupts %ld\n", ie, priv,
+ interrupts);
+ #endif
+
+ if (priv < PRV_M || (priv == PRV_M && ie)) {
+ if (interrupts & MIP_MSIP) {
+ #ifdef RISCV_DEBUG_PRINT
+ fprintf(stderr, "taking soft interrupt M\n");
+ #endif
+
+ // no irq to lower, that is done by the CPU
+ return IRQ_SOFT;
+ }
+
+ if (interrupts & MIP_MTIP) {
+ #ifdef RISCV_DEBUG_PRINT
+ fprintf(stderr, "taking timer interrupt M\n");
+ #endif
+
+ // we're handing it to the cpu now, so get rid of the qemu irq
+ qemu_irq_lower(env->irq[7]); // get rid of the irq request
+ return IRQ_TIMER;
+ }
+
+ if (env->csr[NEW_CSR_MFROMHOST]) {
+ #ifdef RISCV_DEBUG_PRINT
+ fprintf(stderr, "taking host interrupt\n");
+ #endif
+
+ // we're handing it to the cpu now, so get rid of the qemu irq
+ qemu_irq_lower(env->irq[4]); // get rid of the irq request
+ return IRQ_HOST;
+ }
+
+ }
+
+ if (priv < PRV_S || (priv == PRV_S && ie)) {
+ if (interrupts & MIP_SSIP) {
+ #ifdef RISCV_DEBUG_PRINT
+ fprintf(stderr, "taking soft interrupt S\n");
+ #endif
+
+ // no irq to lower, that is done by the CPU
+ return IRQ_SOFT;
+ }
+
+ if (interrupts & MIP_STIP) {
+ #ifdef RISCV_DEBUG_PRINT
+ fprintf(stderr, "taking timer interrupt S\n");
+ #endif
+
+ // no irq to lower, that is done by the CPU
+ return IRQ_TIMER;
+ }
+ }
+
+ // indicates no pending interrupt to handler in cpu-exec.c
+ return -1;
+}
+
+#include "exec/cpu-all.h"
+
+int cpu_riscv_exec(CPUState *cpu);
+void riscv_tcg_init(void);
+RISCVCPU *cpu_riscv_init(const char *cpu_model);
+int cpu_riscv_signal_handler(int host_signum, void *pinfo, void *puc);
+
+#define cpu_init(cpu_model) CPU(cpu_riscv_init(cpu_model))
+
+void cpu_state_reset(CPURISCVState *s);
+
+/* hw/riscv/cputimer.c */
+uint64_t cpu_riscv_get_cycle (CPURISCVState *env);
+uint32_t cpu_riscv_get_random (CPURISCVState *env);
+void cpu_riscv_store_compare (CPURISCVState *env, uint64_t value);
+void cpu_riscv_start_count(CPURISCVState *env);
+
+
+void cpu_riscv_store_timew(CPURISCVState *env, uint64_t val_to_write);
+uint64_t cpu_riscv_read_mtime(CPURISCVState *env);
+uint64_t cpu_riscv_read_stime(CPURISCVState *env);
+uint64_t cpu_riscv_read_time(CPURISCVState *env);
+
+void cpu_riscv_store_instretw(CPURISCVState *env, uint64_t val_to_write);
+uint64_t cpu_riscv_read_instretw(CPURISCVState *env);
+
+/* hw/riscv/riscv_int.c */
+void cpu_riscv_soft_irq(CPURISCVState *env, int irq, int level);
+
+/* helper.c */
+int riscv_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
+ int mmu_idx);
+#if !defined(CONFIG_USER_ONLY)
+hwaddr cpu_riscv_translate_address (CPURISCVState *env, target_ulong address,
+ int rw);
+#endif
+
+static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
+ target_ulong *cs_base, int *flags)
+{
+ *pc = env->active_tc.PC;
+ *cs_base = 0;
+ *flags = 0; // necessary to avoid compiler warning
+}
+
+target_ulong push_priv_stack(target_ulong start_mstatus);
+target_ulong pop_priv_stack(target_ulong start_mstatus);
+
+#ifndef CONFIG_USER_ONLY
+void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
+ target_ulong csrno);
+target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno);
+inline void cpu_riscv_tlb_flush (CPURISCVState *env, int flush_global);
+#endif
+
+#define RISCV_RM ({ if(rm == 7) rm = env->csr[NEW_CSR_FRM]; \
+ /* TODO: throw trap for rm > 4 */ \
+ rm; })
+
+#define set_fp_exceptions ({ env->csr[NEW_CSR_FFLAGS] |= softfloat_exceptionFlags;\
+ softfloat_exceptionFlags = 0; })
+
+void validate_csr(CPURISCVState *env, uint64_t which, uint64_t write, uint64_t
+ new_pc);
+
+#include "exec/exec-all.h"
+
+#endif /* !defined (__RISCV_CPU_H__) */
new file mode 100755
@@ -0,0 +1,40 @@
+
+/*============================================================================
+
+*** FIX.
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2b.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+/*----------------------------------------------------------------------------
+| Underflow tininess-detection mode, statically initialized to default value.
+| (The declaration in `softfloat.h' must match the `int8' type here.)
+*----------------------------------------------------------------------------*/
+bool float_detectTininess = float_tininess_afterRounding;
+
new file mode 100755
@@ -0,0 +1,379 @@
+
+/*============================================================================
+
+*** FIX.
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2b.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+/*----------------------------------------------------------------------------
+| Internal canonical NaN format.
+*----------------------------------------------------------------------------*/
+*** COMMON
+typedef struct {
+ flag sign;
+ uint128_t bits;
+} commonNaNT;
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated single-precision NaN.
+*----------------------------------------------------------------------------*/
+#define float32Bits_defaultNaN 0xFFC00000
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point value `a' is a NaN;
+| otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+*** COMMON
+#define softfloat_isNaNFloat32Bits( a ) ( 0xFF000000 < (uint32_t) ( a )<<1 )
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point value `a' is a signaling
+| NaN; otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+inline bool softfloat_isSigNaNFloat32Bits( uint32_t a )
+ { return ( ( a>>22 & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); }
+
+/*----------------------------------------------------------------------------
+*----------------------------------------------------------------------------*/
+commonNaNT softfloat_NaNFromFloat32Bits( uint32_t );
+uint32_t softfloat_float32BitsFromNaN( commonNaNT );
+uint32_t softfloat_propNaNFloat32Bits( uint32_t, uint32_t );
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated double-precision NaN.
+*----------------------------------------------------------------------------*/
+#define float64Bits_defaultNaN 0xFFF8000000000000
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point value `a' is a NaN;
+| otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+*** COMMON
+#define softfloat_isNaNFloat64Bits( a ) ( 0xFFE0000000000000 < (uint64_t) ( a )<<1 )
+
+
+
+
+
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point value `a' is a signaling
+| NaN; otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+
+flag float64_is_signaling_nan( float64 a )
+{
+
+ return
+ ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
+ && ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the double-precision floating-point NaN
+| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+| exception is raised.
+*----------------------------------------------------------------------------*/
+
+static commonNaNT float64ToCommonNaN( float64 a )
+{
+ commonNaNT z;
+
+ if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = a>>63;
+ z.low = 0;
+ z.high = a<<12;
+ return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the canonical NaN `a' to the double-
+| precision floating-point format.
+*----------------------------------------------------------------------------*/
+
+static float64 commonNaNToFloat64( commonNaNT a )
+{
+
+ return
+ ( ( (bits64) a.sign )<<63 )
+ | LIT64( 0x7FF8000000000000 )
+ | ( a.high>>12 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Takes two double-precision floating-point values `a' and `b', one of which
+| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+| signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+
+static float64 propagateFloat64NaN( float64 a, float64 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = float64_is_nan( a );
+ aIsSignalingNaN = float64_is_signaling_nan( a );
+ bIsNaN = float64_is_nan( b );
+ bIsSignalingNaN = float64_is_signaling_nan( b );
+ a |= LIT64( 0x0008000000000000 );
+ b |= LIT64( 0x0008000000000000 );
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsSignalingNaN ) {
+ if ( bIsSignalingNaN ) goto returnLargerSignificand;
+ return bIsNaN ? b : a;
+ }
+ else if ( aIsNaN ) {
+ if ( bIsSignalingNaN | ! bIsNaN ) return a;
+ returnLargerSignificand:
+ if ( (bits64) ( a<<1 ) < (bits64) ( b<<1 ) ) return b;
+ if ( (bits64) ( b<<1 ) < (bits64) ( a<<1 ) ) return a;
+ return ( a < b ) ? a : b;
+ }
+ else {
+ return b;
+ }
+
+}
+
+#ifdef FLOATX80
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated extended double-precision NaN. The
+| `high' and `low' values hold the most- and least-significant bits,
+| respectively.
+*----------------------------------------------------------------------------*/
+#define floatx80_default_nan_high 0xFFFF
+#define floatx80_default_nan_low LIT64( 0xC000000000000000 )
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is a
+| NaN; otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+
+flag floatx80_is_nan( floatx80 a )
+{
+
+ return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the extended double-precision floating-point value `a' is a
+| signaling NaN; otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+
+flag floatx80_is_signaling_nan( floatx80 a )
+{
+ bits64 aLow;
+
+ aLow = a.low & ~ LIT64( 0x4000000000000000 );
+ return
+ ( ( a.high & 0x7FFF ) == 0x7FFF )
+ && (bits64) ( aLow<<1 )
+ && ( a.low == aLow );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the extended double-precision floating-
+| point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
+| invalid exception is raised.
+*----------------------------------------------------------------------------*/
+
+static commonNaNT floatx80ToCommonNaN( floatx80 a )
+{
+ commonNaNT z;
+
+ if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = a.high>>15;
+ z.low = 0;
+ z.high = a.low<<1;
+ return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the canonical NaN `a' to the extended
+| double-precision floating-point format.
+*----------------------------------------------------------------------------*/
+
+static floatx80 commonNaNToFloatx80( commonNaNT a )
+{
+ floatx80 z;
+
+ z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
+ z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
+ return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Takes two extended double-precision floating-point values `a' and `b', one
+| of which is a NaN, and returns the appropriate NaN result. If either `a' or
+| `b' is a signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+
+static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = floatx80_is_nan( a );
+ aIsSignalingNaN = floatx80_is_signaling_nan( a );
+ bIsNaN = floatx80_is_nan( b );
+ bIsSignalingNaN = floatx80_is_signaling_nan( b );
+ a.low |= LIT64( 0xC000000000000000 );
+ b.low |= LIT64( 0xC000000000000000 );
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsSignalingNaN ) {
+ if ( bIsSignalingNaN ) goto returnLargerSignificand;
+ return bIsNaN ? b : a;
+ }
+ else if ( aIsNaN ) {
+ if ( bIsSignalingNaN | ! bIsNaN ) return a;
+ returnLargerSignificand:
+ if ( a.low < b.low ) return b;
+ if ( b.low < a.low ) return a;
+ return ( a.high < b.high ) ? a : b;
+ }
+ else {
+ return b;
+ }
+
+}
+
+#endif
+
+#ifdef FLOAT128
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated quadruple-precision NaN. The `high' and
+| `low' values hold the most- and least-significant bits, respectively.
+*----------------------------------------------------------------------------*/
+#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
+#define float128_default_nan_low LIT64( 0x0000000000000000 )
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
+| otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+
+flag float128_is_nan( float128 a )
+{
+
+ return
+ ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
+ && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the quadruple-precision floating-point value `a' is a
+| signaling NaN; otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+
+flag float128_is_signaling_nan( float128 a )
+{
+
+ return
+ ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
+ && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the quadruple-precision floating-point NaN
+| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+| exception is raised.
+*----------------------------------------------------------------------------*/
+
+static commonNaNT float128ToCommonNaN( float128 a )
+{
+ commonNaNT z;
+
+ if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
+ z.sign = a.high>>63;
+ shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
+ return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the canonical NaN `a' to the quadruple-
+| precision floating-point format.
+*----------------------------------------------------------------------------*/
+
+static float128 commonNaNToFloat128( commonNaNT a )
+{
+ float128 z;
+
+ shift128Right( a.high, a.low, 16, &z.high, &z.low );
+ z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
+ return z;
+
+}
+
+/*----------------------------------------------------------------------------
+| Takes two quadruple-precision floating-point values `a' and `b', one of
+| which is a NaN, and returns the appropriate NaN result. If either `a' or
+| `b' is a signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+
+static float128 propagateFloat128NaN( float128 a, float128 b )
+{
+ flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
+
+ aIsNaN = float128_is_nan( a );
+ aIsSignalingNaN = float128_is_signaling_nan( a );
+ bIsNaN = float128_is_nan( b );
+ bIsSignalingNaN = float128_is_signaling_nan( b );
+ a.high |= LIT64( 0x0000800000000000 );
+ b.high |= LIT64( 0x0000800000000000 );
+ if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
+ if ( aIsSignalingNaN ) {
+ if ( bIsSignalingNaN ) goto returnLargerSignificand;
+ return bIsNaN ? b : a;
+ }
+ else if ( aIsNaN ) {
+ if ( bIsSignalingNaN | ! bIsNaN ) return a;
+ returnLargerSignificand:
+ if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b;
+ if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a;
+ return ( a.high < b.high ) ? a : b;
+ }
+ else {
+ return b;
+ }
+
+}
+
+#endif
+
new file mode 100755
@@ -0,0 +1,38 @@
+
+/*============================================================================
+
+*** FIX.
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2b.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+/*----------------------------------------------------------------------------
+*----------------------------------------------------------------------------*/
+#define LITTLEENDIAN
+
new file mode 100755
@@ -0,0 +1,17 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "specialize.h"
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the canonical NaN `a' to the single-
+| precision floating-point format.
+*----------------------------------------------------------------------------*/
+
+uint_fast32_t softfloat_commonNaNToF32UI( struct commonNaN a )
+{
+
+ return (uint_fast32_t) a.sign<<31 | 0x7FC00000 | a.v64>>41;
+
+}
+
new file mode 100755
@@ -0,0 +1,19 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "specialize.h"
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the canonical NaN `a' to the double-
+| precision floating-point format.
+*----------------------------------------------------------------------------*/
+
+uint_fast64_t softfloat_commonNaNToF64UI( struct commonNaN a )
+{
+
+ return
+ (uint_fast64_t) a.sign<<63 | UINT64_C( 0x7FF8000000000000 )
+ | a.v64>>12;
+
+}
+
new file mode 100755
@@ -0,0 +1,25 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the single-precision floating-point NaN
+| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+| exception is raised.
+*----------------------------------------------------------------------------*/
+struct commonNaN softfloat_f32UIToCommonNaN( uint_fast32_t uiA )
+{
+ struct commonNaN z;
+
+ if ( softfloat_isSigNaNF32UI( uiA ) ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ }
+ z.sign = uiA>>31;
+ z.v64 = (uint_fast64_t) uiA<<41;
+ z.v0 = 0;
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,25 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the double-precision floating-point NaN
+| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+| exception is raised.
+*----------------------------------------------------------------------------*/
+struct commonNaN softfloat_f64UIToCommonNaN( uint_fast64_t uiA )
+{
+ struct commonNaN z;
+
+ if ( softfloat_isSigNaNF64UI( uiA ) ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ }
+ z.sign = uiA>>63;
+ z.v64 = uiA<<12;
+ z.v0 = 0;
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,13 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "specialize.h"
+
+bool softfloat_isSigNaNF32UI( uint_fast32_t ui )
+{
+
+ return ( ( ui>>22 & 0x1FF ) == 0x1FE ) && ( ui & 0x003FFFFF );
+
+}
+
new file mode 100755
@@ -0,0 +1,15 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "specialize.h"
+
+bool softfloat_isSigNaNF64UI( uint_fast64_t ui )
+{
+
+ return
+ ( ( ui>>51 & 0xFFF ) == 0xFFE )
+ && ( ui & UINT64_C( 0x0007FFFFFFFFFFFF ) );
+
+}
+
new file mode 100755
@@ -0,0 +1,55 @@
+
+/*** UPDATE COMMENTS. ***/
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+/*----------------------------------------------------------------------------
+| Takes two single-precision floating-point values `a' and `b', one of which
+| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+| signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+
+uint_fast32_t
+ softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB )
+{
+ bool isNaNA, isSigNaNA, isNaNB, isSigNaNB;
+ uint_fast32_t uiMagA, uiMagB;
+
+ /*------------------------------------------------------------------------
+ *------------------------------------------------------------------------*/
+ isNaNA = isNaNF32UI( uiA );
+ isSigNaNA = softfloat_isSigNaNF32UI( uiA );
+ isNaNB = isNaNF32UI( uiB );
+ isSigNaNB = softfloat_isSigNaNF32UI( uiB );
+ /*------------------------------------------------------------------------
+ | Make NaNs non-signaling.
+ *------------------------------------------------------------------------*/
+ uiA |= 0x00400000;
+ uiB |= 0x00400000;
+ /*------------------------------------------------------------------------
+ *------------------------------------------------------------------------*/
+ if ( isSigNaNA | isSigNaNB ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ }
+ if ( isSigNaNA ) {
+ if ( isSigNaNB ) goto returnLargerSignificand;
+ return isNaNB ? uiB : uiA;
+ } else if ( isNaNA ) {
+ if ( isSigNaNB || ! isNaNB ) return uiA;
+ returnLargerSignificand:
+ uiMagA = uiA<<1;
+ uiMagB = uiB<<1;
+ if ( uiMagA < uiMagB ) return uiB;
+ if ( uiMagB < uiMagA ) return uiA;
+ return ( uiA < uiB ) ? uiA : uiB;
+ } else {
+ return uiB;
+ }
+
+}
+
new file mode 100755
@@ -0,0 +1,55 @@
+
+/*** UPDATE COMMENTS. ***/
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+/*----------------------------------------------------------------------------
+| Takes two double-precision floating-point values `a' and `b', one of which
+| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+| signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+
+uint_fast64_t
+ softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB )
+{
+ bool isNaNA, isSigNaNA, isNaNB, isSigNaNB;
+ uint_fast64_t uiMagA, uiMagB;
+
+ /*------------------------------------------------------------------------
+ *------------------------------------------------------------------------*/
+ isNaNA = isNaNF64UI( uiA );
+ isSigNaNA = softfloat_isSigNaNF64UI( uiA );
+ isNaNB = isNaNF64UI( uiB );
+ isSigNaNB = softfloat_isSigNaNF64UI( uiB );
+ /*------------------------------------------------------------------------
+ | Make NaNs non-signaling.
+ *------------------------------------------------------------------------*/
+ uiA |= UINT64_C( 0x0008000000000000 );
+ uiB |= UINT64_C( 0x0008000000000000 );
+ /*------------------------------------------------------------------------
+ *------------------------------------------------------------------------*/
+ if ( isSigNaNA | isSigNaNB ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ }
+ if ( isSigNaNA ) {
+ if ( isSigNaNB ) goto returnLargerSignificand;
+ return isNaNB ? uiB : uiA;
+ } else if ( isNaNA ) {
+ if ( isSigNaNB || ! isNaNB ) return uiA;
+ returnLargerSignificand:
+ uiMagA = uiA & UINT64_C( 0x7FFFFFFFFFFFFFFF );
+ uiMagB = uiB & UINT64_C( 0x7FFFFFFFFFFFFFFF );
+ if ( uiMagA < uiMagB ) return uiB;
+ if ( uiMagB < uiMagA ) return uiA;
+ return ( uiA < uiB ) ? uiA : uiB;
+ } else {
+ return uiB;
+ }
+
+}
+
new file mode 100755
@@ -0,0 +1,51 @@
+
+/*============================================================================
+
+*** FIX.
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2b.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+#include "platform.h"
+#include "softfloat.h"
+
+/*----------------------------------------------------------------------------
+| Raises the exceptions specified by `flags'. Floating-point traps can be
+| defined here if desired. It is currently not possible for such a trap
+| to substitute a result value. If traps are not implemented, this routine
+| should be simply `float_exception_flags |= flags;'.
+*----------------------------------------------------------------------------*/
+
+void softfloat_raiseFlags( int_fast8_t flags )
+{
+
+ softfloat_exceptionFlags |= flags;
+
+}
+
new file mode 100755
@@ -0,0 +1,16 @@
+
+#ifndef softfloat_types_h
+#define softfloat_types_h
+
+/*** COMMENTS. ***/
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef struct { uint32_t v; } float32_t;
+typedef struct { uint64_t v; } float64_t;
+typedef struct { uint64_t v; uint16_t x; } floatx80_t;
+typedef struct { uint64_t v[ 2 ]; } float128_t;
+
+#endif
+
new file mode 100755
@@ -0,0 +1,113 @@
+
+/*============================================================================
+
+*** FIX.
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2b.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/*----------------------------------------------------------------------------
+*----------------------------------------------------------------------------*/
+#define init_detectTininess softfloat_tininess_afterRounding;
+
+/*----------------------------------------------------------------------------
+| Structure used to transfer NaN representations from one format to another.
+*----------------------------------------------------------------------------*/
+struct commonNaN {
+ bool sign;
+ uint64_t v64, v0;
+};
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated single-precision NaN.
+*----------------------------------------------------------------------------*/
+#define defaultNaNF32UI 0xFFC00000
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point value `a' is a signaling
+| NaN; otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 1 <= INLINE_LEVEL )
+INLINE bool softfloat_isSigNaNF32UI( uint_fast32_t ui )
+ { return ( ( ui>>22 & 0x1FF ) == 0x1FE ) && ( ui & 0x003FFFFF ); }
+#else
+bool softfloat_isSigNaNF32UI( uint_fast32_t );
+#endif
+
+/*----------------------------------------------------------------------------
+*----------------------------------------------------------------------------*/
+struct commonNaN softfloat_f32UIToCommonNaN( uint_fast32_t );
+#if defined INLINE_LEVEL && ( 1 <= INLINE_LEVEL )
+INLINE uint_fast32_t softfloat_commonNaNToF32UI( struct commonNaN a )
+ { return (uint_fast32_t) a.sign<<31 | 0x7FC00000 | a.v64>>41; }
+#else
+uint_fast32_t softfloat_commonNaNToF32UI( struct commonNaN );
+#endif
+
+/*----------------------------------------------------------------------------
+| Takes two single-precision floating-point values `a' and `b', one of which
+| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+| signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+uint_fast32_t softfloat_propagateNaNF32UI( uint_fast32_t, uint_fast32_t );
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated double-precision NaN.
+*----------------------------------------------------------------------------*/
+#define defaultNaNF64UI UINT64_C(0xFFF8000000000000)
+
+/*----------------------------------------------------------------------------
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 1 <= INLINE_LEVEL )
+INLINE bool softfloat_isSigNaNF64UI( uint_fast64_t ui )
+{
+ return
+ ( ( ui>>51 & 0xFFF ) == 0xFFE )
+ && ( ui & UINT64_C( 0x0007FFFFFFFFFFFF ) );
+}
+#else
+bool softfloat_isSigNaNF64UI( uint_fast64_t );
+#endif
+
+/*----------------------------------------------------------------------------
+*----------------------------------------------------------------------------*/
+/*** MIGHT BE INLINE'D. ***/
+struct commonNaN softfloat_f64UIToCommonNaN( uint_fast64_t );
+uint_fast64_t softfloat_commonNaNToF64UI( struct commonNaN );
+
+/*----------------------------------------------------------------------------
+| Takes two double-precision floating-point values `a' and `b', one of which
+| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+| signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+uint_fast64_t softfloat_propagateNaNF64UI( uint_fast64_t, uint_fast64_t );
+
new file mode 100755
@@ -0,0 +1,29 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float32_t f32_add( float32_t a, float32_t b )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ bool signA;
+ union ui32_f32 uB;
+ uint_fast32_t uiB;
+ bool signB;
+ float32_t ( *magsRoutine )( uint_fast32_t, uint_fast32_t, bool );
+
+ uA.f = a;
+ uiA = uA.ui;
+ signA = signF32UI( uiA );
+ uB.f = b;
+ uiB = uB.ui;
+ signB = signF32UI( uiB );
+ magsRoutine =
+ ( signA == signB ) ? softfloat_addMagsF32 : softfloat_subMagsF32;
+ return magsRoutine( uiA, uiB, signA );
+
+}
+
new file mode 100755
@@ -0,0 +1,33 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+uint_fast16_t f32_classify( float32_t a )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+
+ uA.f = a;
+ uiA = uA.ui;
+
+ uint_fast16_t infOrNaN = expF32UI( uiA ) == 0xFF;
+ uint_fast16_t subnormalOrZero = expF32UI( uiA ) == 0;
+ bool sign = signF32UI( uiA );
+
+ return
+ ( sign && infOrNaN && fracF32UI( uiA ) == 0 ) << 0 |
+ ( sign && !infOrNaN && !subnormalOrZero ) << 1 |
+ ( sign && subnormalOrZero && fracF32UI( uiA ) ) << 2 |
+ ( sign && subnormalOrZero && fracF32UI( uiA ) == 0 ) << 3 |
+ ( !sign && infOrNaN && fracF32UI( uiA ) == 0 ) << 7 |
+ ( !sign && !infOrNaN && !subnormalOrZero ) << 6 |
+ ( !sign && subnormalOrZero && fracF32UI( uiA ) ) << 5 |
+ ( !sign && subnormalOrZero && fracF32UI( uiA ) == 0 ) << 4 |
+ ( isNaNF32UI( uiA ) && softfloat_isSigNaNF32UI( uiA )) << 8 |
+ ( isNaNF32UI( uiA ) && !softfloat_isSigNaNF32UI( uiA )) << 9;
+}
+
new file mode 100755
@@ -0,0 +1,96 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float32_t f32_div( float32_t a, float32_t b )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ bool signA;
+ int_fast16_t expA;
+ uint_fast32_t sigA;
+ union ui32_f32 uB;
+ uint_fast32_t uiB;
+ bool signB;
+ int_fast16_t expB;
+ uint_fast32_t sigB;
+ bool signZ;
+ struct exp16_sig32 normExpSig;
+ int_fast16_t expZ;
+ uint_fast32_t sigZ;
+ uint_fast32_t uiZ;
+ union ui32_f32 uZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ signA = signF32UI( uiA );
+ expA = expF32UI( uiA );
+ sigA = fracF32UI( uiA );
+ uB.f = b;
+ uiB = uB.ui;
+ signB = signF32UI( uiB );
+ expB = expF32UI( uiB );
+ sigB = fracF32UI( uiB );
+ signZ = signA ^ signB;
+ if ( expA == 0xFF ) {
+ if ( sigA ) goto propagateNaN;
+ if ( expB == 0xFF ) {
+ if ( sigB ) goto propagateNaN;
+ goto invalid;
+ }
+ goto infinity;
+ }
+ if ( expB == 0xFF ) {
+ if ( sigB ) goto propagateNaN;
+ goto zero;
+ }
+ if ( ! expB ) {
+ if ( ! sigB ) {
+ if ( ! ( expA | sigA ) ) goto invalid;
+ softfloat_raiseFlags( softfloat_flag_infinity );
+ goto infinity;
+ }
+ normExpSig = softfloat_normSubnormalF32Sig( sigB );
+ expB = normExpSig.exp;
+ sigB = normExpSig.sig;
+ }
+ if ( ! expA ) {
+ if ( ! sigA ) goto zero;
+ normExpSig = softfloat_normSubnormalF32Sig( sigA );
+ expA = normExpSig.exp;
+ sigA = normExpSig.sig;
+ }
+ expZ = expA - expB + 0x7D;
+ sigA = ( sigA | 0x00800000 )<<7;
+ sigB = ( sigB | 0x00800000 )<<8;
+ if ( sigB <= ( sigA + sigA ) ) {
+ ++expZ;
+ sigA >>= 1;
+ }
+ sigZ = ( (uint_fast64_t) sigA<<32 ) / sigB;
+ if ( ! ( sigZ & 0x3F ) ) {
+ sigZ |= ( (uint_fast64_t) sigB * sigZ != (uint_fast64_t) sigA<<32 );
+ }
+ return softfloat_roundPackToF32( signZ, expZ, sigZ );
+ propagateNaN:
+ uiZ = softfloat_propagateNaNF32UI( uiA, uiB );
+ goto uiZ;
+ invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ uiZ = defaultNaNF32UI;
+ goto uiZ;
+ infinity:
+ uiZ = packToF32UI( signZ, 0xFF, 0 );
+ goto uiZ;
+ zero:
+ uiZ = packToF32UI( signZ, 0, 0 );
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,34 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+bool f32_eq( float32_t a, float32_t b )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ union ui32_f32 uB;
+ uint_fast32_t uiB;
+
+ uA.f = a;
+ uiA = uA.ui;
+ uB.f = b;
+ uiB = uB.ui;
+ if (
+ ( ( expF32UI( uiA ) == 0xFF ) && fracF32UI( uiA ) )
+ || ( ( expF32UI( uiB ) == 0xFF ) && fracF32UI( uiB ) )
+ ) {
+ if (
+ softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB )
+ ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ }
+ return false;
+ }
+ return ( uiA == uiB ) || ! (uint32_t) ( ( uiA | uiB )<<1 );
+
+}
+
new file mode 100755
@@ -0,0 +1,29 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+bool f32_eq_signaling( float32_t a, float32_t b )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ union ui32_f32 uB;
+ uint_fast32_t uiB;
+
+ uA.f = a;
+ uiA = uA.ui;
+ uB.f = b;
+ uiB = uB.ui;
+ if (
+ ( ( expF32UI( uiA ) == 0xFF ) && fracF32UI( uiA ) )
+ || ( ( expF32UI( uiB ) == 0xFF ) && fracF32UI( uiB ) )
+ ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return false;
+ }
+ return ( uiA == uiB ) || ! (uint32_t) ( ( uiA | uiB )<<1 );
+
+}
+
new file mode 100755
@@ -0,0 +1,16 @@
+
+#include <stdbool.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+bool f32_isSignalingNaN( float32_t a )
+{
+ union ui32_f32 uA;
+
+ uA.f = a;
+ return softfloat_isSigNaNF32UI( uA.ui );
+
+}
+
new file mode 100755
@@ -0,0 +1,34 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+bool f32_le( float32_t a, float32_t b )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ union ui32_f32 uB;
+ uint_fast32_t uiB;
+ bool signA, signB;
+
+ uA.f = a;
+ uiA = uA.ui;
+ uB.f = b;
+ uiB = uB.ui;
+ if (
+ ( ( expF32UI( uiA ) == 0xFF ) && fracF32UI( uiA ) )
+ || ( ( expF32UI( uiB ) == 0xFF ) && fracF32UI( uiB ) )
+ ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return false;
+ }
+ signA = signF32UI( uiA );
+ signB = signF32UI( uiB );
+ return
+ ( signA != signB ) ? signA || ! (uint32_t) ( ( uiA | uiB )<<1 )
+ : ( uiA == uiB ) || ( signA ^ ( uiA < uiB ) );
+
+}
+
new file mode 100755
@@ -0,0 +1,39 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+bool f32_le_quiet( float32_t a, float32_t b )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ union ui32_f32 uB;
+ uint_fast32_t uiB;
+ bool signA, signB;
+
+ uA.f = a;
+ uiA = uA.ui;
+ uB.f = b;
+ uiB = uB.ui;
+ if (
+ ( ( expF32UI( uiA ) == 0xFF ) && fracF32UI( uiA ) )
+ || ( ( expF32UI( uiB ) == 0xFF ) && fracF32UI( uiB ) )
+ ) {
+ if (
+ softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB )
+ ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ }
+ return false;
+ }
+ signA = signF32UI( uiA );
+ signB = signF32UI( uiB );
+ return
+ ( signA != signB ) ? signA || ! (uint32_t) ( ( uiA | uiB )<<1 )
+ : ( uiA == uiB ) || ( signA ^ ( uiA < uiB ) );
+
+}
+
new file mode 100755
@@ -0,0 +1,34 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+bool f32_lt( float32_t a, float32_t b )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ union ui32_f32 uB;
+ uint_fast32_t uiB;
+ bool signA, signB;
+
+ uA.f = a;
+ uiA = uA.ui;
+ uB.f = b;
+ uiB = uB.ui;
+ if (
+ ( ( expF32UI( uiA ) == 0xFF ) && fracF32UI( uiA ) )
+ || ( ( expF32UI( uiB ) == 0xFF ) && fracF32UI( uiB ) )
+ ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return false;
+ }
+ signA = signF32UI( uiA );
+ signB = signF32UI( uiB );
+ return
+ ( signA != signB ) ? signA && ( (uint32_t) ( ( uiA | uiB )<<1 ) != 0 )
+ : ( uiA != uiB ) && ( signA ^ ( uiA < uiB ) );
+
+}
+
new file mode 100755
@@ -0,0 +1,39 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+bool f32_lt_quiet( float32_t a, float32_t b )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ union ui32_f32 uB;
+ uint_fast32_t uiB;
+ bool signA, signB;
+
+ uA.f = a;
+ uiA = uA.ui;
+ uB.f = b;
+ uiB = uB.ui;
+ if (
+ ( ( expF32UI( uiA ) == 0xFF ) && fracF32UI( uiA ) )
+ || ( ( expF32UI( uiB ) == 0xFF ) && fracF32UI( uiB ) )
+ ) {
+ if (
+ softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB )
+ ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ }
+ return false;
+ }
+ signA = signF32UI( uiA );
+ signB = signF32UI( uiB );
+ return
+ ( signA != signB ) ? signA && ( (uint32_t) ( ( uiA | uiB )<<1 ) != 0 )
+ : ( uiA != uiB ) && ( signA ^ ( uiA < uiB ) );
+
+}
+
new file mode 100755
@@ -0,0 +1,89 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float32_t f32_mul( float32_t a, float32_t b )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ bool signA;
+ int_fast16_t expA;
+ uint_fast32_t sigA;
+ union ui32_f32 uB;
+ uint_fast32_t uiB;
+ bool signB;
+ int_fast16_t expB;
+ uint_fast32_t sigB;
+ bool signZ;
+ uint_fast32_t magBits;
+ struct exp16_sig32 normExpSig;
+ int_fast16_t expZ;
+ uint_fast32_t sigZ, uiZ;
+ union ui32_f32 uZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ signA = signF32UI( uiA );
+ expA = expF32UI( uiA );
+ sigA = fracF32UI( uiA );
+ uB.f = b;
+ uiB = uB.ui;
+ signB = signF32UI( uiB );
+ expB = expF32UI( uiB );
+ sigB = fracF32UI( uiB );
+ signZ = signA ^ signB;
+ if ( expA == 0xFF ) {
+ if ( sigA || ( ( expB == 0xFF ) && sigB ) ) goto propagateNaN;
+ magBits = expB | sigB;
+ goto infArg;
+ }
+ if ( expB == 0xFF ) {
+ if ( sigB ) goto propagateNaN;
+ magBits = expA | sigA;
+ goto infArg;
+ }
+ if ( ! expA ) {
+ if ( ! sigA ) goto zero;
+ normExpSig = softfloat_normSubnormalF32Sig( sigA );
+ expA = normExpSig.exp;
+ sigA = normExpSig.sig;
+ }
+ if ( ! expB ) {
+ if ( ! sigB ) goto zero;
+ normExpSig = softfloat_normSubnormalF32Sig( sigB );
+ expB = normExpSig.exp;
+ sigB = normExpSig.sig;
+ }
+ expZ = expA + expB - 0x7F;
+ sigA = ( sigA | 0x00800000 )<<7;
+ sigB = ( sigB | 0x00800000 )<<8;
+ sigZ = softfloat_shortShift64RightJam( (uint_fast64_t) sigA * sigB, 32 );
+ if ( sigZ < 0x40000000 ) {
+ --expZ;
+ sigZ <<= 1;
+ }
+ return softfloat_roundPackToF32( signZ, expZ, sigZ );
+ propagateNaN:
+ uiZ = softfloat_propagateNaNF32UI( uiA, uiB );
+ goto uiZ;
+ infArg:
+ if ( ! magBits ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ uiZ = defaultNaNF32UI;
+ } else {
+ uiZ = packToF32UI( signZ, 0xFF, 0 );
+ }
+ goto uiZ;
+ zero:
+ uiZ = packToF32UI( signZ, 0, 0 );
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,25 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float32_t f32_mulAdd( float32_t a, float32_t b, float32_t c )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ union ui32_f32 uB;
+ uint_fast32_t uiB;
+ union ui32_f32 uC;
+ uint_fast32_t uiC;
+
+ uA.f = a;
+ uiA = uA.ui;
+ uB.f = b;
+ uiB = uB.ui;
+ uC.f = c;
+ uiC = uC.ui;
+ return softfloat_mulAddF32( 0, uiA, uiB, uiC );
+
+}
+
new file mode 100755
@@ -0,0 +1,124 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float32_t f32_rem( float32_t a, float32_t b )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ bool signA;
+ int_fast16_t expA;
+ uint_fast32_t sigA;
+ union ui32_f32 uB;
+ uint_fast32_t uiB;
+// bool signB;
+ int_fast16_t expB;
+ uint_fast32_t sigB;
+ struct exp16_sig32 normExpSig;
+ int_fast16_t expDiff;
+ uint_fast32_t q;
+ uint_fast64_t sigA64, sigB64, q64;
+ uint_fast32_t alternateSigA;
+ uint32_t sigMean;
+ bool signZ;
+ uint_fast32_t uiZ;
+ union ui32_f32 uZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ signA = signF32UI( uiA );
+ expA = expF32UI( uiA );
+ sigA = fracF32UI( uiA );
+ uB.f = b;
+ uiB = uB.ui;
+// signB = signF32UI( uiB );
+ expB = expF32UI( uiB );
+ sigB = fracF32UI( uiB );
+ if ( expA == 0xFF ) {
+ if ( sigA || ( ( expB == 0xFF ) && sigB ) ) goto propagateNaN;
+ goto invalid;
+ }
+ if ( expB == 0xFF ) {
+ if ( sigB ) goto propagateNaN;
+ return a;
+ }
+ if ( ! expB ) {
+ if ( ! sigB ) goto invalid;
+ normExpSig = softfloat_normSubnormalF32Sig( sigB );
+ expB = normExpSig.exp;
+ sigB = normExpSig.sig;
+ }
+ if ( ! expA ) {
+ if ( ! sigA ) return a;
+ normExpSig = softfloat_normSubnormalF32Sig( sigA );
+ expA = normExpSig.exp;
+ sigA = normExpSig.sig;
+ }
+ expDiff = expA - expB;
+ sigA |= 0x00800000;
+ sigB |= 0x00800000;
+ if ( expDiff < 32 ) {
+ sigA <<= 8;
+ sigB <<= 8;
+ if ( expDiff < 0 ) {
+ if ( expDiff < -1 ) return a;
+ sigA >>= 1;
+ }
+ q = ( sigB <= sigA );
+ if ( q ) sigA -= sigB;
+ if ( 0 < expDiff ) {
+ q = ( (uint_fast64_t) sigA<<32 ) / sigB;
+ q >>= 32 - expDiff;
+ sigB >>= 2;
+ sigA = ( ( sigA>>1 )<<( expDiff - 1 ) ) - sigB * q;
+ } else {
+ sigA >>= 2;
+ sigB >>= 2;
+ }
+ } else {
+ if ( sigB <= sigA ) sigA -= sigB;
+ sigA64 = (uint_fast64_t) sigA<<40;
+ sigB64 = (uint_fast64_t) sigB<<40;
+ expDiff -= 64;
+ while ( 0 < expDiff ) {
+ q64 = softfloat_estimateDiv128To64( sigA64, 0, sigB64 );
+ q64 = ( 2 < q64 ) ? q64 - 2 : 0;
+ sigA64 = - ( ( sigB * q64 )<<38 );
+ expDiff -= 62;
+ }
+ expDiff += 64;
+ q64 = softfloat_estimateDiv128To64( sigA64, 0, sigB64 );
+ q64 = ( 2 < q64 ) ? q64 - 2 : 0;
+ q = q64>>( 64 - expDiff );
+ sigB <<= 6;
+ sigA = ( ( sigA64>>33 )<<( expDiff - 1 ) ) - sigB * q;
+ }
+ do {
+ alternateSigA = sigA;
+ ++q;
+ sigA -= sigB;
+ } while ( sigA < 0x80000000 );
+ sigMean = sigA + alternateSigA;
+ if ( ( 0x80000000 <= sigMean ) || ( ! sigMean && ( q & 1 ) ) ) {
+ sigA = alternateSigA;
+ }
+ signZ = ( 0x80000000 <= sigA );
+ if ( signZ ) sigA = - sigA;
+ return softfloat_normRoundPackToF32( signA ^ signZ, expB, sigA );
+ propagateNaN:
+ uiZ = softfloat_propagateNaNF32UI( uiA, uiB );
+ goto uiZ;
+ invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ uiZ = defaultNaNF32UI;
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,78 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float32_t f32_roundToInt( float32_t a, int_fast8_t roundingMode, bool exact )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ int_fast16_t expA;
+ uint_fast32_t uiZ;
+ bool signA;
+ uint_fast32_t lastBitMask, roundBitsMask;
+ union ui32_f32 uZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ expA = expF32UI( uiA );
+ if ( 0x96 <= expA ) {
+ if ( ( expA == 0xFF ) && fracF32UI( uiA ) ) {
+ uiZ = softfloat_propagateNaNF32UI( uiA, 0 );
+ goto uiZ;
+ }
+ return a;
+ }
+ if ( expA <= 0x7E ) {
+ if ( ! (uint32_t) ( uiA<<1 ) ) return a;
+ if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact;
+ signA = signF32UI( uiA );
+ switch ( roundingMode ) {
+ case softfloat_round_nearest_even:
+ if ( ( expA == 0x7E ) && fracF32UI( uiA ) ) {
+ uiZ = packToF32UI( signA, 0x7F, 0 );
+ goto uiZ;
+ }
+ break;
+ case softfloat_round_min:
+ uiZ = signA ? 0xBF800000 : 0;
+ goto uiZ;
+ case softfloat_round_max:
+ uiZ = signA ? 0x80000000 : 0x3F800000;
+ goto uiZ;
+ case softfloat_round_nearest_maxMag:
+ if ( expA == 0x7E ) {
+ uiZ = packToF32UI( signA, 0x7F, 0 );
+ goto uiZ;
+ }
+ break;
+ }
+ uiZ = packToF32UI( signA, 0, 0 );
+ goto uiZ;
+ }
+ lastBitMask = (uint_fast32_t) 1<<( 0x96 - expA );
+ roundBitsMask = lastBitMask - 1;
+ uiZ = uiA;
+ if ( roundingMode == softfloat_round_nearest_maxMag ) {
+ uiZ += lastBitMask>>1;
+ } else if ( roundingMode == softfloat_round_nearest_even ) {
+ uiZ += lastBitMask>>1;
+ if ( ! ( uiZ & roundBitsMask ) ) uiZ &= ~ lastBitMask;
+ } else if ( roundingMode != softfloat_round_minMag ) {
+ if ( signF32UI( uiZ ) ^ ( roundingMode == softfloat_round_max ) ) {
+ uiZ += roundBitsMask;
+ }
+ }
+ uiZ &= ~ roundBitsMask;
+ if ( exact && ( uiZ != uiA ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,74 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float32_t f32_sqrt( float32_t a )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ bool signA;
+ int_fast16_t expA;
+ uint_fast32_t sigA, uiZ;
+ struct exp16_sig32 normExpSig;
+ int_fast16_t expZ;
+ uint_fast32_t sigZ;
+ uint_fast64_t term, rem;
+ union ui32_f32 uZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ signA = signF32UI( uiA );
+ expA = expF32UI( uiA );
+ sigA = fracF32UI( uiA );
+ if ( expA == 0xFF ) {
+ if ( sigA ) {
+ uiZ = softfloat_propagateNaNF32UI( uiA, 0 );
+ goto uiZ;
+ }
+ if ( ! signA ) return a;
+ goto invalid;
+ }
+ if ( signA ) {
+ if ( ! ( expA | sigA ) ) return a;
+ goto invalid;
+ }
+ if ( ! expA ) {
+ if ( ! sigA ) return a;
+ normExpSig = softfloat_normSubnormalF32Sig( sigA );
+ expA = normExpSig.exp;
+ sigA = normExpSig.sig;
+ }
+ expZ = ( ( expA - 0x7F )>>1 ) + 0x7E;
+ sigA = ( sigA | 0x00800000 )<<8;
+ sigZ = softfloat_estimateSqrt32( expA, sigA ) + 2;
+ if ( ( sigZ & 0x7F ) <= 5 ) {
+ if ( sigZ < 2 ) {
+ sigZ = 0x7FFFFFFF;
+ goto roundPack;
+ }
+ sigA >>= expA & 1;
+ term = (uint_fast64_t) sigZ * sigZ;
+ rem = ( (uint_fast64_t) sigA<<32 ) - term;
+ while ( UINT64_C( 0x8000000000000000 ) <= rem ) {
+ --sigZ;
+ rem += ( (uint_fast64_t) sigZ<<1 ) | 1;
+ }
+ sigZ |= ( rem != 0 );
+ }
+ sigZ = softfloat_shortShift32Right1Jam( sigZ );
+ roundPack:
+ return softfloat_roundPackToF32( 0, expZ, sigZ );
+ invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ uiZ = defaultNaNF32UI;
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,29 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float32_t f32_sub( float32_t a, float32_t b )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ bool signA;
+ union ui32_f32 uB;
+ uint_fast32_t uiB;
+ bool signB;
+ float32_t ( *magsRoutine )( uint_fast32_t, uint_fast32_t, bool );
+
+ uA.f = a;
+ uiA = uA.ui;
+ signA = signF32UI( uiA );
+ uB.f = b;
+ uiB = uB.ui;
+ signB = signF32UI( uiB );
+ magsRoutine =
+ ( signA == signB ) ? softfloat_subMagsF32 : softfloat_addMagsF32;
+ return magsRoutine( uiA, uiB ^ 0x80000000, signA );
+
+}
+
new file mode 100755
@@ -0,0 +1,47 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float64_t f32_to_f64( float32_t a )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ bool sign;
+ int_fast16_t exp;
+ uint_fast32_t sig;
+ uint_fast64_t uiZ;
+ struct exp16_sig32 normExpSig;
+ union ui64_f64 uZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ sign = signF32UI( uiA );
+ exp = expF32UI( uiA );
+ sig = fracF32UI( uiA );
+ if ( exp == 0xFF ) {
+ uiZ =
+ sig ? softfloat_commonNaNToF64UI(
+ softfloat_f32UIToCommonNaN( uiA ) )
+ : packToF64UI( sign, 0x7FF, 0 );
+ goto uiZ;
+ }
+ if ( ! exp ) {
+ if ( ! sig ) {
+ uiZ = packToF64UI( sign, 0, 0 );
+ goto uiZ;
+ }
+ normExpSig = softfloat_normSubnormalF32Sig( sig );
+ exp = normExpSig.exp - 1;
+ sig = normExpSig.sig;
+ }
+ uiZ = packToF64UI( sign, exp + 0x380, (uint_fast64_t) sig<<29 );
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,34 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+int_fast32_t f32_to_i32( float32_t a, int_fast8_t roundingMode, bool exact )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ bool sign;
+ int_fast16_t exp;
+ uint_fast32_t sig;
+ uint_fast64_t sig64;
+ int_fast16_t shiftCount;
+
+ uA.f = a;
+ uiA = uA.ui;
+ sign = signF32UI( uiA );
+ exp = expF32UI( uiA );
+ sig = fracF32UI( uiA );
+ if ( ( exp == 0xFF ) && sig ) sign = 0;
+ if ( exp ) sig |= 0x00800000;
+ sig64 = (uint_fast64_t) sig<<32;
+ shiftCount = 0xAF - exp;
+ if ( 0 < shiftCount ) {
+ sig64 = softfloat_shift64RightJam( sig64, shiftCount );
+ }
+ return softfloat_roundPackToI32( sign, sig64, roundingMode, exact );
+
+}
+
new file mode 100755
@@ -0,0 +1,45 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+int_fast32_t f32_to_i32_r_minMag( float32_t a, bool exact )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ int_fast16_t exp;
+ uint_fast32_t sig;
+ bool sign;
+ int_fast16_t shiftCount;
+ int_fast32_t absZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ exp = expF32UI( uiA );
+ sig = fracF32UI( uiA );
+ if ( exp < 0x7F ) {
+ if ( exact && ( exp | sig ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return 0;
+ }
+ sign = signF32UI( uiA );
+ shiftCount = 0x9E - exp;
+ if ( shiftCount <= 0 ) {
+ if ( uiA != packToF32UI( 1, 0x9E, 0 ) ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ if ( ! sign || ( ( exp == 0xFF ) && sig ) ) return 0x7FFFFFFF;
+ }
+ return -0x7FFFFFFF - 1;
+ }
+ sig = ( sig | 0x00800000 )<<8;
+ absZ = sig>>shiftCount;
+ if ( exact && (uint32_t) ( sig<<( ( - shiftCount ) & 31 ) ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return sign ? - absZ : absZ;
+
+}
+
new file mode 100755
@@ -0,0 +1,44 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+int_fast64_t f32_to_i64( float32_t a, int_fast8_t roundingMode, bool exact )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ bool sign;
+ int_fast16_t exp;
+ uint_fast32_t sig;
+ int_fast16_t shiftCount;
+ uint_fast64_t sig64, extra;
+ struct uint64_extra sig64Extra;
+
+ uA.f = a;
+ uiA = uA.ui;
+ sign = signF32UI( uiA );
+ exp = expF32UI( uiA );
+ sig = fracF32UI( uiA );
+ shiftCount = 0xBE - exp;
+ if ( shiftCount < 0 ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ if ( ! sign || ( ( exp == 0xFF ) && sig ) ) {
+ return INT64_C( 0x7FFFFFFFFFFFFFFF );
+ }
+ return - INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1;
+ }
+ if ( exp ) sig |= 0x00800000;
+ sig64 = (uint_fast64_t) sig<<40;
+ extra = 0;
+ if ( shiftCount ) {
+ sig64Extra = softfloat_shift64ExtraRightJam( sig64, 0, shiftCount );
+ sig64 = sig64Extra.v;
+ extra = sig64Extra.extra;
+ }
+ return softfloat_roundPackToI64( sign, sig64, extra, roundingMode, exact );
+
+}
+
new file mode 100755
@@ -0,0 +1,52 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+int_fast64_t f32_to_i64_r_minMag( float32_t a, bool exact )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ int_fast16_t exp;
+ uint_fast32_t sig;
+ bool sign;
+ int_fast16_t shiftCount;
+ uint_fast64_t sig64;
+ int_fast64_t absZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ exp = expF32UI( uiA );
+ sig = fracF32UI( uiA );
+ if ( exp < 0x7F ) {
+ if ( exact && ( exp | sig ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return 0;
+ }
+ sign = signF32UI( uiA );
+ shiftCount = 0xBE - exp;
+ if ( shiftCount <= 0 ) {
+ if ( uiA != packToF32UI( 1, 0xBE, 0 ) ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ if ( ! sign || ( ( exp == 0xFF ) && sig ) ) {
+ return INT64_C( 0x7FFFFFFFFFFFFFFF );
+ }
+ }
+ return - INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1;
+ }
+ sig |= 0x00800000;
+ sig64 = (uint_fast64_t) sig<<40;
+ absZ = sig64>>shiftCount;
+ shiftCount = 40 - shiftCount;
+ if (
+ exact && ( shiftCount < 0 ) && (uint32_t) ( sig<<( shiftCount & 31 ) )
+ ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return sign ? - absZ : absZ;
+
+}
+
new file mode 100755
@@ -0,0 +1,33 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+uint_fast32_t f32_to_ui32( float32_t a, int_fast8_t roundingMode, bool exact )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ bool sign;
+ int_fast16_t exp;
+ uint_fast32_t sig;
+ uint_fast64_t sig64;
+ int_fast16_t shiftCount;
+
+ uA.f = a;
+ uiA = uA.ui;
+ sign = signF32UI( uiA );
+ exp = expF32UI( uiA );
+ sig = fracF32UI( uiA );
+ if ( exp ) sig |= 0x00800000;
+ sig64 = (uint_fast64_t) sig<<32;
+ shiftCount = 0xAF - exp;
+ if ( 0 < shiftCount ) {
+ sig64 = softfloat_shift64RightJam( sig64, shiftCount );
+ }
+ return softfloat_roundPackToUI32( sign, sig64, roundingMode, exact );
+
+}
+
new file mode 100755
@@ -0,0 +1,41 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+uint_fast32_t f32_to_ui32_r_minMag( float32_t a, bool exact )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ int_fast16_t exp;
+ uint_fast32_t sig;
+ int_fast16_t shiftCount;
+ uint_fast32_t z;
+
+ uA.f = a;
+ uiA = uA.ui;
+ exp = expF32UI( uiA );
+ sig = fracF32UI( uiA );
+ if ( exp < 0x7F ) {
+ if ( exact && ( exp | sig ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return 0;
+ }
+ if ( signF32UI( uiA ) ) goto invalid;
+ shiftCount = 0x9E - exp;
+ if ( shiftCount < 0 ) goto invalid;
+ sig = ( sig | 0x00800000 )<<8;
+ z = sig>>shiftCount;
+ if ( exact && ( sig & ( ( (uint_fast32_t) 1<<shiftCount ) - 1 ) ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return z;
+ invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return 0xFFFFFFFF;
+
+}
+
new file mode 100755
@@ -0,0 +1,42 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+uint_fast64_t f32_to_ui64( float32_t a, int_fast8_t roundingMode, bool exact )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ bool sign;
+ int_fast16_t exp;
+ uint_fast32_t sig;
+ int_fast16_t shiftCount;
+ uint_fast64_t sig64, extra;
+ struct uint64_extra sig64Extra;
+
+ uA.f = a;
+ uiA = uA.ui;
+ sign = signF32UI( uiA );
+ exp = expF32UI( uiA );
+ sig = fracF32UI( uiA );
+ shiftCount = 0xBE - exp;
+ if ( shiftCount < 0 ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return UINT64_C( 0xFFFFFFFFFFFFFFFF );
+ }
+ if ( exp ) sig |= 0x00800000;
+ sig64 = (uint_fast64_t) sig<<40;
+ extra = 0;
+ if ( shiftCount ) {
+ sig64Extra = softfloat_shift64ExtraRightJam( sig64, 0, shiftCount );
+ sig64 = sig64Extra.v;
+ extra = sig64Extra.extra;
+ }
+ return
+ softfloat_roundPackToUI64( sign, sig64, extra, roundingMode, exact );
+
+}
+
new file mode 100755
@@ -0,0 +1,45 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+uint_fast64_t f32_to_ui64_r_minMag( float32_t a, bool exact )
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+ int_fast16_t exp;
+ uint_fast32_t sig;
+ int_fast16_t shiftCount;
+ uint_fast64_t sig64, z;
+
+ uA.f = a;
+ uiA = uA.ui;
+ exp = expF32UI( uiA );
+ sig = fracF32UI( uiA );
+ if ( exp < 0x7F ) {
+ if ( exact && ( exp | sig ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return 0;
+ }
+ if ( signF32UI( uiA ) ) goto invalid;
+ shiftCount = 0xBE - exp;
+ if ( shiftCount < 0 ) goto invalid;
+ sig |= 0x00800000;
+ sig64 = (uint_fast64_t) sig<<40;
+ z = sig64>>shiftCount;
+ shiftCount = 40 - shiftCount;
+ if (
+ exact && ( shiftCount < 0 ) && (uint32_t) ( sig<<( shiftCount & 31 ) )
+ ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return z;
+ invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return UINT64_C( 0xFFFFFFFFFFFFFFFF );
+
+}
+
new file mode 100755
@@ -0,0 +1,29 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float64_t f64_add( float64_t a, float64_t b )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ bool signA;
+ union ui64_f64 uB;
+ uint_fast64_t uiB;
+ bool signB;
+ float64_t ( *magsRoutine )( uint_fast64_t, uint_fast64_t, bool );
+
+ uA.f = a;
+ uiA = uA.ui;
+ signA = signF64UI( uiA );
+ uB.f = b;
+ uiB = uB.ui;
+ signB = signF64UI( uiB );
+ magsRoutine =
+ ( signA == signB ) ? softfloat_addMagsF64 : softfloat_subMagsF64;
+ return magsRoutine( uiA, uiB, signA );
+
+}
+
new file mode 100755
@@ -0,0 +1,33 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+uint_fast16_t f64_classify( float64_t a )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+
+ uA.f = a;
+ uiA = uA.ui;
+
+ uint_fast16_t infOrNaN = expF64UI( uiA ) == 0x7FF;
+ uint_fast16_t subnormalOrZero = expF64UI( uiA ) == 0;
+ bool sign = signF64UI( uiA );
+
+ return
+ ( sign && infOrNaN && fracF64UI( uiA ) == 0 ) << 0 |
+ ( sign && !infOrNaN && !subnormalOrZero ) << 1 |
+ ( sign && subnormalOrZero && fracF64UI( uiA ) ) << 2 |
+ ( sign && subnormalOrZero && fracF64UI( uiA ) == 0 ) << 3 |
+ ( !sign && infOrNaN && fracF64UI( uiA ) == 0 ) << 7 |
+ ( !sign && !infOrNaN && !subnormalOrZero ) << 6 |
+ ( !sign && subnormalOrZero && fracF64UI( uiA ) ) << 5 |
+ ( !sign && subnormalOrZero && fracF64UI( uiA ) == 0 ) << 4 |
+ ( isNaNF64UI( uiA ) && softfloat_isSigNaNF64UI( uiA )) << 8 |
+ ( isNaNF64UI( uiA ) && !softfloat_isSigNaNF64UI( uiA )) << 9;
+}
+
new file mode 100755
@@ -0,0 +1,104 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float64_t f64_div( float64_t a, float64_t b )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ bool signA;
+ int_fast16_t expA;
+ uint_fast64_t sigA;
+ union ui64_f64 uB;
+ uint_fast64_t uiB;
+ bool signB;
+ int_fast16_t expB;
+ uint_fast64_t sigB;
+ bool signZ;
+ struct exp16_sig64 normExpSig;
+ int_fast16_t expZ;
+ uint_fast64_t sigZ;
+ struct uint128 term, rem;
+ uint_fast64_t uiZ;
+ union ui64_f64 uZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ signA = signF64UI( uiA );
+ expA = expF64UI( uiA );
+ sigA = fracF64UI( uiA );
+ uB.f = b;
+ uiB = uB.ui;
+ signB = signF64UI( uiB );
+ expB = expF64UI( uiB );
+ sigB = fracF64UI( uiB );
+ signZ = signA ^ signB;
+ if ( expA == 0x7FF ) {
+ if ( sigA ) goto propagateNaN;
+ if ( expB == 0x7FF ) {
+ if ( sigB ) goto propagateNaN;
+ goto invalid;
+ }
+ goto infinity;
+ }
+ if ( expB == 0x7FF ) {
+ if ( sigB ) goto propagateNaN;
+ goto zero;
+ }
+ if ( ! expB ) {
+ if ( ! sigB ) {
+ if ( ! ( expA | sigA ) ) goto invalid;
+ softfloat_raiseFlags( softfloat_flag_infinity );
+ goto infinity;
+ }
+ normExpSig = softfloat_normSubnormalF64Sig( sigB );
+ expB = normExpSig.exp;
+ sigB = normExpSig.sig;
+ }
+ if ( ! expA ) {
+ if ( ! sigA ) goto zero;
+ normExpSig = softfloat_normSubnormalF64Sig( sigA );
+ expA = normExpSig.exp;
+ sigA = normExpSig.sig;
+ }
+ expZ = expA - expB + 0x3FD;
+ sigA = ( sigA | UINT64_C( 0x0010000000000000 ) )<<10;
+ sigB = ( sigB | UINT64_C( 0x0010000000000000 ) )<<11;
+ if ( sigB <= ( sigA + sigA ) ) {
+ ++expZ;
+ sigA >>= 1;
+ }
+ sigZ = softfloat_estimateDiv128To64( sigA, 0, sigB );
+ if ( ( sigZ & 0x1FF ) <= 2 ) {
+ term = softfloat_mul64To128( sigB, sigZ );
+ rem = softfloat_sub128( sigA, 0, term.v64, term.v0 );
+ while ( UINT64_C( 0x8000000000000000 ) <= rem.v64 ) {
+ --sigZ;
+ rem = softfloat_add128( rem.v64, rem.v0, 0, sigB );
+ }
+ sigZ |= ( rem.v0 != 0 );
+ }
+ return softfloat_roundPackToF64( signZ, expZ, sigZ );
+ propagateNaN:
+ uiZ = softfloat_propagateNaNF64UI( uiA, uiB );
+ goto uiZ;
+ invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ uiZ = defaultNaNF64UI;
+ goto uiZ;
+ infinity:
+ uiZ = packToF64UI( signZ, 0x7FF, 0 );
+ goto uiZ;
+ zero:
+ uiZ = packToF64UI( signZ, 0, 0 );
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,35 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+bool f64_eq( float64_t a, float64_t b )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ union ui64_f64 uB;
+ uint_fast64_t uiB;
+
+ uA.f = a;
+ uiA = uA.ui;
+ uB.f = b;
+ uiB = uB.ui;
+ if (
+ ( ( expF64UI( uiA ) == 0x7FF ) && fracF64UI( uiA ) )
+ || ( ( expF64UI( uiB ) == 0x7FF ) && fracF64UI( uiB ) )
+ ) {
+ if (
+ softfloat_isSigNaNF64UI( uiA ) || softfloat_isSigNaNF64UI( uiB )
+ ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ }
+ return false;
+ }
+ return
+ ( uiA == uiB ) || ! ( ( uiA | uiB ) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) );
+
+}
+
new file mode 100755
@@ -0,0 +1,30 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+bool f64_eq_signaling( float64_t a, float64_t b )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ union ui64_f64 uB;
+ uint_fast64_t uiB;
+
+ uA.f = a;
+ uiA = uA.ui;
+ uB.f = b;
+ uiB = uB.ui;
+ if (
+ ( ( expF64UI( uiA ) == 0x7FF ) && fracF64UI( uiA ) )
+ || ( ( expF64UI( uiB ) == 0x7FF ) && fracF64UI( uiB ) )
+ ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return false;
+ }
+ return
+ ( uiA == uiB ) || ! ( ( uiA | uiB ) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) );
+
+}
+
new file mode 100755
@@ -0,0 +1,16 @@
+
+#include <stdbool.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+bool f64_isSignalingNaN( float64_t a )
+{
+ union ui64_f64 uA;
+
+ uA.f = a;
+ return softfloat_isSigNaNF64UI( uA.ui );
+
+}
+
new file mode 100755
@@ -0,0 +1,35 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+bool f64_le( float64_t a, float64_t b )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ union ui64_f64 uB;
+ uint_fast64_t uiB;
+ bool signA, signB;
+
+ uA.f = a;
+ uiA = uA.ui;
+ uB.f = b;
+ uiB = uB.ui;
+ if (
+ ( ( expF64UI( uiA ) == 0x7FF ) && fracF64UI( uiA ) )
+ || ( ( expF64UI( uiB ) == 0x7FF ) && fracF64UI( uiB ) )
+ ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return false;
+ }
+ signA = signF64UI( uiA );
+ signB = signF64UI( uiB );
+ return
+ ( signA != signB )
+ ? signA || ! ( ( uiA | uiB ) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) )
+ : ( uiA == uiB ) || ( signA ^ ( uiA < uiB ) );
+
+}
+
new file mode 100755
@@ -0,0 +1,40 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+bool f64_le_quiet( float64_t a, float64_t b )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ union ui64_f64 uB;
+ uint_fast64_t uiB;
+ bool signA, signB;
+
+ uA.f = a;
+ uiA = uA.ui;
+ uB.f = b;
+ uiB = uB.ui;
+ if (
+ ( ( expF64UI( uiA ) == 0x7FF ) && fracF64UI( uiA ) )
+ || ( ( expF64UI( uiB ) == 0x7FF ) && fracF64UI( uiB ) )
+ ) {
+ if (
+ softfloat_isSigNaNF64UI( uiA ) || softfloat_isSigNaNF64UI( uiB )
+ ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ }
+ return false;
+ }
+ signA = signF64UI( uiA );
+ signB = signF64UI( uiB );
+ return
+ ( signA != signB )
+ ? signA || ! ( ( uiA | uiB ) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) )
+ : ( uiA == uiB ) || ( signA ^ ( uiA < uiB ) );
+
+}
+
new file mode 100755
@@ -0,0 +1,35 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+bool f64_lt( float64_t a, float64_t b )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ union ui64_f64 uB;
+ uint_fast64_t uiB;
+ bool signA, signB;
+
+ uA.f = a;
+ uiA = uA.ui;
+ uB.f = b;
+ uiB = uB.ui;
+ if (
+ ( ( expF64UI( uiA ) == 0x7FF ) && fracF64UI( uiA ) )
+ || ( ( expF64UI( uiB ) == 0x7FF ) && fracF64UI( uiB ) )
+ ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return false;
+ }
+ signA = signF64UI( uiA );
+ signB = signF64UI( uiB );
+ return
+ ( signA != signB )
+ ? signA && ( ( uiA | uiB ) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) )
+ : ( uiA != uiB ) && ( signA ^ ( uiA < uiB ) );
+
+}
+
new file mode 100755
@@ -0,0 +1,40 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+bool f64_lt_quiet( float64_t a, float64_t b )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ union ui64_f64 uB;
+ uint_fast64_t uiB;
+ bool signA, signB;
+
+ uA.f = a;
+ uiA = uA.ui;
+ uB.f = b;
+ uiB = uB.ui;
+ if (
+ ( ( expF64UI( uiA ) == 0x7FF ) && fracF64UI( uiA ) )
+ || ( ( expF64UI( uiB ) == 0x7FF ) && fracF64UI( uiB ) )
+ ) {
+ if (
+ softfloat_isSigNaNF64UI( uiA ) || softfloat_isSigNaNF64UI( uiB )
+ ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ }
+ return false;
+ }
+ signA = signF64UI( uiA );
+ signB = signF64UI( uiB );
+ return
+ ( signA != signB )
+ ? signA && ( ( uiA | uiB ) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) )
+ : ( uiA != uiB ) && ( signA ^ ( uiA < uiB ) );
+
+}
+
new file mode 100755
@@ -0,0 +1,91 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float64_t f64_mul( float64_t a, float64_t b )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ bool signA;
+ int_fast16_t expA;
+ uint_fast64_t sigA;
+ union ui64_f64 uB;
+ uint_fast64_t uiB;
+ bool signB;
+ int_fast16_t expB;
+ uint_fast64_t sigB;
+ bool signZ;
+ uint_fast64_t magBits;
+ struct exp16_sig64 normExpSig;
+ int_fast16_t expZ;
+ struct uint128 sigZ128;
+ uint_fast64_t sigZ, uiZ;
+ union ui64_f64 uZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ signA = signF64UI( uiA );
+ expA = expF64UI( uiA );
+ sigA = fracF64UI( uiA );
+ uB.f = b;
+ uiB = uB.ui;
+ signB = signF64UI( uiB );
+ expB = expF64UI( uiB );
+ sigB = fracF64UI( uiB );
+ signZ = signA ^ signB;
+ if ( expA == 0x7FF ) {
+ if ( sigA || ( ( expB == 0x7FF ) && sigB ) ) goto propagateNaN;
+ magBits = expB | sigB;
+ goto infArg;
+ }
+ if ( expB == 0x7FF ) {
+ if ( sigB ) goto propagateNaN;
+ magBits = expA | sigA;
+ goto infArg;
+ }
+ if ( ! expA ) {
+ if ( ! sigA ) goto zero;
+ normExpSig = softfloat_normSubnormalF64Sig( sigA );
+ expA = normExpSig.exp;
+ sigA = normExpSig.sig;
+ }
+ if ( ! expB ) {
+ if ( ! sigB ) goto zero;
+ normExpSig = softfloat_normSubnormalF64Sig( sigB );
+ expB = normExpSig.exp;
+ sigB = normExpSig.sig;
+ }
+ expZ = expA + expB - 0x3FF;
+ sigA = ( sigA | UINT64_C( 0x0010000000000000 ) )<<10;
+ sigB = ( sigB | UINT64_C( 0x0010000000000000 ) )<<11;
+ sigZ128 = softfloat_mul64To128( sigA, sigB );
+ sigZ = sigZ128.v64 | ( sigZ128.v0 != 0 );
+ if ( sigZ < UINT64_C( 0x4000000000000000 ) ) {
+ --expZ;
+ sigZ <<= 1;
+ }
+ return softfloat_roundPackToF64( signZ, expZ, sigZ );
+ propagateNaN:
+ uiZ = softfloat_propagateNaNF64UI( uiA, uiB );
+ goto uiZ;
+ infArg:
+ if ( ! magBits ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ uiZ = defaultNaNF64UI;
+ } else {
+ uiZ = packToF64UI( signZ, 0x7FF, 0 );
+ }
+ goto uiZ;
+ zero:
+ uiZ = packToF64UI( signZ, 0, 0 );
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,25 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float64_t f64_mulAdd( float64_t a, float64_t b, float64_t c )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ union ui64_f64 uB;
+ uint_fast64_t uiB;
+ union ui64_f64 uC;
+ uint_fast64_t uiC;
+
+ uA.f = a;
+ uiA = uA.ui;
+ uB.f = b;
+ uiB = uB.ui;
+ uC.f = c;
+ uiC = uC.ui;
+ return softfloat_mulAddF64( 0, uiA, uiB, uiC );
+
+}
+
new file mode 100755
@@ -0,0 +1,113 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float64_t f64_rem( float64_t a, float64_t b )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ bool signA;
+ int_fast16_t expA;
+ uint_fast64_t sigA;
+ union ui64_f64 uB;
+ uint_fast64_t uiB;
+// bool signB;
+ int_fast16_t expB;
+ uint_fast64_t sigB;
+ struct exp16_sig64 normExpSig;
+ int_fast16_t expDiff;
+ uint_fast64_t q, alternateSigA;
+ uint64_t sigMean;
+ bool signZ;
+ uint_fast64_t uiZ;
+ union ui64_f64 uZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ signA = signF64UI( uiA );
+ expA = expF64UI( uiA );
+ sigA = fracF64UI( uiA );
+ uB.f = b;
+ uiB = uB.ui;
+// signB = signF64UI( uiB );
+ expB = expF64UI( uiB );
+ sigB = fracF64UI( uiB );
+ if ( expA == 0x7FF ) {
+ if ( sigA || ( ( expB == 0x7FF ) && sigB ) ) goto propagateNaN;
+ goto invalid;
+ }
+ if ( expB == 0x7FF ) {
+ if ( sigB ) goto propagateNaN;
+ return a;
+ }
+ if ( ! expB ) {
+ if ( ! sigB ) goto invalid;
+ normExpSig = softfloat_normSubnormalF64Sig( sigB );
+ expB = normExpSig.exp;
+ sigB = normExpSig.sig;
+ }
+ if ( ! expA ) {
+ if ( ! sigA ) return a;
+ normExpSig = softfloat_normSubnormalF64Sig( sigA );
+ expA = normExpSig.exp;
+ sigA = normExpSig.sig;
+ }
+ expDiff = expA - expB;
+ sigA = ( sigA | UINT64_C( 0x0010000000000000 ) )<<11;
+ sigB = ( sigB | UINT64_C( 0x0010000000000000 ) )<<11;
+ if ( expDiff < 0 ) {
+ if ( expDiff < -1 ) return a;
+ sigA >>= 1;
+ }
+ q = ( sigB <= sigA );
+ if ( q ) sigA -= sigB;
+ expDiff -= 64;
+ while ( 0 < expDiff ) {
+ q = softfloat_estimateDiv128To64( sigA, 0, sigB );
+ q = ( 2 < q ) ? q - 2 : 0;
+ sigA = - ( ( sigB>>2 ) * q );
+ expDiff -= 62;
+ }
+ expDiff += 64;
+ if ( 0 < expDiff ) {
+ q = softfloat_estimateDiv128To64( sigA, 0, sigB );
+ q = ( 2 < q ) ? q - 2 : 0;
+ q >>= 64 - expDiff;
+ sigB >>= 2;
+ sigA = ( ( sigA>>1 )<<( expDiff - 1 ) ) - sigB * q;
+ } else {
+ sigA >>= 2;
+ sigB >>= 2;
+ }
+ do {
+ alternateSigA = sigA;
+ ++q;
+ sigA -= sigB;
+ } while ( sigA < UINT64_C( 0x8000000000000000 ) );
+ sigMean = sigA + alternateSigA;
+ if (
+ ( UINT64_C( 0x8000000000000000 ) <= sigMean )
+ || ( ! sigMean && ( q & 1 ) )
+ ) {
+ sigA = alternateSigA;
+ }
+ signZ = ( UINT64_C( 0x8000000000000000 ) <= sigA );
+ if ( signZ ) sigA = - sigA;
+ return softfloat_normRoundPackToF64( signA ^ signZ, expB, sigA );
+ propagateNaN:
+ uiZ = softfloat_propagateNaNF64UI( uiA, uiB );
+ goto uiZ;
+ invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ uiZ = defaultNaNF64UI;
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,80 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float64_t f64_roundToInt( float64_t a, int_fast8_t roundingMode, bool exact )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ int_fast16_t expA;
+ uint_fast64_t uiZ;
+ bool signA;
+ uint_fast64_t lastBitMask, roundBitsMask;
+ union ui64_f64 uZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ expA = expF64UI( uiA );
+ if ( 0x433 <= expA ) {
+ if ( ( expA == 0x7FF ) && fracF64UI( uiA ) ) {
+ uiZ = softfloat_propagateNaNF64UI( uiA, 0 );
+ goto uiZ;
+ }
+ return a;
+ }
+ if ( expA <= 0x3FE ) {
+ if ( ! ( uiA & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) ) return a;
+ if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact;
+ signA = signF64UI( uiA );
+ switch ( roundingMode ) {
+ case softfloat_round_nearest_even:
+ if ( ( expA == 0x3FE ) && fracF64UI( uiA ) ) {
+ uiZ = packToF64UI( signA, 0x3FF, 0 );
+ goto uiZ;
+ }
+ break;
+ case softfloat_round_min:
+ uiZ = signA ? UINT64_C( 0xBFF0000000000000 ) : 0;
+ goto uiZ;
+ case softfloat_round_max:
+ uiZ =
+ signA ? UINT64_C( 0x8000000000000000 )
+ : UINT64_C( 0x3FF0000000000000 );
+ goto uiZ;
+ case softfloat_round_nearest_maxMag:
+ if ( expA == 0x3FE ) {
+ uiZ = packToF64UI( signA, 0x3FF, 0 );
+ goto uiZ;
+ }
+ break;
+ }
+ uiZ = packToF64UI( signA, 0, 0 );
+ goto uiZ;
+ }
+ lastBitMask = (uint_fast64_t) 1<<( 0x433 - expA );
+ roundBitsMask = lastBitMask - 1;
+ uiZ = uiA;
+ if ( roundingMode == softfloat_round_nearest_maxMag ) {
+ uiZ += lastBitMask>>1;
+ } else if ( roundingMode == softfloat_round_nearest_even ) {
+ uiZ += lastBitMask>>1;
+ if ( ! ( uiZ & roundBitsMask ) ) uiZ &= ~ lastBitMask;
+ } else if ( roundingMode != softfloat_round_minMag ) {
+ if ( signF64UI( uiZ ) ^ ( roundingMode == softfloat_round_max ) ) {
+ uiZ += roundBitsMask;
+ }
+ }
+ uiZ &= ~ roundBitsMask;
+ if ( exact && ( uiZ != uiA ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,74 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float64_t f64_sqrt( float64_t a )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ bool signA;
+ int_fast16_t expA;
+ uint_fast64_t sigA, uiZ;
+ struct exp16_sig64 normExpSig;
+ int_fast16_t expZ;
+ uint_fast32_t sigZ32;
+ uint_fast64_t sigZ;
+ struct uint128 term, rem;
+ union ui64_f64 uZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ signA = signF64UI( uiA );
+ expA = expF64UI( uiA );
+ sigA = fracF64UI( uiA );
+ if ( expA == 0x7FF ) {
+ if ( sigA ) {
+ uiZ = softfloat_propagateNaNF64UI( uiA, 0 );
+ goto uiZ;
+ }
+ if ( ! signA ) return a;
+ goto invalid;
+ }
+ if ( signA ) {
+ if ( ! ( expA | sigA ) ) return a;
+ goto invalid;
+ }
+ if ( ! expA ) {
+ if ( ! sigA ) return a;
+ normExpSig = softfloat_normSubnormalF64Sig( sigA );
+ expA = normExpSig.exp;
+ sigA = normExpSig.sig;
+ }
+ expZ = ( ( expA - 0x3FF )>>1 ) + 0x3FE;
+ sigA |= UINT64_C( 0x0010000000000000 );
+ sigZ32 = softfloat_estimateSqrt32( expA, sigA>>21 );
+ sigA <<= 9 - ( expA & 1 );
+ sigZ =
+ softfloat_estimateDiv128To64( sigA, 0, (uint_fast64_t) sigZ32<<32 )
+ + ( (uint_fast64_t) sigZ32<<30 );
+ if ( ( sigZ & 0x1FF ) <= 5 ) {
+ term = softfloat_mul64To128( sigZ, sigZ );
+ rem = softfloat_sub128( sigA, 0, term.v64, term.v0 );
+ while ( UINT64_C( 0x8000000000000000 ) <= rem.v64 ) {
+ --sigZ;
+ rem =
+ softfloat_add128(
+ rem.v64, rem.v0, sigZ>>63, (uint64_t) ( sigZ<<1 ) );
+ }
+ sigZ |= ( ( rem.v64 | rem.v0 ) != 0 );
+ }
+ return softfloat_roundPackToF64( 0, expZ, sigZ );
+ invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ uiZ = defaultNaNF64UI;
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,29 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float64_t f64_sub( float64_t a, float64_t b )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ bool signA;
+ union ui64_f64 uB;
+ uint_fast64_t uiB;
+ bool signB;
+ float64_t ( *magsRoutine )( uint_fast64_t, uint_fast64_t, bool );
+
+ uA.f = a;
+ uiA = uA.ui;
+ signA = signF64UI( uiA );
+ uB.f = b;
+ uiB = uB.ui;
+ signB = signF64UI( uiB );
+ magsRoutine =
+ ( signA == signB ) ? softfloat_subMagsF64 : softfloat_addMagsF64;
+ return magsRoutine( uiA, uiB, signA );
+
+}
+
new file mode 100755
@@ -0,0 +1,43 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float32_t f64_to_f32( float64_t a )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ bool sign;
+ int_fast16_t exp;
+ uint_fast64_t sig;
+ uint_fast32_t uiZ, sig32;
+ union ui32_f32 uZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ sign = signF64UI( uiA );
+ exp = expF64UI( uiA );
+ sig = fracF64UI( uiA );
+ if ( exp == 0x7FF ) {
+ uiZ =
+ sig ? softfloat_commonNaNToF32UI(
+ softfloat_f64UIToCommonNaN( uiA ) )
+ : packToF32UI( sign, 0xFF, 0 );
+ goto uiZ;
+ }
+ sig32 = softfloat_shortShift64RightJam( sig, 22 );
+ if ( ! ( exp | sig32 ) ) {
+ uiZ = packToF32UI( sign, 0, 0 );
+ goto uiZ;
+ }
+ return softfloat_roundPackToF32( sign, exp - 0x381, sig32 | 0x40000000 );
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,30 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+int_fast32_t f64_to_i32( float64_t a, int_fast8_t roundingMode, bool exact )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ bool sign;
+ int_fast16_t exp;
+ uint_fast64_t sig;
+ int_fast16_t shiftCount;
+
+ uA.f = a;
+ uiA = uA.ui;
+ sign = signF64UI( uiA );
+ exp = expF64UI( uiA );
+ sig = fracF64UI( uiA );
+ if ( ( exp == 0x7FF ) && sig ) sign = 0;
+ if ( exp ) sig |= UINT64_C( 0x0010000000000000 );
+ shiftCount = 0x42C - exp;
+ if ( 0 < shiftCount ) sig = softfloat_shift64RightJam( sig, shiftCount );
+ return softfloat_roundPackToI32( sign, sig, roundingMode, exact );
+
+}
+
new file mode 100755
@@ -0,0 +1,50 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+int_fast32_t f64_to_i32_r_minMag( float64_t a, bool exact )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ int_fast16_t exp;
+ uint_fast64_t sig;
+ bool sign;
+ int_fast16_t shiftCount;
+ uint_fast32_t absZ;
+ union { uint32_t ui; int32_t i; } uZ;
+ int_fast32_t z;
+
+ uA.f = a;
+ uiA = uA.ui;
+ exp = expF64UI( uiA );
+ sig = fracF64UI( uiA );
+ if ( exp < 0x3FF ) {
+ if ( exact && ( exp | sig ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return 0;
+ }
+ sign = signF64UI( uiA );
+ if ( 0x41E < exp ) {
+ if ( ( exp == 0x7FF ) && sig ) sign = 0;
+ goto invalid;
+ }
+ sig |= UINT64_C( 0x0010000000000000 );
+ shiftCount = 0x433 - exp;
+ absZ = sig>>shiftCount;
+ uZ.ui = sign ? - absZ : absZ;
+ z = uZ.i;
+ if ( ( z < 0 ) != sign ) goto invalid;
+ if ( exact && ( (uint_fast64_t) absZ<<shiftCount != sig ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return z;
+ invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return sign ? -0x7FFFFFFF - 1 : 0x7FFFFFFF;
+
+}
+
new file mode 100755
@@ -0,0 +1,46 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+int_fast64_t f64_to_i64( float64_t a, int_fast8_t roundingMode, bool exact )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ bool sign;
+ int_fast16_t exp;
+ uint_fast64_t sig;
+ int_fast16_t shiftCount;
+ struct uint64_extra sigExtra;
+
+ uA.f = a;
+ uiA = uA.ui;
+ sign = signF64UI( uiA );
+ exp = expF64UI( uiA );
+ sig = fracF64UI( uiA );
+ if ( exp ) sig |= UINT64_C( 0x0010000000000000 );
+ shiftCount = 0x433 - exp;
+ if ( shiftCount <= 0 ) {
+ if ( 0x43E < exp ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return
+ ! sign
+ || ( ( exp == 0x7FF )
+ && fracF64UI( uiA ) )
+ ? INT64_C( 0x7FFFFFFFFFFFFFFF )
+ : - INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1;
+ }
+ sigExtra.v = sig<<( - shiftCount );
+ sigExtra.extra = 0;
+ } else {
+ sigExtra = softfloat_shift64ExtraRightJam( sig, 0, shiftCount );
+ }
+ return
+ softfloat_roundPackToI64(
+ sign, sigExtra.v, sigExtra.extra, roundingMode, exact );
+
+}
+
new file mode 100755
@@ -0,0 +1,52 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+int_fast64_t f64_to_i64_r_minMag( float64_t a, bool exact )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ bool sign;
+ int_fast16_t exp;
+ uint_fast64_t sig;
+ int_fast16_t shiftCount;
+ int_fast64_t absZ;
+
+ uA.f = a;
+ uiA = uA.ui;
+ sign = signF64UI( uiA );
+ exp = expF64UI( uiA );
+ sig = fracF64UI( uiA );
+ shiftCount = exp - 0x433;
+ if ( 0 <= shiftCount ) {
+ if ( 0x43E <= exp ) {
+ if ( uiA != packToF64UI( 1, 0x43E, 0 ) ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ if ( ! sign || ( ( exp == 0x7FF ) && sig ) ) {
+ return INT64_C( 0x7FFFFFFFFFFFFFFF );
+ }
+ }
+ return - INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1;
+ }
+ sig |= UINT64_C( 0x0010000000000000 );
+ absZ = sig<<shiftCount;
+ } else {
+ if ( exp < 0x3FF ) {
+ if ( exact && ( exp | sig ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return 0;
+ }
+ sig |= UINT64_C( 0x0010000000000000 );
+ absZ = sig>>( - shiftCount );
+ if ( exact && (uint64_t) ( sig<<( shiftCount & 63 ) ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ }
+ return sign ? - absZ : absZ;
+
+}
+
new file mode 100755
@@ -0,0 +1,29 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+uint_fast32_t f64_to_ui32( float64_t a, int_fast8_t roundingMode, bool exact )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ bool sign;
+ int_fast16_t exp;
+ uint_fast64_t sig;
+ int_fast16_t shiftCount;
+
+ uA.f = a;
+ uiA = uA.ui;
+ sign = signF64UI( uiA );
+ exp = expF64UI( uiA );
+ sig = fracF64UI( uiA );
+ if ( exp ) sig |= UINT64_C( 0x0010000000000000 );
+ shiftCount = 0x42C - exp;
+ if ( 0 < shiftCount ) sig = softfloat_shift64RightJam( sig, shiftCount );
+ return softfloat_roundPackToUI32( sign, sig, roundingMode, exact );
+
+}
+
new file mode 100755
@@ -0,0 +1,40 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+uint_fast32_t f64_to_ui32_r_minMag( float64_t a, bool exact )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ int_fast16_t exp;
+ uint_fast64_t sig;
+ int_fast16_t shiftCount;
+ uint_fast32_t z;
+
+ uA.f = a;
+ uiA = uA.ui;
+ exp = expF64UI( uiA );
+ sig = fracF64UI( uiA );
+ if ( exp < 0x3FF ) {
+ if ( exact && ( exp | sig ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return 0;
+ }
+ if ( signF64UI( uiA ) || ( 0x41E < exp ) ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return 0xFFFFFFFF;
+ }
+ sig |= UINT64_C( 0x0010000000000000 );
+ shiftCount = 0x433 - exp;
+ z = sig>>shiftCount;
+ if ( exact && ( (uint_fast64_t) z<<shiftCount != sig ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,41 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+uint_fast64_t f64_to_ui64( float64_t a, int_fast8_t roundingMode, bool exact )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ bool sign;
+ int_fast16_t exp;
+ uint_fast64_t sig;
+ int_fast16_t shiftCount;
+ struct uint64_extra sigExtra;
+
+ uA.f = a;
+ uiA = uA.ui;
+ sign = signF64UI( uiA );
+ exp = expF64UI( uiA );
+ sig = fracF64UI( uiA );
+ if ( exp ) sig |= UINT64_C( 0x0010000000000000 );
+ shiftCount = 0x433 - exp;
+ if ( shiftCount <= 0 ) {
+ if ( 0x43E < exp ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return UINT64_C( 0xFFFFFFFFFFFFFFFF );
+ }
+ sigExtra.v = sig<<( - shiftCount );
+ sigExtra.extra = 0;
+ } else {
+ sigExtra = softfloat_shift64ExtraRightJam( sig, 0, shiftCount );
+ }
+ return
+ softfloat_roundPackToUI64(
+ sign, sigExtra.v, sigExtra.extra, roundingMode, exact );
+
+}
+
new file mode 100755
@@ -0,0 +1,45 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+uint_fast64_t f64_to_ui64_r_minMag( float64_t a, bool exact )
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+ int_fast16_t exp;
+ uint_fast64_t sig;
+ int_fast16_t shiftCount;
+ uint_fast64_t z;
+
+ uA.f = a;
+ uiA = uA.ui;
+ exp = expF64UI( uiA );
+ sig = fracF64UI( uiA );
+ if ( exp < 0x3FF ) {
+ if ( exact && ( exp | sig ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return 0;
+ }
+ if ( signF64UI( uiA ) ) goto invalid;
+ shiftCount = exp - 0x433;
+ if ( 0 <= shiftCount ) {
+ if ( 0x43E < exp ) goto invalid;
+ z = ( sig | UINT64_C( 0x0010000000000000 ) )<<shiftCount;
+ } else {
+ sig |= UINT64_C( 0x0010000000000000 );
+ z = sig>>( - shiftCount );
+ if ( exact && (uint64_t) ( sig<<( shiftCount & 63 ) ) ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ }
+ return z;
+ invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return UINT64_C( 0xFFFFFFFFFFFFFFFF );
+
+}
+
new file mode 100755
@@ -0,0 +1,21 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float32_t i32_to_f32( int_fast32_t a )
+{
+ bool sign;
+ union ui32_f32 uZ;
+
+ sign = ( a < 0 );
+ if ( ! ( a & 0x7FFFFFFF ) ) {
+ uZ.ui = sign ? packToF32UI( 1, 0x9E, 0 ) : 0;
+ return uZ.f;
+ }
+ return softfloat_normRoundPackToF32( sign, 0x9C, sign ? - a : a );
+
+}
+
new file mode 100755
@@ -0,0 +1,31 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float64_t i32_to_f64( int_fast32_t a )
+{
+ uint_fast64_t uiZ;
+ bool sign;
+ uint_fast32_t absA;
+ int shiftCount;
+ union ui64_f64 uZ;
+
+ if ( ! a ) {
+ uiZ = 0;
+ } else {
+ sign = ( a < 0 );
+ absA = sign ? - a : a;
+ shiftCount = softfloat_countLeadingZeros32( absA ) + 21;
+ uiZ =
+ packToF64UI(
+ sign, 0x432 - shiftCount, (uint_fast64_t) absA<<shiftCount );
+ }
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,36 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float32_t i64_to_f32( int_fast64_t a )
+{
+ bool sign;
+ uint_fast64_t absA;
+ int shiftCount;
+ union ui32_f32 u;
+ uint_fast32_t sig;
+
+ sign = ( a < 0 );
+ absA = sign ? - (uint_fast64_t) a : a;
+ shiftCount = softfloat_countLeadingZeros64( absA ) - 40;
+ if ( 0 <= shiftCount ) {
+ u.ui =
+ a ? packToF32UI(
+ sign, 0x95 - shiftCount, (uint_fast32_t) absA<<shiftCount )
+ : 0;
+ return u.f;
+ } else {
+ shiftCount += 7;
+ sig =
+ ( shiftCount < 0 )
+ ? softfloat_shortShift64RightJam( absA, - shiftCount )
+ : (uint_fast32_t) absA<<shiftCount;
+ return softfloat_roundPackToF32( sign, 0x9C - shiftCount, sig );
+ }
+
+}
+
new file mode 100755
@@ -0,0 +1,21 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float64_t i64_to_f64( int_fast64_t a )
+{
+ bool sign;
+ union ui64_f64 uZ;
+
+ sign = ( a < 0 );
+ if ( ! ( a & UINT64_C( 0x7FFFFFFFFFFFFFFF ) ) ) {
+ uZ.ui = sign ? packToF64UI( 1, 0x43E, 0 ) : 0;
+ return uZ.f;
+ }
+ return softfloat_normRoundPackToF64( sign, 0x43C, sign ? - a : a );
+
+}
+
new file mode 100755
@@ -0,0 +1,232 @@
+
+/*** UPDATE COMMENTS. ***/
+
+#include "softfloat_types.h"
+
+union ui32_f32 { uint32_t ui; float32_t f; };
+union ui64_f64 { uint64_t ui; float64_t f; };
+#ifdef LITTLEENDIAN
+union ui128_f128 { uint64_t ui0, ui64; float128_t f; };
+#else
+union ui128_f128 { uint64_t ui64, ui0; float128_t f; };
+#endif
+
+enum {
+ softfloat_mulAdd_subC = 1,
+ softfloat_mulAdd_subProd = 2
+};
+
+uint_fast32_t
+ softfloat_roundPackToUI32( bool, uint_fast64_t, int_fast8_t, bool );
+uint_fast64_t
+ softfloat_roundPackToUI64(
+ bool, uint_fast64_t, uint_fast64_t, int_fast8_t, bool );
+/*----------------------------------------------------------------------------
+| Takes a 64-bit fixed-point value `absZ' with binary point between bits 6
+| and 7, and returns the properly rounded 32-bit integer corresponding to the
+| input. If `zSign' is 1, the input is negated before being converted to an
+| integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point input
+| is simply rounded to an integer, with the inexact exception raised if the
+| input cannot be represented exactly as an integer. However, if the fixed-
+| point input is too large, the invalid exception is raised and the largest
+| positive or negative integer is returned.
+*----------------------------------------------------------------------------*/
+int_fast32_t
+ softfloat_roundPackToI32( bool, uint_fast64_t, int_fast8_t, bool );
+/*----------------------------------------------------------------------------
+| Takes the 128-bit fixed-point value formed by concatenating `absZ0' and
+| `absZ1', with binary point between bits 63 and 64 (between the input words),
+| and returns the properly rounded 64-bit integer corresponding to the input.
+| If `zSign' is 1, the input is negated before being converted to an integer.
+| Ordinarily, the fixed-point input is simply rounded to an integer, with
+| the inexact exception raised if the input cannot be represented exactly as
+| an integer. However, if the fixed-point input is too large, the invalid
+| exception is raised and the largest positive or negative integer is
+| returned.
+*----------------------------------------------------------------------------*/
+int_fast64_t
+ softfloat_roundPackToI64(
+ bool, uint_fast64_t, uint_fast64_t, int_fast8_t, bool );
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point value `a' is a NaN;
+| otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+#define isNaNF32UI( ui ) (0xFF000000<(uint32_t)((uint_fast32_t)(ui)<<1))
+/*----------------------------------------------------------------------------
+| Returns the sign bit of the single-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+#define signF32UI( a ) ((bool)((uint32_t)(a)>>31))
+/*----------------------------------------------------------------------------
+| Returns the exponent bits of the single-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+#define expF32UI( a ) ((int_fast16_t)((a)>>23)&0xFF)
+/*----------------------------------------------------------------------------
+| Returns the fraction bits of the single-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+#define fracF32UI( a ) ((a)&0x007FFFFF)
+/*----------------------------------------------------------------------------
+| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
+| single-precision floating-point value, returning the result. After being
+| shifted into the proper positions, the three fields are simply added
+| together to form the result. This means that any integer portion of `zSig'
+| will be added into the exponent. Since a properly normalized significand
+| will have an integer portion equal to 1, the `zExp' input should be 1 less
+| than the desired result exponent whenever `zSig' is a complete, normalized
+| significand.
+*----------------------------------------------------------------------------*/
+#define packToF32UI( sign, exp, sig ) (((uint32_t)(sign)<<31)+((uint32_t)(exp)<<23)+(sig))
+
+/*----------------------------------------------------------------------------
+| Normalizes the subnormal single-precision floating-point value represented
+| by the denormalized significand `aSig'. The normalized exponent and
+| significand are stored at the locations pointed to by `zExpPtr' and
+| `zSigPtr', respectively.
+*----------------------------------------------------------------------------*/
+struct exp16_sig32 { int_fast16_t exp; uint_fast32_t sig; };
+struct exp16_sig32 softfloat_normSubnormalF32Sig( uint_fast32_t );
+
+/*----------------------------------------------------------------------------
+| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+| and significand `zSig', and returns the proper single-precision floating-
+| point value corresponding to the abstract input. Ordinarily, the abstract
+| value is simply rounded and packed into the single-precision format, with
+| the inexact exception raised if the abstract input cannot be represented
+| exactly. However, if the abstract value is too large, the overflow and
+| inexact exceptions are raised and an infinity or maximal finite value is
+| returned. If the abstract value is too small, the input value is rounded to
+| a subnormal number, and the underflow and inexact exceptions are raised if
+| the abstract input cannot be represented exactly as a subnormal single-
+| precision floating-point number.
+| The input significand `zSig' has its binary point between bits 30
+| and 29, which is 7 bits to the left of the usual location. This shifted
+| significand must be normalized or smaller. If `zSig' is not normalized,
+| `zExp' must be 0; in that case, the result returned is a subnormal number,
+| and it must not require rounding. In the usual case that `zSig' is
+| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
+| The handling of underflow and overflow follows the IEC/IEEE Standard for
+| Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+float32_t softfloat_roundPackToF32( bool, int_fast16_t, uint_fast32_t );
+/*----------------------------------------------------------------------------
+| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+| and significand `zSig', and returns the proper single-precision floating-
+| point value corresponding to the abstract input. This routine is just like
+| `roundAndPackFloat32' except that `zSig' does not have to be normalized.
+| Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
+| floating-point exponent.
+*----------------------------------------------------------------------------*/
+float32_t softfloat_normRoundPackToF32( bool, int_fast16_t, uint_fast32_t );
+
+/*----------------------------------------------------------------------------
+| Returns the result of adding the absolute values of the single-precision
+| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
+| before being returned. `zSign' is ignored if the result is a NaN.
+| The addition is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+float32_t softfloat_addMagsF32( uint_fast32_t, uint_fast32_t, bool );
+/*----------------------------------------------------------------------------
+| Returns the result of subtracting the absolute values of the single-
+| precision floating-point values `a' and `b'. If `zSign' is 1, the
+| difference is negated before being returned. `zSign' is ignored if the
+| result is a NaN. The subtraction is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+float32_t softfloat_subMagsF32( uint_fast32_t, uint_fast32_t, bool );
+/*----------------------------------------------------------------------------
+*----------------------------------------------------------------------------*/
+float32_t
+ softfloat_mulAddF32( int, uint_fast32_t, uint_fast32_t, uint_fast32_t );
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point value `a' is a NaN;
+| otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+#define isNaNF64UI( ui ) (UINT64_C(0xFFE0000000000000)<(uint64_t)((uint_fast64_t)(ui)<<1))
+/*----------------------------------------------------------------------------
+| Returns the sign bit of the double-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+#define signF64UI( a ) ((bool)((uint64_t)(a)>>63))
+/*----------------------------------------------------------------------------
+| Returns the exponent bits of the double-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+#define expF64UI( a ) ((int_fast16_t)((a)>>52)&0x7FF)
+/*----------------------------------------------------------------------------
+| Returns the fraction bits of the double-precision floating-point value `a'.
+*----------------------------------------------------------------------------*/
+#define fracF64UI( a ) ((a)&UINT64_C(0x000FFFFFFFFFFFFF))
+/*----------------------------------------------------------------------------
+| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
+| double-precision floating-point value, returning the result. After being
+| shifted into the proper positions, the three fields are simply added
+| together to form the result. This means that any integer portion of `zSig'
+| will be added into the exponent. Since a properly normalized significand
+| will have an integer portion equal to 1, the `zExp' input should be 1 less
+| than the desired result exponent whenever `zSig' is a complete, normalized
+| significand.
+*----------------------------------------------------------------------------*/
+#define packToF64UI( sign, exp, sig ) (((uint64_t)(sign)<<63)+((uint64_t)(exp)<<52)+(sig))
+
+/*----------------------------------------------------------------------------
+| Normalizes the subnormal double-precision floating-point value represented
+| by the denormalized significand `aSig'. The normalized exponent and
+| significand are stored at the locations pointed to by `zExpPtr' and
+| `zSigPtr', respectively.
+*----------------------------------------------------------------------------*/
+struct exp16_sig64 { int_fast16_t exp; uint_fast64_t sig; };
+struct exp16_sig64 softfloat_normSubnormalF64Sig( uint_fast64_t );
+
+/*----------------------------------------------------------------------------
+| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+| and significand `zSig', and returns the proper double-precision floating-
+| point value corresponding to the abstract input. Ordinarily, the abstract
+| value is simply rounded and packed into the double-precision format, with
+| the inexact exception raised if the abstract input cannot be represented
+| exactly. However, if the abstract value is too large, the overflow and
+| inexact exceptions are raised and an infinity or maximal finite value is
+| returned. If the abstract value is too small, the input value is rounded
+| to a subnormal number, and the underflow and inexact exceptions are raised
+| if the abstract input cannot be represented exactly as a subnormal double-
+| precision floating-point number.
+| The input significand `zSig' has its binary point between bits 62
+| and 61, which is 10 bits to the left of the usual location. This shifted
+| significand must be normalized or smaller. If `zSig' is not normalized,
+| `zExp' must be 0; in that case, the result returned is a subnormal number,
+| and it must not require rounding. In the usual case that `zSig' is
+| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
+| The handling of underflow and overflow follows the IEC/IEEE Standard for
+| Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+float64_t softfloat_roundPackToF64( bool, int_fast16_t, uint_fast64_t );
+/*----------------------------------------------------------------------------
+| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
+| and significand `zSig', and returns the proper double-precision floating-
+| point value corresponding to the abstract input. This routine is just like
+| `roundAndPackFloat64' except that `zSig' does not have to be normalized.
+| Bit 63 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
+| floating-point exponent.
+*----------------------------------------------------------------------------*/
+float64_t softfloat_normRoundPackToF64( bool, int_fast16_t, uint_fast64_t );
+
+/*----------------------------------------------------------------------------
+| Returns the result of adding the absolute values of the double-precision
+| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
+| before being returned. `zSign' is ignored if the result is a NaN.
+| The addition is performed according to the IEC/IEEE Standard for Binary
+| Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+float64_t softfloat_addMagsF64( uint_fast64_t, uint_fast64_t, bool );
+/*----------------------------------------------------------------------------
+| Returns the result of subtracting the absolute values of the double-
+| precision floating-point values `a' and `b'. If `zSign' is 1, the
+| difference is negated before being returned. `zSign' is ignored if the
+| result is a NaN. The subtraction is performed according to the IEC/IEEE
+| Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+float64_t softfloat_subMagsF64( uint_fast64_t, uint_fast64_t, bool );
+/*----------------------------------------------------------------------------
+*----------------------------------------------------------------------------*/
+float64_t
+ softfloat_mulAddF64( int, uint_fast64_t, uint_fast64_t, uint_fast64_t );
+
new file mode 100755
@@ -0,0 +1,42 @@
+
+/*============================================================================
+
+*** FIX.
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2b.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+/*----------------------------------------------------------------------------
+*----------------------------------------------------------------------------*/
+#define LITTLEENDIAN
+
+#ifndef UINT64_C
+# define UINT64_C(x) (x ## ULL)
+# define INT64_C(x) (x ## LL)
+#endif
new file mode 100755
@@ -0,0 +1,628 @@
+
+/*============================================================================
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 3.
+
+*** UPDATE
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/*** CHANGE TO USE `fast' INTEGER TYPES? ***/
+/*** ADD 80-BIT FUNCTIONS? ***/
+
+#ifdef LITTLEENDIAN
+struct uintx80 { uint64_t v0; uint16_t v64; };
+struct uint128 { uint64_t v0, v64; };
+struct uint192 { uint64_t v0, v64, v128; };
+struct uint256 { uint64_t v0, v64, v128, v192; };
+#else
+struct uintx80 { uint16_t v64; uint64_t v0; };
+struct uint128 { uint64_t v64, v0; };
+struct uint192 { uint64_t v128, v64, v0; };
+struct uint256 { uint64_t v256, v128, v64, v0; };
+#endif
+
+struct uint64_extra { uint64_t v, extra; };
+struct uint128_extra { uint64_t v64; uint64_t v0; uint64_t extra; };
+
+
+/*** SHIFT COUNTS CANNOT BE ZERO. MUST CHECK BEFORE CALLING! ***/
+
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1'
+| is equal to the 128-bit value formed by concatenating `b0' and `b1'.
+| Otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 1 <= INLINE_LEVEL )
+INLINE bool
+ softfloat_eq128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
+ { return ( a64 == b64 ) && ( a0 == b0 ); }
+#else
+bool softfloat_eq128( uint64_t, uint64_t, uint64_t, uint64_t );
+#endif
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
+| than or equal to the 128-bit value formed by concatenating `b0' and `b1'.
+| Otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 1 <= INLINE_LEVEL )
+INLINE bool
+ softfloat_le128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
+ { return ( a64 < b64 ) || ( ( a64 == b64 ) && ( a0 <= b0 ) ); }
+#else
+bool softfloat_le128( uint64_t, uint64_t, uint64_t, uint64_t );
+#endif
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
+| than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise,
+| returns 0.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 1 <= INLINE_LEVEL )
+INLINE bool
+ softfloat_lt128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
+ { return ( a64 < b64 ) || ( ( a64 == b64 ) && ( a0 < b0 ) ); }
+#else
+bool softfloat_lt128( uint64_t, uint64_t, uint64_t, uint64_t );
+#endif
+
+/*----------------------------------------------------------------------------
+| Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the
+| number of bits given in `count'. Any bits shifted off are lost. The value
+| of `count' must be less than 64. The result is broken into two 64-bit
+| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 2 <= INLINE_LEVEL )
+INLINE struct uint128
+ softfloat_shortShift128Left( uint64_t a64, uint64_t a0, unsigned int count )
+{
+ struct uint128 z;
+ z.v64 = a64<<count | a0>>( ( - count ) & 63 );
+ z.v0 = a0<<count;
+ return z;
+}
+#else
+struct uint128 softfloat_shortShift128Left( uint64_t, uint64_t, unsigned int );
+#endif
+
+/*----------------------------------------------------------------------------
+| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left
+| by the number of bits given in `count'. Any bits shifted off are lost.
+| The value of `count' must be less than 64. The result is broken into three
+| 64-bit pieces which are stored at the locations pointed to by `z0Ptr',
+| `z1Ptr', and `z2Ptr'.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 3 <= INLINE_LEVEL )
+INLINE struct uint192
+ softfloat_shortShift192Left(
+ uint64_t a128, uint64_t a64, uint64_t a0, unsigned int count )
+{
+ unsigned int negCount = - count;
+ struct uint192 z;
+ z.v128 = a128<<count | a64>>( negCount & 63 );
+ z.v64 = a64<<count | a0>>( negCount & 63 );
+ z.v0 = a0<<count;
+ return z;
+}
+#else
+struct uint192
+ softfloat_shortShift192Left( uint64_t, uint64_t, uint64_t, unsigned int );
+#endif
+
+/*----------------------------------------------------------------------------
+| Shifts `a' right by the number of bits given in `count'. If any nonzero
+| bits are shifted off, they are ``jammed'' into the least significant bit of
+| the result by setting the least significant bit to 1. The value of `count'
+| can be arbitrarily large; in particular, if `count' is greater than 32, the
+| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
+| The result is stored in the location pointed to by `zPtr'.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 2 <= INLINE_LEVEL )
+INLINE uint32_t softfloat_shift32RightJam( uint32_t a, unsigned int count )
+{
+ return
+ ( count < 32 )
+ ? a>>count | ( (uint32_t) ( a<<( ( - count ) & 31 ) ) != 0 )
+ : ( a != 0 );
+}
+#else
+uint32_t softfloat_shift32RightJam( uint32_t, unsigned int );
+#endif
+
+/*----------------------------------------------------------------------------
+| Shift count is less than 32.
+*----------------------------------------------------------------------------*/
+#if defined INLINE
+INLINE uint32_t softfloat_shortShift32Right1Jam( uint32_t a )
+ { return a>>1 | ( a & 1 ); }
+#else
+uint32_t softfloat_shortShift32Right1Jam( uint32_t );
+#endif
+
+/*----------------------------------------------------------------------------
+| Shifts `a' right by the number of bits given in `count'. If any nonzero
+| bits are shifted off, they are ``jammed'' into the least significant bit of
+| the result by setting the least significant bit to 1. The value of `count'
+| can be arbitrarily large; in particular, if `count' is greater than 64, the
+| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
+| The result is stored in the location pointed to by `zPtr'.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 3 <= INLINE_LEVEL )
+INLINE uint64_t softfloat_shift64RightJam( uint64_t a, unsigned int count )
+{
+ return
+ ( count < 64 )
+ ? a>>count | ( (uint64_t) ( a<<( ( - count ) & 63 ) ) != 0 )
+ : ( a != 0 );
+}
+#else
+uint64_t softfloat_shift64RightJam( uint64_t, unsigned int );
+#endif
+
+/*----------------------------------------------------------------------------
+| Shift count is less than 64.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 2 <= INLINE_LEVEL )
+INLINE uint64_t
+ softfloat_shortShift64RightJam( uint64_t a, unsigned int count )
+ { return a>>count | ( ( a & ( ( (uint64_t) 1<<count ) - 1 ) ) != 0 ); }
+#else
+uint64_t softfloat_shortShift64RightJam( uint64_t, unsigned int );
+#endif
+
+/*----------------------------------------------------------------------------
+| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64
+| _plus_ the number of bits given in `count'. The shifted result is at most
+| 64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The
+| bits shifted off form a second 64-bit result as follows: The _last_ bit
+| shifted off is the most-significant bit of the extra result, and the other
+| 63 bits of the extra result are all zero if and only if _all_but_the_last_
+| bits shifted off were all zero. This extra result is stored in the location
+| pointed to by `z1Ptr'. The value of `count' can be arbitrarily large.
+| (This routine makes more sense if `a0' and `a1' are considered to form
+| a fixed-point value with binary point between `a0' and `a1'. This fixed-
+| point value is shifted right by the number of bits given in `count', and
+| the integer part of the result is returned at the location pointed to by
+| `z0Ptr'. The fractional part of the result may be slightly corrupted as
+| described above, and is returned at the location pointed to by `z1Ptr'.)
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 3 <= INLINE_LEVEL )
+INLINE struct uint64_extra
+ softfloat_shift64ExtraRightJam(
+ uint64_t a, uint64_t extra, unsigned int count )
+{
+ struct uint64_extra z;
+ if ( count < 64 ) {
+ z.v = a>>count;
+ z.extra = a<<( ( - count ) & 63 );
+ } else {
+ z.v = 0;
+ z.extra = ( count == 64 ) ? a : ( a != 0 );
+ }
+ z.extra |= ( extra != 0 );
+ return z;
+}
+#else
+struct uint64_extra
+ softfloat_shift64ExtraRightJam( uint64_t, uint64_t, unsigned int );
+#endif
+
+/*----------------------------------------------------------------------------
+| Shift count is less than 64.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 2 <= INLINE_LEVEL )
+INLINE struct uint64_extra
+ softfloat_shortShift64ExtraRightJam(
+ uint64_t a, uint64_t extra, unsigned int count )
+{
+ struct uint64_extra z;
+ z.v = a>>count;
+ z.extra = a<<( ( - count ) & 63 ) | ( extra != 0 );
+ return z;
+}
+#else
+struct uint64_extra
+ softfloat_shortShift64ExtraRightJam( uint64_t, uint64_t, unsigned int );
+#endif
+
+/*----------------------------------------------------------------------------
+| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
+| number of bits given in `count'. Any bits shifted off are lost. The value
+| of `count' can be arbitrarily large; in particular, if `count' is greater
+| than 128, the result will be 0. The result is broken into two 64-bit pieces
+| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+*----------------------------------------------------------------------------*/
+/*----------------------------------------------------------------------------
+| Shift count is less than 64.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 2 <= INLINE_LEVEL )
+INLINE struct uint128
+ softfloat_shortShift128Right( uint64_t a64, uint64_t a0, unsigned int count )
+{
+ struct uint128 z;
+ z.v64 = a64>>count;
+ z.v0 = a64<<( ( - count ) & 63 ) | a0>>count;
+ return z;
+}
+#else
+struct uint128
+ softfloat_shortShift128Right( uint64_t, uint64_t, unsigned int );
+#endif
+
+/*----------------------------------------------------------------------------
+| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
+| number of bits given in `count'. If any nonzero bits are shifted off, they
+| are ``jammed'' into the least significant bit of the result by setting the
+| least significant bit to 1. The value of `count' can be arbitrarily large;
+| in particular, if `count' is greater than 128, the result will be either
+| 0 or 1, depending on whether the concatenation of `a0' and `a1' is zero or
+| nonzero. The result is broken into two 64-bit pieces which are stored at
+| the locations pointed to by `z0Ptr' and `z1Ptr'.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 4 <= INLINE_LEVEL )
+INLINE struct uint128
+ softfloat_shift128RightJam( uint64_t a64, uint64_t a0, unsigned int count )
+{
+ unsigned int negCount;
+ struct uint128 z;
+ if ( count < 64 ) {
+ negCount = - count;
+ z.v64 = a64>>( count & 63 );
+ z.v0 =
+ a64<<( negCount & 63 ) | a0>>count
+ | ( (uint64_t) ( a0<<( negCount & 63 ) ) != 0 );
+ } else {
+ z.v64 = 0;
+ z.v0 =
+ ( count < 128 )
+ ? a64>>( count & 63 )
+ | ( ( ( a64 & ( ( (uint64_t) 1<<( count & 63 ) ) - 1 ) )
+ | a0 )
+ != 0 )
+ : ( ( a64 | a0 ) != 0 );
+ }
+ return z;
+}
+#else
+struct uint128
+ softfloat_shift128RightJam( uint64_t, uint64_t, unsigned int );
+#endif
+
+/*----------------------------------------------------------------------------
+| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right
+| by 64 _plus_ the number of bits given in `count'. The shifted result is
+| at most 128 nonzero bits; these are broken into two 64-bit pieces which are
+| stored at the locations pointed to by `z0Ptr' and `z1Ptr'. The bits shifted
+| off form a third 64-bit result as follows: The _last_ bit shifted off is
+| the most-significant bit of the extra result, and the other 63 bits of the
+| extra result are all zero if and only if _all_but_the_last_ bits shifted off
+| were all zero. This extra result is stored in the location pointed to by
+| `z2Ptr'. The value of `count' can be arbitrarily large.
+| (This routine makes more sense if `a0', `a1', and `a2' are considered
+| to form a fixed-point value with binary point between `a1' and `a2'. This
+| fixed-point value is shifted right by the number of bits given in `count',
+| and the integer part of the result is returned at the locations pointed to
+| by `z0Ptr' and `z1Ptr'. The fractional part of the result may be slightly
+| corrupted as described above, and is returned at the location pointed to by
+| `z2Ptr'.)
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 5 <= INLINE_LEVEL )
+INLINE struct uint128_extra
+ softfloat_shift128ExtraRightJam(
+ uint64_t a64, uint64_t a0, uint64_t extra, unsigned int count )
+{
+ unsigned int negCount = - count;
+ struct uint128_extra z;
+ if ( count < 64 ) {
+ z.v64 = a64>>count;
+ z.v0 = a64<<( negCount & 63 ) | a0>>count;
+ z.extra = a0<<( negCount & 63 );
+ } else {
+ z.v64 = 0;
+ if ( count == 64 ) {
+ z.v0 = a64;
+ z.extra = a0;
+ } else {
+ extra |= a0;
+ if ( count < 128 ) {
+ z.v0 = a64>>( count & 63 );
+ z.extra = a64<<( negCount & 63 );
+ } else {
+ z.v0 = 0;
+ z.extra = ( count == 128 ) ? a64 : ( a64 != 0 );
+ }
+ }
+ }
+ z.extra |= ( extra != 0 );
+ return z;
+}
+#else
+struct uint128_extra
+ softfloat_shift128ExtraRightJam( uint64_t, uint64_t, uint64_t, unsigned int );
+#endif
+
+/*----------------------------------------------------------------------------
+| Shift count is less than 64.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 3 <= INLINE_LEVEL )
+INLINE struct uint128_extra
+ softfloat_shortShift128ExtraRightJam(
+ uint64_t a64, uint64_t a0, uint64_t extra, unsigned int count )
+{
+ unsigned int negCount = - count;
+ struct uint128_extra z;
+ z.v64 = a64>>count;
+ z.v0 = a64<<( negCount & 63 ) | a0>>count;
+ z.extra = a0<<( negCount & 63 ) | ( extra != 0 );
+ return z;
+}
+#else
+struct uint128_extra
+ softfloat_shortShift128ExtraRightJam(
+ uint64_t, uint64_t, uint64_t, unsigned int );
+#endif
+
+extern const uint8_t softfloat_countLeadingZeros8[ 256 ];
+
+/*----------------------------------------------------------------------------
+| Returns the number of leading 0 bits before the most-significant 1 bit of
+| `a'. If `a' is zero, 32 is returned.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 2 <= INLINE_LEVEL )
+INLINE int softfloat_countLeadingZeros32( uint32_t a )
+{
+ int count = 0;
+ if ( a < 0x10000 ) {
+ count = 16;
+ a <<= 16;
+ }
+ if ( a < 0x1000000 ) {
+ count += 8;
+ a <<= 8;
+ }
+ count += softfloat_countLeadingZeros8[ a>>24 ];
+ return count;
+}
+#else
+int softfloat_countLeadingZeros32( uint32_t );
+#endif
+
+/*----------------------------------------------------------------------------
+| Returns the number of leading 0 bits before the most-significant 1 bit of
+| `a'. If `a' is zero, 64 is returned.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 4 <= INLINE_LEVEL )
+INLINE int softfloat_countLeadingZeros64( uint64_t a )
+{
+ int count = 32;
+ uint32_t a32 = a;
+ if ( UINT64_C( 0x100000000 ) <= a ) {
+ count = 0;
+ a32 = a>>32;
+ }
+ /*------------------------------------------------------------------------
+ | From here, result is current count + count leading zeros of `a32'.
+ *------------------------------------------------------------------------*/
+ if ( a32 < 0x10000 ) {
+ count += 16;
+ a32 <<= 16;
+ }
+ if ( a32 < 0x1000000 ) {
+ count += 8;
+ a32 <<= 8;
+ }
+ count += softfloat_countLeadingZeros8[ a32>>24 ];
+ return count;
+}
+#else
+int softfloat_countLeadingZeros64( uint64_t );
+#endif
+
+/*----------------------------------------------------------------------------
+| Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit
+| value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so
+| any carry out is lost. The result is broken into two 64-bit pieces which
+| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 2 <= INLINE_LEVEL )
+INLINE struct uint128
+ softfloat_add128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
+{
+ struct uint128 z;
+ z.v0 = a0 + b0;
+ z.v64 = a64 + b64;
+ z.v64 += ( z.v0 < a0 );
+ return z;
+}
+#else
+struct uint128 softfloat_add128( uint64_t, uint64_t, uint64_t, uint64_t );
+#endif
+
+/*----------------------------------------------------------------------------
+| Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the
+| 192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is
+| modulo 2^192, so any carry out is lost. The result is broken into three
+| 64-bit pieces which are stored at the locations pointed to by `z0Ptr',
+| `z1Ptr', and `z2Ptr'.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 3 <= INLINE_LEVEL )
+INLINE struct uint192
+ softfloat_add192(
+ uint64_t a128,
+ uint64_t a64,
+ uint64_t a0,
+ uint64_t b128,
+ uint64_t b64,
+ uint64_t b0
+ )
+{
+ struct uint192 z;
+ unsigned int carry64, carry128;
+ z.v0 = a0 + b0;
+ carry64 = ( z.v0 < a0 );
+ z.v64 = a64 + b64;
+ carry128 = ( z.v64 < a64 );
+ z.v128 = a128 + b128;
+ z.v64 += carry64;
+ carry128 += ( z.v64 < carry64 );
+ z.v128 += carry128;
+ return z;
+}
+#else
+struct uint192
+ softfloat_add192(
+ uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t );
+#endif
+
+/*----------------------------------------------------------------------------
+| Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the
+| 128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo
+| 2^128, so any borrow out (carry out) is lost. The result is broken into two
+| 64-bit pieces which are stored at the locations pointed to by `z0Ptr' and
+| `z1Ptr'.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 2 <= INLINE_LEVEL )
+INLINE struct uint128
+ softfloat_sub128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
+{
+ struct uint128 z;
+ z.v0 = a0 - b0;
+ z.v64 = a64 - b64;
+ z.v64 -= ( a0 < b0 );
+ return z;
+}
+#else
+struct uint128 softfloat_sub128( uint64_t, uint64_t, uint64_t, uint64_t );
+#endif
+
+/*----------------------------------------------------------------------------
+| Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2'
+| from the 192-bit value formed by concatenating `a0', `a1', and `a2'.
+| Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The
+| result is broken into three 64-bit pieces which are stored at the locations
+| pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 3 <= INLINE_LEVEL )
+INLINE struct uint192
+ softfloat_sub192(
+ uint64_t a128,
+ uint64_t a64,
+ uint64_t a0,
+ uint64_t b128,
+ uint64_t b64,
+ uint64_t b0
+ )
+{
+ struct uint192 z;
+ unsigned int borrow64, borrow128;
+ z.v0 = a0 - b0;
+ borrow64 = ( a0 < b0 );
+ z.v64 = a64 - b64;
+ borrow128 = ( a64 < b64 );
+ z.v128 = a128 - b128;
+ borrow128 += ( z.v64 < borrow64 );
+ z.v64 -= borrow64;
+ z.v128 -= borrow128;
+ return z;
+}
+#else
+struct uint192
+ softfloat_sub192(
+ uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t );
+#endif
+
+/*----------------------------------------------------------------------------
+| Multiplies `a' by `b' to obtain a 128-bit product. The product is broken
+| into two 64-bit pieces which are stored at the locations pointed to by
+| `z0Ptr' and `z1Ptr'.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 4 <= INLINE_LEVEL )
+INLINE struct uint128 softfloat_mul64To128( uint64_t a, uint64_t b )
+{
+ uint32_t a32 = a>>32;
+ uint32_t a0 = a;
+ uint32_t b32 = b>>32;
+ uint32_t b0 = b;
+ struct uint128 z;
+ uint64_t mid1, mid2, mid;
+ z.v0 = (uint64_t) a0 * b0;
+ mid1 = (uint64_t) a32 * b0;
+ mid2 = (uint64_t) a0 * b32;
+ z.v64 = (uint64_t) a32 * b32;
+ mid = mid1 + mid2;
+ z.v64 += ( (uint64_t) ( mid < mid1 ) )<<32 | mid>>32;
+ mid <<= 32;
+ z.v0 += mid;
+ z.v64 += ( z.v0 < mid );
+ return z;
+}
+#else
+struct uint128 softfloat_mul64To128( uint64_t, uint64_t );
+#endif
+
+/*----------------------------------------------------------------------------
+| Multiplies the 128-bit value formed by concatenating `a0' and `a1' by
+| `b' to obtain a 192-bit product. The product is broken into three 64-bit
+| pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
+| `z2Ptr'.
+*----------------------------------------------------------------------------*/
+struct uint192 softfloat_mul128By64To192( uint64_t, uint64_t, uint64_t );
+/*----------------------------------------------------------------------------
+| Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the
+| 128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit
+| product. The product is broken into four 64-bit pieces which are stored at
+| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
+*----------------------------------------------------------------------------*/
+struct uint256 softfloat_mul128To256( uint64_t, uint64_t, uint64_t, uint64_t );
+
+/*----------------------------------------------------------------------------
+| Returns an approximation to the 64-bit integer quotient obtained by dividing
+| `b' into the 128-bit value formed by concatenating `a0' and `a1'. The
+| divisor `b' must be at least 2^63. If q is the exact quotient truncated
+| toward zero, the approximation returned lies between q and q + 2 inclusive.
+| If the exact quotient q is larger than 64 bits, the maximum positive 64-bit
+| unsigned integer is returned.
+*----------------------------------------------------------------------------*/
+uint64_t softfloat_estimateDiv128To64( uint64_t, uint64_t, uint64_t );
+
+/*----------------------------------------------------------------------------
+| Returns an approximation to the square root of the 32-bit significand given
+| by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of
+| `aExp' (the least significant bit) is 1, the integer returned approximates
+| 2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp'
+| is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either
+| case, the approximation returned lies strictly within +/-2 of the exact
+| value.
+*----------------------------------------------------------------------------*/
+uint32_t softfloat_estimateSqrt32( unsigned int, uint32_t );
+
new file mode 100755
@@ -0,0 +1,17 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint128
+ softfloat_add128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
+{
+ struct uint128 z;
+
+ z.v0 = a0 + b0;
+ z.v64 = a64 + b64;
+ z.v64 += ( z.v0 < a0 );
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,30 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint192
+ softfloat_add192(
+ uint64_t a128,
+ uint64_t a64,
+ uint64_t a0,
+ uint64_t b128,
+ uint64_t b64,
+ uint64_t b0
+ )
+{
+ struct uint192 z;
+ unsigned int carry64, carry128;
+
+ z.v0 = a0 + b0;
+ carry64 = ( z.v0 < a0 );
+ z.v64 = a64 + b64;
+ carry128 = ( z.v64 < a64 );
+ z.v128 = a128 + b128;
+ z.v64 += carry64;
+ carry128 += ( z.v64 < carry64 );
+ z.v128 += carry128;
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,75 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "specialize.h"
+
+float32_t
+ softfloat_addMagsF32( uint_fast32_t uiA, uint_fast32_t uiB, bool signZ )
+{
+ int_fast16_t expA;
+ uint_fast32_t sigA;
+ int_fast16_t expB;
+ uint_fast32_t sigB;
+ int_fast16_t expDiff;
+ uint_fast32_t uiZ;
+ int_fast16_t expZ;
+ uint_fast32_t sigZ;
+ union ui32_f32 uZ;
+
+ expA = expF32UI( uiA );
+ sigA = fracF32UI( uiA );
+ expB = expF32UI( uiB );
+ sigB = fracF32UI( uiB );
+ expDiff = expA - expB;
+ sigA <<= 6;
+ sigB <<= 6;
+ if ( ! expDiff ) {
+ if ( expA == 0xFF ) {
+ if ( sigA | sigB ) goto propagateNaN;
+ uiZ = uiA;
+ goto uiZ;
+ }
+ if ( ! expA ) {
+ uiZ = packToF32UI( signZ, 0, ( uiA + uiB ) & 0x7FFFFFFF );
+ goto uiZ;
+ }
+ expZ = expA;
+ sigZ = 0x40000000 + sigA + sigB;
+ } else {
+ if ( expDiff < 0 ) {
+ if ( expB == 0xFF ) {
+ if ( sigB ) goto propagateNaN;
+ uiZ = packToF32UI( signZ, 0xFF, 0 );
+ goto uiZ;
+ }
+ expZ = expB;
+ sigA += expA ? 0x20000000 : sigA;
+ sigA = softfloat_shift32RightJam( sigA, - expDiff );
+ } else {
+ if ( expA == 0xFF ) {
+ if ( sigA ) goto propagateNaN;
+ uiZ = uiA;
+ goto uiZ;
+ }
+ expZ = expA;
+ sigB += expB ? 0x20000000 : sigB;
+ sigB = softfloat_shift32RightJam( sigB, expDiff );
+ }
+ sigZ = 0x20000000 + sigA + sigB;
+ if ( sigZ < 0x40000000 ) {
+ --expZ;
+ sigZ <<= 1;
+ }
+ }
+ return softfloat_roundPackToF32( signZ, expZ, sigZ );
+ propagateNaN:
+ uiZ = softfloat_propagateNaNF32UI( uiA, uiB );
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,77 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "specialize.h"
+
+float64_t
+ softfloat_addMagsF64( uint_fast64_t uiA, uint_fast64_t uiB, bool signZ )
+{
+ int_fast16_t expA;
+ uint_fast64_t sigA;
+ int_fast16_t expB;
+ uint_fast64_t sigB;
+ int_fast16_t expDiff;
+ uint_fast64_t uiZ;
+ int_fast16_t expZ;
+ uint_fast64_t sigZ;
+ union ui64_f64 uZ;
+
+ expA = expF64UI( uiA );
+ sigA = fracF64UI( uiA );
+ expB = expF64UI( uiB );
+ sigB = fracF64UI( uiB );
+ expDiff = expA - expB;
+ sigA <<= 9;
+ sigB <<= 9;
+ if ( ! expDiff ) {
+ if ( expA == 0x7FF ) {
+ if ( sigA | sigB ) goto propagateNaN;
+ uiZ = uiA;
+ goto uiZ;
+ }
+ if ( ! expA ) {
+ uiZ =
+ packToF64UI(
+ signZ, 0, ( uiA + uiB ) & UINT64_C( 0x7FFFFFFFFFFFFFFF ) );
+ goto uiZ;
+ }
+ expZ = expA;
+ sigZ = UINT64_C( 0x4000000000000000 ) + sigA + sigB;
+ } else {
+ if ( expDiff < 0 ) {
+ if ( expB == 0x7FF ) {
+ if ( sigB ) goto propagateNaN;
+ uiZ = packToF64UI( signZ, 0x7FF, 0 );
+ goto uiZ;
+ }
+ expZ = expB;
+ sigA += expA ? UINT64_C( 0x2000000000000000 ) : sigA;
+ sigA = softfloat_shift64RightJam( sigA, - expDiff );
+ } else {
+ if ( expA == 0x7FF ) {
+ if ( sigA ) goto propagateNaN;
+ uiZ = uiA;
+ goto uiZ;
+ }
+ expZ = expA;
+ sigB += expB ? UINT64_C( 0x2000000000000000 ) : sigB;
+ sigB = softfloat_shift64RightJam( sigB, expDiff );
+ }
+ sigZ = UINT64_C( 0x2000000000000000 ) + sigA + sigB;
+ if ( sigZ < UINT64_C( 0x4000000000000000 ) ) {
+ --expZ;
+ sigZ <<= 1;
+ }
+ }
+ return softfloat_roundPackToF64( signZ, expZ, sigZ );
+ propagateNaN:
+ uiZ = softfloat_propagateNaNF64UI( uiA, uiB );
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,17 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "specialize.h"
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the canonical NaN `a' to the single-
+| precision floating-point format.
+*----------------------------------------------------------------------------*/
+
+uint_fast32_t softfloat_commonNaNToF32UI( struct commonNaN a )
+{
+
+ return defaultNaNF32UI;
+
+}
+
new file mode 100755
@@ -0,0 +1,17 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "specialize.h"
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the canonical NaN `a' to the double-
+| precision floating-point format.
+*----------------------------------------------------------------------------*/
+
+uint_fast64_t softfloat_commonNaNToF64UI( struct commonNaN a )
+{
+
+ return defaultNaNF64UI;
+
+}
+
new file mode 100755
@@ -0,0 +1,22 @@
+
+#include <stdint.h>
+#include "primitives.h"
+
+int softfloat_countLeadingZeros32( uint32_t a )
+{
+ int count;
+
+ count = 0;
+ if ( a < 0x10000 ) {
+ count = 16;
+ a <<= 16;
+ }
+ if ( a < 0x1000000 ) {
+ count += 8;
+ a <<= 8;
+ }
+ count += softfloat_countLeadingZeros8[ a>>24 ];
+ return count;
+
+}
+
new file mode 100755
@@ -0,0 +1,32 @@
+
+#include <stdint.h>
+#include "primitives.h"
+#include "platform.h"
+
+int softfloat_countLeadingZeros64( uint64_t a )
+{
+ int count;
+ uint32_t a32;
+
+ count = 32;
+ a32 = a;
+ if ( UINT64_C( 0x100000000 ) <= a ) {
+ count = 0;
+ a32 = a>>32;
+ }
+ /*------------------------------------------------------------------------
+ | From here, result is current count + count leading zeros of `a32'.
+ *------------------------------------------------------------------------*/
+ if ( a32 < 0x10000 ) {
+ count += 16;
+ a32 <<= 16;
+ }
+ if ( a32 < 0x1000000 ) {
+ count += 8;
+ a32 <<= 8;
+ }
+ count += softfloat_countLeadingZeros8[ a32>>24 ];
+ return count;
+
+}
+
new file mode 100755
@@ -0,0 +1,24 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+const uint8_t softfloat_countLeadingZeros8[ 256 ] = {
+ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
new file mode 100755
@@ -0,0 +1,13 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+bool softfloat_eq128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
+{
+
+ return ( a64 == b64 ) && ( a0 == b0 );
+
+}
+
new file mode 100755
@@ -0,0 +1,28 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+uint64_t softfloat_estimateDiv128To64( uint64_t a64, uint64_t a0, uint64_t b )
+{
+ uint32_t b32;
+ uint64_t z;
+ struct uint128 term, rem;
+ uint64_t rem32;
+
+ if ( b <= a64 ) return UINT64_C( 0xFFFFFFFFFFFFFFFF );
+ b32 = b>>32;
+ z = ( (uint64_t) b32<<32 <= a64 ) ? UINT64_C( 0xFFFFFFFF00000000 )
+ : ( a64 / b32 )<<32;
+ term = softfloat_mul64To128( b, z );
+ rem = softfloat_sub128( a64, a0, term.v64, term.v0 );
+ while ( UINT64_C( 0x8000000000000000 ) <= rem.v64 ) {
+ z -= UINT64_C( 0x100000000 );
+ rem = softfloat_add128( rem.v64, rem.v0, b32, (uint64_t) ( b<<32 ) );
+ }
+ rem32 = ( rem.v64<<32 ) | ( rem.v0>>32 );
+ z |= ( (uint64_t) b32<<32 <= rem32 ) ? 0xFFFFFFFF : rem32 / b32;
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,37 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+uint32_t softfloat_estimateSqrt32( unsigned int expA, uint32_t a )
+{
+ static const uint16_t sqrtOddAdjustments[] = {
+ 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
+ 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
+ };
+ static const uint16_t sqrtEvenAdjustments[] = {
+ 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
+ 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
+ };
+ int index;
+ uint32_t z;
+ union { uint32_t ui; int32_t i; } u32;
+
+ index = ( a>>27 ) & 15;
+ if ( expA & 1 ) {
+ z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ];
+ z = ( ( a / z )<<14 ) + ( z<<15 );
+ a >>= 1;
+ } else {
+ z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ];
+ z = a / z + z;
+ z = ( 0x20000 <= z ) ? 0xFFFF8000 : z<<15;
+ if ( z <= a ) {
+ u32.ui = a;
+ return u32.i>>1;
+ }
+ }
+ return (uint32_t) ( ( (uint64_t) a<<31 ) / z ) + ( z>>1 );
+
+}
+
new file mode 100755
@@ -0,0 +1,25 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the single-precision floating-point NaN
+| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+| exception is raised.
+*----------------------------------------------------------------------------*/
+struct commonNaN softfloat_f32UIToCommonNaN( uint_fast32_t uiA )
+{
+ struct commonNaN z;
+
+ if ( softfloat_isSigNaNF32UI( uiA ) ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ }
+ z.sign = uiA>>31;
+ z.v64 = (uint_fast64_t) 0x7FFFF <<41;
+ z.v0 = 0;
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,25 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the double-precision floating-point NaN
+| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+| exception is raised.
+*----------------------------------------------------------------------------*/
+struct commonNaN softfloat_f64UIToCommonNaN( uint_fast64_t uiA )
+{
+ struct commonNaN z;
+
+ if ( softfloat_isSigNaNF64UI( uiA ) ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ }
+ z.sign = uiA>>63;
+ z.v64 = (uint_fast64_t) 0xFFFFFFFFFFFFF <<12;
+ z.v0 = 0;
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,13 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "specialize.h"
+
+bool softfloat_isSigNaNF32UI( uint_fast32_t ui )
+{
+
+ return ( ( ui>>22 & 0x1FF ) == 0x1FE ) && ( ui & 0x003FFFFF );
+
+}
+
new file mode 100755
@@ -0,0 +1,15 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "specialize.h"
+
+bool softfloat_isSigNaNF64UI( uint_fast64_t ui )
+{
+
+ return
+ ( ( ui>>51 & 0xFFF ) == 0xFFE )
+ && ( ui & UINT64_C( 0x0007FFFFFFFFFFFF ) );
+
+}
+
new file mode 100755
@@ -0,0 +1,13 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+bool softfloat_le128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
+{
+
+ return ( a64 < b64 ) || ( ( a64 == b64 ) && ( a0 <= b0 ) );
+
+}
+
new file mode 100755
@@ -0,0 +1,13 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+bool softfloat_lt128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
+{
+
+ return ( a64 < b64 ) || ( ( a64 == b64 ) && ( a0 < b0 ) );
+
+}
+
new file mode 100755
@@ -0,0 +1,20 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint192
+ softfloat_mul128By64To192( uint64_t a64, uint64_t a0, uint64_t b )
+{
+ struct uint128 p0, p64;
+ struct uint192 z;
+
+ p0 = softfloat_mul64To128( a0, b );
+ z.v0 = p0.v0;
+ p64 = softfloat_mul64To128( a64, b );
+ z.v64 = p64.v0 + p0.v64;
+ z.v128 = p64.v64 + ( z.v64 < p64.v0 );
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,28 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint256
+ softfloat_mul128To256( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
+{
+ struct uint128 p0, p64, p128;
+ struct uint256 z;
+
+ p0 = softfloat_mul64To128( a0, b0 );
+ z.v0 = p0.v0;
+ p64 = softfloat_mul64To128( a64, b0 );
+ z.v64 = p64.v0 + p0.v64;
+ z.v128 = p64.v64 + ( z.v64 < p64.v0 );
+ p128 = softfloat_mul64To128( a64, b64 );
+ z.v128 += p128.v0;
+ z.v192 = p128.v64 + ( z.v128 < p128.v0 );
+ p64 = softfloat_mul64To128( a0, b64 );
+ z.v64 += p64.v0;
+ p64.v64 += ( z.v64 < p64.v0 );
+ z.v128 += p64.v64;
+ z.v192 += ( z.v128 < p64.v64 );
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,28 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint128 softfloat_mul64To128( uint64_t a, uint64_t b )
+{
+ uint32_t a32, a0, b32, b0;
+ struct uint128 z;
+ uint64_t mid1, mid2, mid;
+
+ a32 = a>>32;
+ a0 = a;
+ b32 = b>>32;
+ b0 = b;
+ z.v0 = (uint64_t) a0 * b0;
+ mid1 = (uint64_t) a32 * b0;
+ mid2 = (uint64_t) a0 * b32;
+ z.v64 = (uint64_t) a32 * b32;
+ mid = mid1 + mid2;
+ z.v64 += ( (uint64_t) ( mid < mid1 ) )<<32 | mid>>32;
+ mid <<= 32;
+ z.v0 += mid;
+ z.v64 += ( z.v0 < mid );
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,171 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float32_t
+ softfloat_mulAddF32(
+ int op, uint_fast32_t uiA, uint_fast32_t uiB, uint_fast32_t uiC )
+{
+ bool signA;
+ int_fast16_t expA;
+ uint_fast32_t sigA;
+ bool signB;
+ int_fast16_t expB;
+ uint_fast32_t sigB;
+ bool signC;
+ int_fast16_t expC;
+ uint_fast32_t sigC;
+ bool signProd;
+ uint_fast32_t magBits, uiZ;
+ struct exp16_sig32 normExpSig;
+ int_fast16_t expProd;
+ uint_fast64_t sigProd;
+ bool signZ;
+ int_fast16_t expZ;
+ uint_fast32_t sigZ;
+ int_fast16_t expDiff;
+ uint_fast64_t sigZ64, sigC64;
+ int shiftCount;
+ union ui32_f32 uZ;
+
+ signA = signF32UI( uiA );
+ expA = expF32UI( uiA );
+ sigA = fracF32UI( uiA );
+ signB = signF32UI( uiB );
+ expB = expF32UI( uiB );
+ sigB = fracF32UI( uiB );
+ signC = signF32UI( uiC ) ^ ( op == softfloat_mulAdd_subC );
+ expC = expF32UI( uiC );
+ sigC = fracF32UI( uiC );
+ signProd = signA ^ signB ^ ( op == softfloat_mulAdd_subProd );
+ if ( expA == 0xFF ) {
+ if ( sigA || ( ( expB == 0xFF ) && sigB ) ) goto propagateNaN_ABC;
+ magBits = expB | sigB;
+ goto infProdArg;
+ }
+ if ( expB == 0xFF ) {
+ if ( sigB ) goto propagateNaN_ABC;
+ magBits = expA | sigA;
+ goto infProdArg;
+ }
+ if ( expC == 0xFF ) {
+ if ( sigC ) {
+ uiZ = 0;
+ goto propagateNaN_ZC;
+ }
+ uiZ = uiC;
+ goto uiZ;
+ }
+ if ( ! expA ) {
+ if ( ! sigA ) goto zeroProd;
+ normExpSig = softfloat_normSubnormalF32Sig( sigA );
+ expA = normExpSig.exp;
+ sigA = normExpSig.sig;
+ }
+ if ( ! expB ) {
+ if ( ! sigB ) goto zeroProd;
+ normExpSig = softfloat_normSubnormalF32Sig( sigB );
+ expB = normExpSig.exp;
+ sigB = normExpSig.sig;
+ }
+ expProd = expA + expB - 0x7E;
+ sigA = ( sigA | 0x00800000 )<<7;
+ sigB = ( sigB | 0x00800000 )<<7;
+ sigProd = (uint_fast64_t) sigA * sigB;
+ if ( sigProd < UINT64_C( 0x2000000000000000 ) ) {
+ --expProd;
+ sigProd <<= 1;
+ }
+ signZ = signProd;
+ if ( ! expC ) {
+ if ( ! sigC ) {
+ expZ = expProd - 1;
+ sigZ = softfloat_shortShift64RightJam( sigProd, 31 );
+ goto roundPack;
+ }
+ normExpSig = softfloat_normSubnormalF32Sig( sigC );
+ expC = normExpSig.exp;
+ sigC = normExpSig.sig;
+ }
+ sigC = ( sigC | 0x00800000 )<<6;
+ expDiff = expProd - expC;
+ if ( signProd == signC ) {
+ if ( expDiff <= 0 ) {
+ expZ = expC;
+ sigZ = sigC + softfloat_shift64RightJam( sigProd, 32 - expDiff );
+ } else {
+ expZ = expProd;
+ sigZ64 =
+ sigProd
+ + softfloat_shift64RightJam(
+ (uint_fast64_t) sigC<<32, expDiff );
+ sigZ = softfloat_shortShift64RightJam( sigZ64, 32 );
+ }
+ if ( sigZ < 0x40000000 ) {
+ --expZ;
+ sigZ <<= 1;
+ }
+ } else {
+/*** OPTIMIZE BETTER? ***/
+ sigC64 = (uint_fast64_t) sigC<<32;
+ if ( expDiff < 0 ) {
+ signZ = signC;
+ expZ = expC;
+ sigZ64 = sigC64 - softfloat_shift64RightJam( sigProd, - expDiff );
+ } else if ( ! expDiff ) {
+ expZ = expProd;
+ sigZ64 = sigProd - sigC64;
+ if ( ! sigZ64 ) goto completeCancellation;
+ if ( sigZ64 & UINT64_C( 0x8000000000000000 ) ) {
+ signZ ^= 1;
+ sigZ64 = - sigZ64;
+ }
+ } else {
+ expZ = expProd;
+ sigZ64 = sigProd - softfloat_shift64RightJam( sigC64, expDiff );
+ }
+ shiftCount = softfloat_countLeadingZeros64( sigZ64 ) - 1;
+ expZ -= shiftCount;
+ shiftCount -= 32;
+ if ( shiftCount < 0 ) {
+ sigZ = softfloat_shortShift64RightJam( sigZ64, - shiftCount );
+ } else {
+ sigZ = (uint_fast32_t) sigZ64<<shiftCount;
+ }
+ }
+ roundPack:
+ return softfloat_roundPackToF32( signZ, expZ, sigZ );
+ propagateNaN_ABC:
+ uiZ = softfloat_propagateNaNF32UI( uiA, uiB );
+ goto propagateNaN_ZC;
+ infProdArg:
+ if ( magBits ) {
+ uiZ = packToF32UI( signProd, 0xFF, 0 );
+ if ( expC != 0xFF ) goto uiZ;
+ if ( sigC ) goto propagateNaN_ZC;
+ if ( signProd == signC ) goto uiZ;
+ }
+// invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ uiZ = defaultNaNF32UI;
+ propagateNaN_ZC:
+ uiZ = softfloat_propagateNaNF32UI( uiZ, uiC );
+ goto uiZ;
+ zeroProd:
+ uiZ = uiC;
+ if ( ! ( expC | sigC ) && ( signProd != signC ) ) {
+ completeCancellation:
+ uiZ =
+ packToF32UI( softfloat_roundingMode == softfloat_round_min, 0, 0 );
+ }
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,188 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float64_t
+ softfloat_mulAddF64(
+ int op, uint_fast64_t uiA, uint_fast64_t uiB, uint_fast64_t uiC )
+{
+ bool signA;
+ int_fast16_t expA;
+ uint_fast64_t sigA;
+ bool signB;
+ int_fast16_t expB;
+ uint_fast64_t sigB;
+ bool signC;
+ int_fast16_t expC;
+ uint_fast64_t sigC;
+ bool signProd;
+ uint_fast64_t magBits, uiZ;
+ struct exp16_sig64 normExpSig;
+ int_fast16_t expProd;
+ struct uint128 sigProd;
+ bool signZ;
+ int_fast16_t expZ;
+ uint_fast64_t sigZ;
+ int_fast16_t expDiff;
+ struct uint128 sigC128, sigZ128;
+ int shiftCount;
+ union ui64_f64 uZ;
+
+ signA = signF64UI( uiA );
+ expA = expF64UI( uiA );
+ sigA = fracF64UI( uiA );
+ signB = signF64UI( uiB );
+ expB = expF64UI( uiB );
+ sigB = fracF64UI( uiB );
+ signC = signF64UI( uiC ) ^ ( op == softfloat_mulAdd_subC );
+ expC = expF64UI( uiC );
+ sigC = fracF64UI( uiC );
+ signProd = signA ^ signB ^ ( op == softfloat_mulAdd_subProd );
+ if ( expA == 0x7FF ) {
+ if ( sigA || ( ( expB == 0x7FF ) && sigB ) ) goto propagateNaN_ABC;
+ magBits = expB | sigB;
+ goto infProdArg;
+ }
+ if ( expB == 0x7FF ) {
+ if ( sigB ) goto propagateNaN_ABC;
+ magBits = expA | sigA;
+ goto infProdArg;
+ }
+ if ( expC == 0x7FF ) {
+ if ( sigC ) {
+ uiZ = 0;
+ goto propagateNaN_ZC;
+ }
+ uiZ = uiC;
+ goto uiZ;
+ }
+ if ( ! expA ) {
+ if ( ! sigA ) goto zeroProd;
+ normExpSig = softfloat_normSubnormalF64Sig( sigA );
+ expA = normExpSig.exp;
+ sigA = normExpSig.sig;
+ }
+ if ( ! expB ) {
+ if ( ! sigB ) goto zeroProd;
+ normExpSig = softfloat_normSubnormalF64Sig( sigB );
+ expB = normExpSig.exp;
+ sigB = normExpSig.sig;
+ }
+ expProd = expA + expB - 0x3FE;
+ sigA = ( sigA | UINT64_C( 0x0010000000000000 ) )<<10;
+ sigB = ( sigB | UINT64_C( 0x0010000000000000 ) )<<10;
+ sigProd = softfloat_mul64To128( sigA, sigB );
+ if ( sigProd.v64 < UINT64_C( 0x2000000000000000 ) ) {
+ --expProd;
+ sigProd = softfloat_shortShift128Left( sigProd.v64, sigProd.v0, 1 );
+ }
+ signZ = signProd;
+ if ( ! expC ) {
+ if ( ! sigC ) {
+ expZ = expProd - 1;
+ sigZ = sigProd.v64<<1 | ( sigProd.v0 != 0 );
+ goto roundPack;
+ }
+ normExpSig = softfloat_normSubnormalF64Sig( sigC );
+ expC = normExpSig.exp;
+ sigC = normExpSig.sig;
+ }
+ sigC = ( sigC | UINT64_C( 0x0010000000000000 ) )<<9;
+ expDiff = expProd - expC;
+ if ( signProd == signC ) {
+ if ( expDiff <= 0 ) {
+ expZ = expC;
+ if ( expDiff ) {
+ sigProd.v64 =
+ softfloat_shift64RightJam( sigProd.v64, - expDiff );
+ }
+ sigZ = ( sigC + sigProd.v64 ) | ( sigProd.v0 != 0 );
+ } else {
+ expZ = expProd;
+ sigC128 = softfloat_shift128RightJam( sigC, 0, expDiff );
+ sigZ128 =
+ softfloat_add128(
+ sigProd.v64, sigProd.v0, sigC128.v64, sigC128.v0 );
+ sigZ = sigZ128.v64 | ( sigZ128.v0 != 0 );
+ }
+ if ( sigZ < UINT64_C( 0x4000000000000000 ) ) {
+ --expZ;
+ sigZ <<= 1;
+ }
+ } else {
+/*** OPTIMIZE BETTER? ***/
+ if ( expDiff < 0 ) {
+ signZ = signC;
+ expZ = expC;
+ sigProd =
+ softfloat_shift128RightJam(
+ sigProd.v64, sigProd.v0, - expDiff );
+ sigZ128 = softfloat_sub128( sigC, 0, sigProd.v64, sigProd.v0 );
+ } else if ( ! expDiff ) {
+ expZ = expProd;
+ sigZ128 = softfloat_sub128( sigProd.v64, sigProd.v0, sigC, 0 );
+ if ( ! ( sigZ128.v64 | sigZ128.v0 ) ) goto completeCancellation;
+ if ( sigZ128.v64 & UINT64_C( 0x8000000000000000 ) ) {
+ signZ ^= 1;
+ sigZ128 = softfloat_sub128( 0, 0, sigZ128.v64, sigZ128.v0 );
+ }
+ } else {
+ expZ = expProd;
+ sigC128 = softfloat_shift128RightJam( sigC, 0, expDiff );
+ sigZ128 =
+ softfloat_sub128(
+ sigProd.v64, sigProd.v0, sigC128.v64, sigC128.v0 );
+ }
+ if ( ! sigZ128.v64 ) {
+ expZ -= 64;
+ sigZ128.v64 = sigZ128.v0;
+ sigZ128.v0 = 0;
+ }
+ shiftCount = softfloat_countLeadingZeros64( sigZ128.v64 ) - 1;
+ expZ -= shiftCount;
+ if ( shiftCount < 0 ) {
+ sigZ = softfloat_shortShift64RightJam( sigZ128.v64, - shiftCount );
+ } else {
+ sigZ128 =
+ softfloat_shortShift128Left(
+ sigZ128.v64, sigZ128.v0, shiftCount );
+ sigZ = sigZ128.v64;
+ }
+ sigZ |= ( sigZ128.v0 != 0 );
+ }
+ roundPack:
+ return softfloat_roundPackToF64( signZ, expZ, sigZ );
+ propagateNaN_ABC:
+ uiZ = softfloat_propagateNaNF64UI( uiA, uiB );
+ goto propagateNaN_ZC;
+ infProdArg:
+ if ( magBits ) {
+ uiZ = packToF64UI( signProd, 0x7FF, 0 );
+ if ( expC != 0x7FF ) goto uiZ;
+ if ( sigC ) goto propagateNaN_ZC;
+ if ( signProd == signC ) goto uiZ;
+ }
+// invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ uiZ = defaultNaNF64UI;
+ propagateNaN_ZC:
+ uiZ = softfloat_propagateNaNF64UI( uiZ, uiC );
+ goto uiZ;
+ zeroProd:
+ uiZ = uiC;
+ if ( ! ( expC | sigC ) && ( signProd != signC ) ) {
+ completeCancellation:
+ uiZ =
+ packToF64UI( softfloat_roundingMode == softfloat_round_min, 0, 0 );
+ }
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,24 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+
+float32_t
+ softfloat_normRoundPackToF32( bool sign, int_fast16_t exp, uint_fast32_t sig )
+{
+ int shiftCount;
+ union ui32_f32 uZ;
+
+ shiftCount = softfloat_countLeadingZeros32( sig ) - 1;
+ exp -= shiftCount;
+ if ( ( 7 <= shiftCount ) && ( (uint16_t) exp < 0xFD ) ) {
+ uZ.ui = packToF32UI( sign, sig ? exp : 0, sig<<( shiftCount - 7 ) );
+ return uZ.f;
+ } else {
+ return softfloat_roundPackToF32( sign, exp, sig<<shiftCount );
+ }
+
+}
+
new file mode 100755
@@ -0,0 +1,24 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+
+float64_t
+ softfloat_normRoundPackToF64( bool sign, int_fast16_t exp, uint_fast64_t sig )
+{
+ int shiftCount;
+ union ui64_f64 uZ;
+
+ shiftCount = softfloat_countLeadingZeros64( sig ) - 1;
+ exp -= shiftCount;
+ if ( ( 10 <= shiftCount ) && ( (uint16_t) exp < 0x7FD ) ) {
+ uZ.ui = packToF64UI( sign, sig ? exp : 0, sig<<( shiftCount - 10 ) );
+ return uZ.f;
+ } else {
+ return softfloat_roundPackToF64( sign, exp, sig<<shiftCount );
+ }
+
+}
+
new file mode 100755
@@ -0,0 +1,18 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+
+struct exp16_sig32 softfloat_normSubnormalF32Sig( uint_fast32_t sig )
+{
+ int shiftCount;
+ struct exp16_sig32 z;
+
+ shiftCount = softfloat_countLeadingZeros32( sig ) - 8;
+ z.exp = 1 - shiftCount;
+ z.sig = sig<<shiftCount;
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,18 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+
+struct exp16_sig64 softfloat_normSubnormalF64Sig( uint_fast64_t sig )
+{
+ int shiftCount;
+ struct exp16_sig64 z;
+
+ shiftCount = softfloat_countLeadingZeros64( sig ) - 11;
+ z.exp = 1 - shiftCount;
+ z.sig = sig<<shiftCount;
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,25 @@
+
+/*** UPDATE COMMENTS. ***/
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+/*----------------------------------------------------------------------------
+| Takes two single-precision floating-point values `a' and `b', one of which
+| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+| signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+
+uint_fast32_t
+ softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB )
+{
+ if ( softfloat_isSigNaNF32UI( uiA ) | softfloat_isSigNaNF32UI( uiB ) ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ }
+ return defaultNaNF32UI;
+}
+
new file mode 100755
@@ -0,0 +1,25 @@
+
+/*** UPDATE COMMENTS. ***/
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+/*----------------------------------------------------------------------------
+| Takes two double-precision floating-point values `a' and `b', one of which
+| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+| signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+
+uint_fast64_t
+ softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB )
+{
+ if ( softfloat_isSigNaNF64UI( uiA ) | softfloat_isSigNaNF64UI( uiB ) ) {
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ }
+ return defaultNaNF64UI;
+}
+
new file mode 100755
@@ -0,0 +1,65 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float32_t
+ softfloat_roundPackToF32( bool sign, int_fast16_t exp, uint_fast32_t sig )
+{
+ int roundingMode;
+ bool roundNearestEven;
+ int roundIncrement, roundBits;
+ bool isTiny;
+ uint_fast32_t uiZ;
+ union ui32_f32 uZ;
+
+ roundingMode = softfloat_roundingMode;
+ roundNearestEven = ( roundingMode == softfloat_round_nearest_even );
+ roundIncrement = 0x40;
+ if (
+ ! roundNearestEven
+ && ( roundingMode != softfloat_round_nearest_maxMag )
+ ) {
+ roundIncrement =
+ ( roundingMode == softfloat_round_minMag )
+ || ( roundingMode
+ == ( sign ? softfloat_round_max : softfloat_round_min ) )
+ ? 0
+ : 0x7F;
+ }
+ roundBits = sig & 0x7F;
+ if ( 0xFD <= (uint16_t) exp ) {
+ if ( exp < 0 ) {
+ isTiny =
+ ( softfloat_detectTininess
+ == softfloat_tininess_beforeRounding )
+ || ( exp < -1 )
+ || ( sig + roundIncrement < 0x80000000 );
+ sig = softfloat_shift32RightJam( sig, - exp );
+ exp = 0;
+ roundBits = sig & 0x7F;
+ if ( isTiny && roundBits ) {
+ softfloat_raiseFlags( softfloat_flag_underflow );
+ }
+ } else if (
+ ( 0xFD < exp ) || ( 0x80000000 <= sig + roundIncrement )
+ ) {
+ softfloat_raiseFlags(
+ softfloat_flag_overflow | softfloat_flag_inexact );
+ uiZ = packToF32UI( sign, 0xFF, 0 ) - ! roundIncrement;
+ goto uiZ;
+ }
+ }
+ if ( roundBits ) softfloat_exceptionFlags |= softfloat_flag_inexact;
+ sig = ( sig + roundIncrement )>>7;
+ sig &= ~ ( ! ( roundBits ^ 0x40 ) & roundNearestEven );
+ uiZ = packToF32UI( sign, sig ? exp : 0, sig );
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,66 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float64_t
+ softfloat_roundPackToF64( bool sign, int_fast16_t exp, uint_fast64_t sig )
+{
+ int roundingMode;
+ bool roundNearestEven;
+ int roundIncrement, roundBits;
+ bool isTiny;
+ uint_fast64_t uiZ;
+ union ui64_f64 uZ;
+
+ roundingMode = softfloat_roundingMode;
+ roundNearestEven = ( roundingMode == softfloat_round_nearest_even );
+ roundIncrement = 0x200;
+ if (
+ ! roundNearestEven
+ && ( roundingMode != softfloat_round_nearest_maxMag )
+ ) {
+ roundIncrement =
+ ( roundingMode == softfloat_round_minMag )
+ || ( roundingMode
+ == ( sign ? softfloat_round_max : softfloat_round_min ) )
+ ? 0
+ : 0x3FF;
+ }
+ roundBits = sig & 0x3FF;
+ if ( 0x7FD <= (uint16_t) exp ) {
+ if ( exp < 0 ) {
+ isTiny =
+ ( softfloat_detectTininess
+ == softfloat_tininess_beforeRounding )
+ || ( exp < -1 )
+ || ( sig + roundIncrement < UINT64_C( 0x8000000000000000 ) );
+ sig = softfloat_shift64RightJam( sig, - exp );
+ exp = 0;
+ roundBits = sig & 0x3FF;
+ if ( isTiny && roundBits ) {
+ softfloat_raiseFlags( softfloat_flag_underflow );
+ }
+ } else if (
+ ( 0x7FD < exp )
+ || ( UINT64_C( 0x8000000000000000 ) <= sig + roundIncrement )
+ ) {
+ softfloat_raiseFlags(
+ softfloat_flag_overflow | softfloat_flag_inexact );
+ uiZ = packToF64UI( sign, 0x7FF, 0 ) - ! roundIncrement;
+ goto uiZ;
+ }
+ }
+ if ( roundBits ) softfloat_exceptionFlags |= softfloat_flag_inexact;
+ sig = ( sig + roundIncrement )>>10;
+ sig &= ~ ( ! ( roundBits ^ 0x200 ) & roundNearestEven );
+ uiZ = packToF64UI( sign, sig ? exp : 0, sig );
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,48 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+int_fast32_t
+ softfloat_roundPackToI32(
+ bool sign, uint_fast64_t sig, int_fast8_t roundingMode, bool exact )
+{
+ bool roundNearestEven;
+ int roundIncrement, roundBits;
+ uint_fast32_t sig32;
+ union { uint32_t ui; int32_t i; } uZ;
+ int_fast32_t z;
+
+ roundNearestEven = ( roundingMode == softfloat_round_nearest_even );
+ roundIncrement = 0x40;
+ if (
+ ! roundNearestEven
+ && ( roundingMode != softfloat_round_nearest_maxMag )
+ ) {
+ roundIncrement =
+ ( roundingMode == softfloat_round_minMag )
+ || ( roundingMode
+ == ( sign ? softfloat_round_max : softfloat_round_min ) )
+ ? 0
+ : 0x7F;
+ }
+ roundBits = sig & 0x7F;
+ sig += roundIncrement;
+ if ( sig & UINT64_C( 0xFFFFFF8000000000 ) ) goto invalid;
+ sig32 = sig>>7;
+ sig32 &= ~ ( ! ( roundBits ^ 0x40 ) & roundNearestEven );
+ uZ.ui = sign ? - sig32 : sig32;
+ z = uZ.i;
+ if ( z && ( ( z < 0 ) ^ sign ) ) goto invalid;
+ if ( exact && roundBits ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return z;
+ invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return sign ? -0x7FFFFFFF - 1 : 0x7FFFFFFF;
+
+}
+
new file mode 100755
@@ -0,0 +1,52 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+int_fast64_t
+ softfloat_roundPackToI64(
+ bool sign,
+ uint_fast64_t sig64,
+ uint_fast64_t sig0,
+ int_fast8_t roundingMode,
+ bool exact
+ )
+{
+ bool roundNearestEven, increment;
+ union { uint64_t ui; int64_t i; } uZ;
+ int_fast64_t z;
+
+ roundNearestEven = ( roundingMode == softfloat_round_nearest_even );
+ increment = ( UINT64_C( 0x8000000000000000 ) <= sig0 );
+ if (
+ ! roundNearestEven
+ && ( roundingMode != softfloat_round_nearest_maxMag )
+ ) {
+ increment =
+ ( roundingMode != softfloat_round_minMag )
+ && ( roundingMode
+ == ( sign ? softfloat_round_min : softfloat_round_max ) )
+ && sig0;
+ }
+ if ( increment ) {
+ ++sig64;
+ if ( ! sig64 ) goto invalid;
+ sig64 &=
+ ~ ( ! ( sig0 & UINT64_C( 0x7FFFFFFFFFFFFFFF ) )
+ & roundNearestEven );
+ }
+ uZ.ui = sign ? - sig64 : sig64;
+ z = uZ.i;
+ if ( z && ( ( z < 0 ) ^ sign ) ) goto invalid;
+ if ( exact && sig0 ) softfloat_exceptionFlags |= softfloat_flag_inexact;
+ return z;
+ invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return
+ sign ? - INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1
+ : INT64_C( 0x7FFFFFFFFFFFFFFF );
+
+}
+
new file mode 100755
@@ -0,0 +1,44 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+uint_fast32_t
+ softfloat_roundPackToUI32(
+ bool sign, uint_fast64_t sig, int_fast8_t roundingMode, bool exact )
+{
+ bool roundNearestEven;
+ int roundIncrement, roundBits;
+ uint_fast32_t z;
+
+ roundNearestEven = ( roundingMode == softfloat_round_nearest_even );
+ roundIncrement = 0x40;
+ if (
+ ! roundNearestEven
+ && ( roundingMode != softfloat_round_nearest_maxMag )
+ ) {
+ roundIncrement =
+ ( roundingMode == softfloat_round_minMag )
+ || ( roundingMode
+ == ( sign ? softfloat_round_max : softfloat_round_min ) )
+ ? 0
+ : 0x7F;
+ }
+ roundBits = sig & 0x7F;
+ sig += roundIncrement;
+ if ( sig & UINT64_C( 0xFFFFFF8000000000 ) ) goto invalid;
+ z = sig>>7;
+ z &= ~ ( ! ( roundBits ^ 0x40 ) & roundNearestEven );
+ if ( sign && z ) goto invalid;
+ if ( exact && roundBits ) {
+ softfloat_exceptionFlags |= softfloat_flag_inexact;
+ }
+ return z;
+ invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return 0xFFFFFFFF;
+
+}
+
new file mode 100755
@@ -0,0 +1,46 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "softfloat.h"
+
+uint_fast64_t
+ softfloat_roundPackToUI64(
+ bool sign,
+ uint_fast64_t sig64,
+ uint_fast64_t sig0,
+ int_fast8_t roundingMode,
+ bool exact
+ )
+{
+ bool roundNearestEven, increment;
+
+ roundNearestEven = ( roundingMode == softfloat_round_nearest_even );
+ increment = ( UINT64_C( 0x8000000000000000 ) <= sig0 );
+ if (
+ ! roundNearestEven
+ && ( roundingMode != softfloat_round_nearest_maxMag )
+ ) {
+ increment =
+ ( roundingMode != softfloat_round_minMag )
+ && ( roundingMode
+ == ( sign ? softfloat_round_min : softfloat_round_max ) )
+ && sig0;
+ }
+ if ( increment ) {
+ ++sig64;
+ if ( ! sig64 ) goto invalid;
+ sig64 &=
+ ~ ( ! ( sig0 & UINT64_C( 0x7FFFFFFFFFFFFFFF ) )
+ & roundNearestEven );
+ }
+ if ( sign && sig64 ) goto invalid;
+ if ( exact && sig0 ) softfloat_exceptionFlags |= softfloat_flag_inexact;
+ return sig64;
+ invalid:
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ return UINT64_C( 0xFFFFFFFFFFFFFFFF );
+
+}
+
new file mode 100755
@@ -0,0 +1,38 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint128_extra
+ softfloat_shift128ExtraRightJam(
+ uint64_t a64, uint64_t a0, uint64_t extra, unsigned int count )
+{
+ unsigned int negCount;
+ struct uint128_extra z;
+
+ negCount = - count;
+ if ( count < 64 ) {
+ z.v64 = a64>>count;
+ z.v0 = a64<<( negCount & 63 ) | a0>>count;
+ z.extra = a0<<( negCount & 63 );
+ } else {
+ z.v64 = 0;
+ if ( count == 64 ) {
+ z.v0 = a64;
+ z.extra = a0;
+ } else {
+ extra |= a0;
+ if ( count < 128 ) {
+ z.v0 = a64>>( count & 63 );
+ z.extra = a64<<( negCount & 63 );
+ } else {
+ z.v0 = 0;
+ z.extra = ( count == 128 ) ? a64 : ( a64 != 0 );
+ }
+ }
+ }
+ z.extra |= ( extra != 0 );
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,31 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint128
+ softfloat_shift128RightJam( uint64_t a64, uint64_t a0, unsigned int count )
+{
+ unsigned int negCount;
+ struct uint128 z;
+
+ if ( count < 64 ) {
+ negCount = - count;
+ z.v64 = a64>>( count & 63 );
+ z.v0 =
+ a64<<( negCount & 63 ) | a0>>count
+ | ( (uint64_t) ( a0<<( negCount & 63 ) ) != 0 );
+ } else {
+ z.v64 = 0;
+ z.v0 =
+ ( count < 128 )
+ ? a64>>( count & 63 )
+ | ( ( ( a64 & ( ( (uint64_t) 1<<( count & 63 ) ) - 1 ) )
+ | a0 )
+ != 0 )
+ : ( ( a64 | a0 ) != 0 );
+ }
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,15 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+uint32_t softfloat_shift32RightJam( uint32_t a, unsigned int count )
+{
+
+ return
+ ( count < 32 )
+ ? a>>count | ( (uint32_t) ( a<<( ( - count ) & 31 ) ) != 0 )
+ : ( a != 0 );
+
+}
+
new file mode 100755
@@ -0,0 +1,23 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint64_extra
+ softfloat_shift64ExtraRightJam(
+ uint64_t a, uint64_t extra, unsigned int count )
+{
+ struct uint64_extra z;
+
+ if ( count < 64 ) {
+ z.v = a>>count;
+ z.extra = a<<( ( - count ) & 63 );
+ } else {
+ z.v = 0;
+ z.extra = ( count == 64 ) ? a : ( a != 0 );
+ }
+ z.extra |= ( extra != 0 );
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,15 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+uint64_t softfloat_shift64RightJam( uint64_t a, unsigned int count )
+{
+
+ return
+ ( count < 64 )
+ ? a>>count | ( (uint64_t) ( a<<( ( - count ) & 63 ) ) != 0 )
+ : ( a != 0 );
+
+}
+
new file mode 100755
@@ -0,0 +1,20 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint128_extra
+ softfloat_shortShift128ExtraRightJam(
+ uint64_t a64, uint64_t a0, uint64_t extra, unsigned int count )
+{
+ unsigned int negCount;
+ struct uint128_extra z;
+
+ negCount = - count;
+ z.v64 = a64>>count;
+ z.v0 = a64<<( negCount & 63 ) | a0>>count;
+ z.extra = a0<<( negCount & 63 ) | ( extra != 0 );
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,16 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint128
+ softfloat_shortShift128Left( uint64_t a64, uint64_t a0, unsigned int count )
+{
+ struct uint128 z;
+
+ z.v64 = a64<<count | a0>>( ( - count ) & 63 );
+ z.v0 = a0<<count;
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,16 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint128
+ softfloat_shortShift128Right( uint64_t a64, uint64_t a0, unsigned int count )
+{
+ struct uint128 z;
+
+ z.v64 = a64>>count;
+ z.v0 = a64<<( ( - count ) & 63 ) | a0>>count;
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,20 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint192
+ softfloat_shortShift192Left(
+ uint64_t a128, uint64_t a64, uint64_t a0, unsigned int count )
+{
+ unsigned int negCount;
+ struct uint192 z;
+
+ negCount = - count;
+ z.v128 = a128<<count | a64>>( negCount & 63 );
+ z.v64 = a64<<count | a0>>( negCount & 63 );
+ z.v0 = a0<<count;
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,12 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+uint32_t softfloat_shortShift32Right1Jam( uint32_t a )
+{
+
+ return a>>1 | ( a & 1 );
+
+}
+
new file mode 100755
@@ -0,0 +1,17 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint64_extra
+ softfloat_shortShift64ExtraRightJam(
+ uint64_t a, uint64_t extra, unsigned int count )
+{
+ struct uint64_extra z;
+
+ z.v = a>>count;
+ z.extra = a<<( ( - count ) & 63 ) | ( extra != 0 );
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,12 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+uint64_t softfloat_shortShift64RightJam( uint64_t a, unsigned int count )
+{
+
+ return a>>count | ( ( a & ( ( (uint64_t) 1<<count ) - 1 ) ) != 0 );
+
+}
+
new file mode 100755
@@ -0,0 +1,17 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint128
+ softfloat_sub128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 )
+{
+ struct uint128 z;
+
+ z.v0 = a0 - b0;
+ z.v64 = a64 - b64;
+ z.v64 -= ( a0 < b0 );
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,30 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+
+struct uint192
+ softfloat_sub192(
+ uint64_t a128,
+ uint64_t a64,
+ uint64_t a0,
+ uint64_t b128,
+ uint64_t b64,
+ uint64_t b0
+ )
+{
+ struct uint192 z;
+ unsigned int borrow64, borrow128;
+
+ z.v0 = a0 - b0;
+ borrow64 = ( a0 < b0 );
+ z.v64 = a64 - b64;
+ borrow128 = ( a64 < b64 );
+ z.v128 = a128 - b128;
+ borrow128 += ( z.v64 < borrow64 );
+ z.v64 -= borrow64;
+ z.v128 -= borrow128;
+ return z;
+
+}
+
new file mode 100755
@@ -0,0 +1,81 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float32_t
+ softfloat_subMagsF32( uint_fast32_t uiA, uint_fast32_t uiB, bool signZ )
+{
+ int_fast16_t expA;
+ uint_fast32_t sigA;
+ int_fast16_t expB;
+ uint_fast32_t sigB;
+ int_fast16_t expDiff;
+ uint_fast32_t uiZ;
+ int_fast16_t expZ;
+ uint_fast32_t sigZ;
+ union ui32_f32 uZ;
+
+ expA = expF32UI( uiA );
+ sigA = fracF32UI( uiA );
+ expB = expF32UI( uiB );
+ sigB = fracF32UI( uiB );
+ expDiff = expA - expB;
+ sigA <<= 7;
+ sigB <<= 7;
+ if ( 0 < expDiff ) goto expABigger;
+ if ( expDiff < 0 ) goto expBBigger;
+ if ( expA == 0xFF ) {
+ if ( sigA | sigB ) goto propagateNaN;
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ uiZ = defaultNaNF32UI;
+ goto uiZ;
+ }
+ if ( ! expA ) {
+ expA = 1;
+ expB = 1;
+ }
+ if ( sigB < sigA ) goto aBigger;
+ if ( sigA < sigB ) goto bBigger;
+ uiZ = packToF32UI( softfloat_roundingMode == softfloat_round_min, 0, 0 );
+ goto uiZ;
+ expBBigger:
+ if ( expB == 0xFF ) {
+ if ( sigB ) goto propagateNaN;
+ uiZ = packToF32UI( signZ ^ 1, 0xFF, 0 );
+ goto uiZ;
+ }
+ sigA += expA ? 0x40000000 : sigA;
+ sigA = softfloat_shift32RightJam( sigA, - expDiff );
+ sigB |= 0x40000000;
+ bBigger:
+ signZ ^= 1;
+ expZ = expB;
+ sigZ = sigB - sigA;
+ goto normRoundPack;
+ expABigger:
+ if ( expA == 0xFF ) {
+ if ( sigA ) goto propagateNaN;
+ uiZ = uiA;
+ goto uiZ;
+ }
+ sigB += expB ? 0x40000000 : sigB;
+ sigB = softfloat_shift32RightJam( sigB, expDiff );
+ sigA |= 0x40000000;
+ aBigger:
+ expZ = expA;
+ sigZ = sigA - sigB;
+ normRoundPack:
+ return softfloat_normRoundPackToF32( signZ, expZ - 1, sigZ );
+ propagateNaN:
+ uiZ = softfloat_propagateNaNF32UI( uiA, uiB );
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,81 @@
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+float64_t
+ softfloat_subMagsF64( uint_fast64_t uiA, uint_fast64_t uiB, bool signZ )
+{
+ int_fast16_t expA;
+ uint_fast64_t sigA;
+ int_fast16_t expB;
+ uint_fast64_t sigB;
+ int_fast16_t expDiff;
+ uint_fast64_t uiZ;
+ int_fast16_t expZ;
+ uint_fast64_t sigZ;
+ union ui64_f64 uZ;
+
+ expA = expF64UI( uiA );
+ sigA = fracF64UI( uiA );
+ expB = expF64UI( uiB );
+ sigB = fracF64UI( uiB );
+ expDiff = expA - expB;
+ sigA <<= 10;
+ sigB <<= 10;
+ if ( 0 < expDiff ) goto expABigger;
+ if ( expDiff < 0 ) goto expBBigger;
+ if ( expA == 0x7FF ) {
+ if ( sigA | sigB ) goto propagateNaN;
+ softfloat_raiseFlags( softfloat_flag_invalid );
+ uiZ = defaultNaNF64UI;
+ goto uiZ;
+ }
+ if ( ! expA ) {
+ expA = 1;
+ expB = 1;
+ }
+ if ( sigB < sigA ) goto aBigger;
+ if ( sigA < sigB ) goto bBigger;
+ uiZ = packToF64UI( softfloat_roundingMode == softfloat_round_min, 0, 0 );
+ goto uiZ;
+ expBBigger:
+ if ( expB == 0x7FF ) {
+ if ( sigB ) goto propagateNaN;
+ uiZ = packToF64UI( signZ ^ 1, 0x7FF, 0 );
+ goto uiZ;
+ }
+ sigA += expA ? UINT64_C( 0x4000000000000000 ) : sigA;
+ sigA = softfloat_shift64RightJam( sigA, - expDiff );
+ sigB |= UINT64_C( 0x4000000000000000 );
+ bBigger:
+ signZ ^= 1;
+ expZ = expB;
+ sigZ = sigB - sigA;
+ goto normRoundPack;
+ expABigger:
+ if ( expA == 0x7FF ) {
+ if ( sigA ) goto propagateNaN;
+ uiZ = uiA;
+ goto uiZ;
+ }
+ sigB += expB ? UINT64_C( 0x4000000000000000 ) : sigB;
+ sigB = softfloat_shift64RightJam( sigB, expDiff );
+ sigA |= UINT64_C( 0x4000000000000000 );
+ aBigger:
+ expZ = expA;
+ sigZ = sigA - sigB;
+ normRoundPack:
+ return softfloat_normRoundPackToF64( signZ, expZ - 1, sigZ );
+ propagateNaN:
+ uiZ = softfloat_propagateNaNF64UI( uiA, uiB );
+ uiZ:
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100644
new file mode 100755
@@ -0,0 +1,235 @@
+
+#ifndef softfloat_h
+#define softfloat_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*** UPDATE COMMENTS. ***/
+
+/*============================================================================
+
+This C header file is part of the SoftFloat IEEE Floating-point Arithmetic
+Package, Release 2b.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+#include "softfloat_types.h"
+
+/*----------------------------------------------------------------------------
+| Software floating-point underflow tininess-detection mode.
+*----------------------------------------------------------------------------*/
+extern int_fast8_t softfloat_detectTininess;
+enum {
+ softfloat_tininess_beforeRounding = 0,
+ softfloat_tininess_afterRounding = 1
+};
+
+/*----------------------------------------------------------------------------
+| Software floating-point rounding mode.
+*----------------------------------------------------------------------------*/
+extern int_fast8_t softfloat_roundingMode;
+enum {
+ softfloat_round_nearest_even = 0,
+ softfloat_round_minMag = 1,
+ softfloat_round_min = 2,
+ softfloat_round_max = 3,
+ softfloat_round_nearest_maxMag = 4
+};
+
+/*----------------------------------------------------------------------------
+| Software floating-point exception flags.
+*----------------------------------------------------------------------------*/
+extern int_fast8_t softfloat_exceptionFlags;
+enum {
+ softfloat_flag_inexact = 1,
+ softfloat_flag_underflow = 2,
+ softfloat_flag_overflow = 4,
+ softfloat_flag_infinity = 8,
+ softfloat_flag_invalid = 16
+};
+
+/*----------------------------------------------------------------------------
+| Routine to raise any or all of the software floating-point exception flags.
+*----------------------------------------------------------------------------*/
+void softfloat_raiseFlags( int_fast8_t );
+
+/*----------------------------------------------------------------------------
+| Integer-to-floating-point conversion routines.
+*----------------------------------------------------------------------------*/
+float32_t ui32_to_f32( uint_fast32_t );
+float64_t ui32_to_f64( uint_fast32_t );
+floatx80_t ui32_to_fx80( uint_fast32_t );
+float128_t ui32_to_f128( uint_fast32_t );
+float32_t ui64_to_f32( uint_fast64_t );
+float64_t ui64_to_f64( uint_fast64_t );
+floatx80_t ui64_to_fx80( uint_fast64_t );
+float128_t ui64_to_f128( uint_fast64_t );
+float32_t i32_to_f32( int_fast32_t );
+float64_t i32_to_f64( int_fast32_t );
+floatx80_t i32_to_fx80( int_fast32_t );
+float128_t i32_to_f128( int_fast32_t );
+float32_t i64_to_f32( int_fast64_t );
+float64_t i64_to_f64( int_fast64_t );
+floatx80_t i64_to_fx80( int_fast64_t );
+float128_t i64_to_f128( int_fast64_t );
+
+/*----------------------------------------------------------------------------
+| 32-bit (single-precision) floating-point operations.
+*----------------------------------------------------------------------------*/
+uint_fast32_t f32_to_ui32( float32_t, int_fast8_t, bool );
+uint_fast64_t f32_to_ui64( float32_t, int_fast8_t, bool );
+int_fast32_t f32_to_i32( float32_t, int_fast8_t, bool );
+int_fast64_t f32_to_i64( float32_t, int_fast8_t, bool );
+uint_fast32_t f32_to_ui32_r_minMag( float32_t, bool );
+uint_fast64_t f32_to_ui64_r_minMag( float32_t, bool );
+int_fast32_t f32_to_i32_r_minMag( float32_t, bool );
+int_fast64_t f32_to_i64_r_minMag( float32_t, bool );
+float64_t f32_to_f64( float32_t );
+floatx80_t f32_to_fx80( float32_t );
+float128_t f32_to_f128( float32_t );
+float32_t f32_roundToInt( float32_t, int_fast8_t, bool );
+float32_t f32_add( float32_t, float32_t );
+float32_t f32_sub( float32_t, float32_t );
+float32_t f32_mul( float32_t, float32_t );
+float32_t f32_mulAdd( float32_t, float32_t, float32_t );
+float32_t f32_div( float32_t, float32_t );
+float32_t f32_rem( float32_t, float32_t );
+float32_t f32_sqrt( float32_t );
+bool f32_eq( float32_t, float32_t );
+bool f32_le( float32_t, float32_t );
+bool f32_lt( float32_t, float32_t );
+bool f32_eq_signaling( float32_t, float32_t );
+bool f32_le_quiet( float32_t, float32_t );
+bool f32_lt_quiet( float32_t, float32_t );
+bool f32_isSignalingNaN( float32_t );
+uint_fast16_t f32_classify( float32_t );
+
+/*----------------------------------------------------------------------------
+| 64-bit (double-precision) floating-point operations.
+*----------------------------------------------------------------------------*/
+uint_fast32_t f64_to_ui32( float64_t, int_fast8_t, bool );
+uint_fast64_t f64_to_ui64( float64_t, int_fast8_t, bool );
+int_fast32_t f64_to_i32( float64_t, int_fast8_t, bool );
+int_fast64_t f64_to_i64( float64_t, int_fast8_t, bool );
+uint_fast32_t f64_to_ui32_r_minMag( float64_t, bool );
+uint_fast64_t f64_to_ui64_r_minMag( float64_t, bool );
+int_fast32_t f64_to_i32_r_minMag( float64_t, bool );
+int_fast64_t f64_to_i64_r_minMag( float64_t, bool );
+float32_t f64_to_f32( float64_t );
+floatx80_t f64_to_fx80( float64_t );
+float128_t f64_to_f128( float64_t );
+float64_t f64_roundToInt( float64_t, int_fast8_t, bool );
+float64_t f64_add( float64_t, float64_t );
+float64_t f64_sub( float64_t, float64_t );
+float64_t f64_mul( float64_t, float64_t );
+float64_t f64_mulAdd( float64_t, float64_t, float64_t );
+float64_t f64_div( float64_t, float64_t );
+float64_t f64_rem( float64_t, float64_t );
+float64_t f64_sqrt( float64_t );
+bool f64_eq( float64_t, float64_t );
+bool f64_le( float64_t, float64_t );
+bool f64_lt( float64_t, float64_t );
+bool f64_eq_signaling( float64_t, float64_t );
+bool f64_le_quiet( float64_t, float64_t );
+bool f64_lt_quiet( float64_t, float64_t );
+bool f64_isSignalingNaN( float64_t );
+uint_fast16_t f64_classify( float64_t );
+
+/*----------------------------------------------------------------------------
+| Extended double-precision rounding precision. Valid values are 32, 64, and
+| 80.
+*----------------------------------------------------------------------------*/
+extern int_fast8_t floatx80_roundingPrecision;
+
+/*----------------------------------------------------------------------------
+| Extended double-precision floating-point operations.
+*----------------------------------------------------------------------------*/
+uint_fast32_t fx80_to_ui32( floatx80_t, int_fast8_t, bool );
+uint_fast64_t fx80_to_ui64( floatx80_t, int_fast8_t, bool );
+int_fast32_t fx80_to_i32( floatx80_t, int_fast8_t, bool );
+int_fast64_t fx80_to_i64( floatx80_t, int_fast8_t, bool );
+uint_fast32_t fx80_to_ui32_r_minMag( floatx80_t, bool );
+uint_fast64_t fx80_to_ui64_r_minMag( floatx80_t, bool );
+int_fast32_t fx80_to_i32_r_minMag( floatx80_t, bool );
+int_fast64_t fx80_to_i64_r_minMag( floatx80_t, bool );
+float32_t fx80_to_f32( floatx80_t );
+float64_t fx80_to_f64( floatx80_t );
+float128_t fx80_to_f128( floatx80_t );
+floatx80_t fx80_roundToInt( floatx80_t, int_fast8_t, bool );
+floatx80_t fx80_add( floatx80_t, floatx80_t );
+floatx80_t fx80_sub( floatx80_t, floatx80_t );
+floatx80_t fx80_mul( floatx80_t, floatx80_t );
+floatx80_t fx80_mulAdd( floatx80_t, floatx80_t, floatx80_t );
+floatx80_t fx80_div( floatx80_t, floatx80_t );
+floatx80_t fx80_rem( floatx80_t, floatx80_t );
+floatx80_t fx80_sqrt( floatx80_t );
+bool fx80_eq( floatx80_t, floatx80_t );
+bool fx80_le( floatx80_t, floatx80_t );
+bool fx80_lt( floatx80_t, floatx80_t );
+bool fx80_eq_signaling( floatx80_t, floatx80_t );
+bool fx80_le_quiet( floatx80_t, floatx80_t );
+bool fx80_lt_quiet( floatx80_t, floatx80_t );
+bool fx80_isSignalingNaN( floatx80_t );
+
+/*----------------------------------------------------------------------------
+| 128-bit (quadruple-precision) floating-point operations.
+*----------------------------------------------------------------------------*/
+uint_fast32_t f128_to_ui32( float128_t, int_fast8_t, bool );
+uint_fast64_t f128_to_ui64( float128_t, int_fast8_t, bool );
+int_fast32_t f128_to_i32( float128_t, int_fast8_t, bool );
+int_fast64_t f128_to_i64( float128_t, int_fast8_t, bool );
+uint_fast32_t f128_to_ui32_r_minMag( float128_t, bool );
+uint_fast64_t f128_to_ui64_r_minMag( float128_t, bool );
+int_fast32_t f128_to_i32_r_minMag( float128_t, bool );
+int_fast64_t f128_to_i64_r_minMag( float128_t, bool );
+float32_t f128_to_f32( float128_t );
+float64_t f128_to_f64( float128_t );
+floatx80_t f128_to_fx80( float128_t );
+float128_t f128_roundToInt( float128_t, int_fast8_t, bool );
+float128_t f128_add( float128_t, float128_t );
+float128_t f128_sub( float128_t, float128_t );
+float128_t f128_mul( float128_t, float128_t );
+float128_t f128_mulAdd( float128_t, float128_t, float128_t );
+float128_t f128_div( float128_t, float128_t );
+float128_t f128_rem( float128_t, float128_t );
+float128_t f128_sqrt( float128_t );
+bool f128_eq( float128_t, float128_t );
+bool f128_le( float128_t, float128_t );
+bool f128_lt( float128_t, float128_t );
+bool f128_eq_signaling( float128_t, float128_t );
+bool f128_le_quiet( float128_t, float128_t );
+bool f128_lt_quiet( float128_t, float128_t );
+bool f128_isSignalingNaN( float128_t );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
new file mode 100644
@@ -0,0 +1,126 @@
+softfloat_subproject_deps = \
+
+softfloat_hdrs = \
+ internals.h \
+ primitives.h \
+ softfloat.h \
+ softfloat_types.h \
+ platform.h \
+ specialize.h \
+
+softfloat_c_srcs = \
+ f32_add.c \
+ f32_div.c \
+ f32_eq.c \
+ f32_eq_signaling.c \
+ f32_isSignalingNaN.c \
+ f32_le.c \
+ f32_le_quiet.c \
+ f32_lt.c \
+ f32_lt_quiet.c \
+ f32_mulAdd.c \
+ f32_mul.c \
+ f32_rem.c \
+ f32_roundToInt.c \
+ f32_sqrt.c \
+ f32_sub.c \
+ f32_to_f64.c \
+ f32_to_i32.c \
+ f32_to_i32_r_minMag.c \
+ f32_to_i64.c \
+ f32_to_i64_r_minMag.c \
+ f32_to_ui32.c \
+ f32_to_ui32_r_minMag.c \
+ f32_to_ui64.c \
+ f32_to_ui64_r_minMag.c \
+ f32_classify.c \
+ f64_add.c \
+ f64_div.c \
+ f64_eq.c \
+ f64_eq_signaling.c \
+ f64_isSignalingNaN.c \
+ f64_le.c \
+ f64_le_quiet.c \
+ f64_lt.c \
+ f64_lt_quiet.c \
+ f64_mulAdd.c \
+ f64_mul.c \
+ f64_rem.c \
+ f64_roundToInt.c \
+ f64_sqrt.c \
+ f64_sub.c \
+ f64_to_f32.c \
+ f64_to_i32.c \
+ f64_to_i32_r_minMag.c \
+ f64_to_i64.c \
+ f64_to_i64_r_minMag.c \
+ f64_to_ui32.c \
+ f64_to_ui32_r_minMag.c \
+ f64_to_ui64.c \
+ f64_to_ui64_r_minMag.c \
+ f64_classify.c \
+ i32_to_f32.c \
+ i32_to_f64.c \
+ i64_to_f32.c \
+ i64_to_f64.c \
+ s_add128.c \
+ s_add192.c \
+ s_addMagsF32.c \
+ s_addMagsF64.c \
+ s_countLeadingZeros32.c \
+ s_countLeadingZeros64.c \
+ s_countLeadingZeros8.c \
+ s_eq128.c \
+ s_estimateDiv128To64.c \
+ s_estimateSqrt32.c \
+ s_le128.c \
+ s_lt128.c \
+ s_mul128By64To192.c \
+ s_mul128To256.c \
+ s_mul64To128.c \
+ s_mulAddF32.c \
+ s_mulAddF64.c \
+ s_normRoundPackToF32.c \
+ s_normRoundPackToF64.c \
+ s_normSubnormalF32Sig.c \
+ s_normSubnormalF64Sig.c \
+ softfloat_state.c \
+ s_roundPackToF32.c \
+ s_roundPackToF64.c \
+ s_roundPackToI32.c \
+ s_roundPackToI64.c \
+ s_roundPackToUI32.c \
+ s_roundPackToUI64.c \
+ s_shift128ExtraRightJam.c \
+ s_shift128RightJam.c \
+ s_shift32RightJam.c \
+ s_shift64ExtraRightJam.c \
+ s_shift64RightJam.c \
+ s_shortShift128ExtraRightJam.c \
+ s_shortShift128Left.c \
+ s_shortShift128Right.c \
+ s_shortShift192Left.c \
+ s_shortShift32Right1Jam.c \
+ s_shortShift64ExtraRightJam.c \
+ s_shortShift64RightJam.c \
+ s_sub128.c \
+ s_sub192.c \
+ s_subMagsF32.c \
+ s_subMagsF64.c \
+ ui32_to_f32.c \
+ ui32_to_f64.c \
+ ui64_to_f32.c \
+ ui64_to_f64.c \
+ softfloat_raiseFlags.c \
+ s_commonNaNToF32UI.c \
+ s_commonNaNToF64UI.c \
+ s_f32UIToCommonNaN.c \
+ s_f64UIToCommonNaN.c \
+ s_isSigNaNF32UI.c \
+ s_isSigNaNF64UI.c \
+ s_propagateNaNF32UI.c \
+ s_propagateNaNF64UI.c \
+
+softfloat_test_srcs =
+
+softfloat_install_prog_srcs =
new file mode 100755
@@ -0,0 +1,51 @@
+
+/*============================================================================
+
+*** FIX.
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2b.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+#include "platform.h"
+#include "softfloat.h"
+
+/*----------------------------------------------------------------------------
+| Raises the exceptions specified by `flags'. Floating-point traps can be
+| defined here if desired. It is currently not possible for such a trap
+| to substitute a result value. If traps are not implemented, this routine
+| should be simply `float_exception_flags |= flags;'.
+*----------------------------------------------------------------------------*/
+
+void softfloat_raiseFlags( int_fast8_t flags )
+{
+
+ softfloat_exceptionFlags |= flags;
+
+}
+
new file mode 100755
@@ -0,0 +1,19 @@
+
+/*** COMMENTS. ***/
+
+#include <stdint.h>
+#include "platform.h"
+#include "internals.h"
+#include "specialize.h"
+#include "softfloat.h"
+
+/*----------------------------------------------------------------------------
+| Floating-point rounding mode, extended double-precision rounding precision,
+| and exception flags.
+*----------------------------------------------------------------------------*/
+int_fast8_t softfloat_roundingMode = softfloat_round_nearest_even;
+int_fast8_t softfloat_detectTininess = init_detectTininess;
+int_fast8_t softfloat_exceptionFlags = 0;
+
+int_fast8_t floatx80_roundingPrecision = 80;
+
new file mode 100755
@@ -0,0 +1,16 @@
+
+#ifndef softfloat_types_h
+#define softfloat_types_h
+
+/*** COMMENTS. ***/
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef uint32_t float32_t;
+typedef uint64_t float64_t;
+typedef struct { uint64_t v; uint16_t x; } floatx80_t;
+typedef struct { uint64_t v[ 2 ]; } float128_t;
+
+#endif
+
new file mode 100755
@@ -0,0 +1,113 @@
+
+/*============================================================================
+
+*** FIX.
+
+This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2b.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+arithmetic/SoftFloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
+been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
+RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
+AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
+COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
+EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
+INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
+OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) the source code for the derivative work includes prominent notice that
+the work is derivative, and (2) the source code includes prominent notice with
+these four paragraphs for those parts of this code that are retained.
+
+=============================================================================*/
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/*----------------------------------------------------------------------------
+*----------------------------------------------------------------------------*/
+#define init_detectTininess softfloat_tininess_beforeRounding;
+
+/*----------------------------------------------------------------------------
+| Structure used to transfer NaN representations from one format to another.
+*----------------------------------------------------------------------------*/
+struct commonNaN {
+ bool sign;
+ uint64_t v64, v0;
+};
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated single-precision NaN.
+*----------------------------------------------------------------------------*/
+#define defaultNaNF32UI 0x7FC00000
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point value `a' is a signaling
+| NaN; otherwise, returns 0.
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 1 <= INLINE_LEVEL )
+INLINE bool softfloat_isSigNaNF32UI( uint_fast32_t ui )
+ { return ( ( ui>>22 & 0x1FF ) == 0x1FE ) && ( ui & 0x003FFFFF ); }
+#else
+bool softfloat_isSigNaNF32UI( uint_fast32_t );
+#endif
+
+/*----------------------------------------------------------------------------
+*----------------------------------------------------------------------------*/
+struct commonNaN softfloat_f32UIToCommonNaN( uint_fast32_t );
+#if defined INLINE_LEVEL && ( 1 <= INLINE_LEVEL )
+INLINE uint_fast32_t softfloat_commonNaNToF32UI( struct commonNaN a )
+ { return defaultNaNF32UI; }
+#else
+uint_fast32_t softfloat_commonNaNToF32UI( struct commonNaN );
+#endif
+
+/*----------------------------------------------------------------------------
+| Takes two single-precision floating-point values `a' and `b', one of which
+| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+| signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+uint_fast32_t softfloat_propagateNaNF32UI( uint_fast32_t, uint_fast32_t );
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated double-precision NaN.
+*----------------------------------------------------------------------------*/
+#define defaultNaNF64UI UINT64_C(0x7FF8000000000000)
+
+/*----------------------------------------------------------------------------
+*----------------------------------------------------------------------------*/
+#if defined INLINE_LEVEL && ( 1 <= INLINE_LEVEL )
+INLINE bool softfloat_isSigNaNF64UI( uint_fast64_t ui )
+{
+ return
+ ( ( ui>>51 & 0xFFF ) == 0xFFE )
+ && ( ui & UINT64_C( 0x0007FFFFFFFFFFFF ) );
+}
+#else
+bool softfloat_isSigNaNF64UI( uint_fast64_t );
+#endif
+
+/*----------------------------------------------------------------------------
+*----------------------------------------------------------------------------*/
+/*** MIGHT BE INLINE'D. ***/
+struct commonNaN softfloat_f64UIToCommonNaN( uint_fast64_t );
+uint_fast64_t softfloat_commonNaNToF64UI( struct commonNaN );
+
+/*----------------------------------------------------------------------------
+| Takes two double-precision floating-point values `a' and `b', one of which
+| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
+| signaling NaN, the invalid exception is raised.
+*----------------------------------------------------------------------------*/
+uint_fast64_t softfloat_propagateNaNF64UI( uint_fast64_t, uint_fast64_t );
+
new file mode 100755
@@ -0,0 +1,25 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float32_t ui32_to_f32( uint_fast32_t a )
+{
+ union ui32_f32 uZ;
+
+ if ( ! a ) {
+ uZ.ui = 0;
+ return uZ.f;
+ }
+ if ( a & 0x80000000 ) {
+ return
+ softfloat_roundPackToF32(
+ 0, 0x9D, softfloat_shortShift32Right1Jam( a ) );
+ } else {
+ return softfloat_normRoundPackToF32( 0, 0x9C, a );
+ }
+
+}
+
new file mode 100755
@@ -0,0 +1,26 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float64_t ui32_to_f64( uint_fast32_t a )
+{
+ uint_fast64_t uiZ;
+ int shiftCount;
+ union ui64_f64 uZ;
+
+ if ( ! a ) {
+ uiZ = 0;
+ } else {
+ shiftCount = softfloat_countLeadingZeros32( a ) + 21;
+ uiZ =
+ packToF64UI(
+ 0, 0x432 - shiftCount, (uint_fast64_t) a<<shiftCount );
+ }
+ uZ.ui = uiZ;
+ return uZ.f;
+
+}
+
new file mode 100755
@@ -0,0 +1,31 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float32_t ui64_to_f32( uint_fast64_t a )
+{
+ int shiftCount;
+ union ui32_f32 u;
+ uint_fast32_t sig;
+
+ shiftCount = softfloat_countLeadingZeros64( a ) - 40;
+ if ( 0 <= shiftCount ) {
+ u.ui =
+ a ? packToF32UI(
+ 0, 0x95 - shiftCount, (uint_fast32_t) a<<shiftCount )
+ : 0;
+ return u.f;
+ } else {
+ shiftCount += 7;
+ sig =
+ ( shiftCount < 0 )
+ ? softfloat_shortShift64RightJam( a, - shiftCount )
+ : (uint_fast32_t) a<<shiftCount;
+ return softfloat_roundPackToF32( 0, 0x9C - shiftCount, sig );
+ }
+
+}
+
new file mode 100755
@@ -0,0 +1,25 @@
+
+#include <stdint.h>
+#include "platform.h"
+#include "primitives.h"
+#include "internals.h"
+#include "softfloat.h"
+
+float64_t ui64_to_f64( uint_fast64_t a )
+{
+ union ui64_f64 uZ;
+
+ if ( ! a ) {
+ uZ.ui = 0;
+ return uZ.f;
+ }
+ if ( a & UINT64_C( 0x8000000000000000 ) ) {
+ return
+ softfloat_roundPackToF64(
+ 0, 0x43D, softfloat_shortShift64RightJam( a, 1 ) );
+ } else {
+ return softfloat_normRoundPackToF64( 0, 0x43C, a );
+ }
+
+}
+
new file mode 100644
@@ -0,0 +1,177 @@
+/*
+ * RISC-V GDB Server Stub
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "qemu-common.h"
+#include "exec/gdbstub.h"
+#include "cpu.h"
+
+// map to CSR NOs for GDB
+int indexed_csrs[] = {
+ NEW_CSR_FFLAGS,
+ NEW_CSR_FRM,
+ NEW_CSR_FCSR,
+ NEW_CSR_CYCLE,
+ NEW_CSR_TIME,
+ NEW_CSR_INSTRET,
+ NEW_CSR_STATS,
+ NEW_CSR_UARCH0,
+ NEW_CSR_UARCH1,
+ NEW_CSR_UARCH2,
+ NEW_CSR_UARCH3,
+ NEW_CSR_UARCH4,
+ NEW_CSR_UARCH5,
+ NEW_CSR_UARCH6,
+ NEW_CSR_UARCH7,
+ NEW_CSR_UARCH8,
+ NEW_CSR_UARCH9,
+ NEW_CSR_UARCH10,
+ NEW_CSR_UARCH11,
+ NEW_CSR_UARCH12,
+ NEW_CSR_UARCH13,
+ NEW_CSR_UARCH14,
+ NEW_CSR_UARCH15,
+ NEW_CSR_SSTATUS,
+ NEW_CSR_STVEC,
+ NEW_CSR_SIE,
+ NEW_CSR_SSCRATCH,
+ NEW_CSR_SEPC,
+ NEW_CSR_SIP,
+ NEW_CSR_SPTBR,
+ NEW_CSR_SASID,
+ NEW_CSR_CYCLEW,
+ NEW_CSR_TIMEW,
+ NEW_CSR_INSTRETW,
+ NEW_CSR_STIME,
+ NEW_CSR_SCAUSE,
+ NEW_CSR_SBADADDR,
+ NEW_CSR_STIMEW,
+ NEW_CSR_MSTATUS,
+ NEW_CSR_MTVEC,
+ NEW_CSR_MTDELEG,
+ NEW_CSR_MIE,
+ NEW_CSR_MTIMECMP,
+ NEW_CSR_MSCRATCH,
+ NEW_CSR_MEPC,
+ NEW_CSR_MCAUSE,
+ NEW_CSR_MBADADDR,
+ NEW_CSR_MIP,
+ NEW_CSR_MTIME,
+ NEW_CSR_MCPUID,
+ NEW_CSR_MIMPID,
+ NEW_CSR_MHARTID,
+ NEW_CSR_MTOHOST,
+ NEW_CSR_MFROMHOST,
+ NEW_CSR_MRESET,
+ NEW_CSR_MIPI,
+ NEW_CSR_MIOBASE,
+ NEW_CSR_CYCLEH,
+ NEW_CSR_TIMEH,
+ NEW_CSR_INSTRETH,
+ NEW_CSR_CYCLEHW,
+ NEW_CSR_TIMEHW,
+ NEW_CSR_INSTRETHW,
+ NEW_CSR_STIMEH,
+ NEW_CSR_STIMEHW,
+ NEW_CSR_MTIMECMPH,
+ NEW_CSR_MTIMEH
+};
+
+int riscv_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ int target_csrno;
+
+ if (n < 32) {
+ return gdb_get_regl(mem_buf, env->active_tc.gpr[n]);
+ } else if (n == 32) {
+ return gdb_get_regl(mem_buf, env->active_tc.PC);
+ } else if (n < 65) {
+ return gdb_get_regl(mem_buf, env->active_tc.fpr[n-33]);
+ } else if (n < 132) {
+ n -= 65;
+ target_csrno = indexed_csrs[n];
+ switch (target_csrno)
+ {
+ // 32-bit wide
+ case NEW_CSR_FFLAGS:
+ case NEW_CSR_FRM:
+ case NEW_CSR_FCSR:
+ return gdb_get_reg32(mem_buf, csr_read_helper(env, target_csrno));
+
+ // unused on RV64 or not implemented
+ case NEW_CSR_MTIMEH:
+ case NEW_CSR_STIMEH:
+ case NEW_CSR_STIMEHW:
+ case NEW_CSR_TIMEH:
+ case NEW_CSR_TIMEHW:
+ case NEW_CSR_CYCLEH:
+ case NEW_CSR_INSTRETH:
+ case NEW_CSR_CYCLEHW:
+ case NEW_CSR_INSTRETHW:
+ case NEW_CSR_STATS:
+ case NEW_CSR_MRESET:
+ case NEW_CSR_MTIMECMPH:
+ return gdb_get_regl(mem_buf, 0L);
+
+ // special MFROMHOST, MTOHOST
+ case NEW_CSR_MFROMHOST:
+ case NEW_CSR_MTOHOST:
+ return gdb_get_regl(mem_buf, env->csr[target_csrno]);
+
+ // all others
+ default:
+ return gdb_get_regl(mem_buf, csr_read_helper(env, target_csrno));
+ }
+ }
+ return 0;
+}
+
+int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ target_ulong tmp;
+ int target_csrno;
+
+ tmp = ldtul_p(mem_buf);
+
+ if (n < 32) {
+ env->active_tc.gpr[n] = tmp;
+ return sizeof(target_ulong);
+ } else if (n == 32) {
+ env->active_tc.PC = tmp;
+ return sizeof(target_ulong);
+ } else if (n < 65) {
+ env->active_tc.fpr[n-33] = tmp;
+ return sizeof(target_ulong);
+ } else if (n < 132) {
+ n -= 65;
+ target_csrno = indexed_csrs[n];
+ env->csr[target_csrno] = tmp;
+ if (n < 3) {
+ return sizeof(uint32_t);
+ } else {
+ return sizeof(target_ulong);
+ }
+ }
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,356 @@
+/*
+ * RISC-V emulation helpers for qemu.
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <signal.h>
+#include "cpu.h"
+
+#define QEMU_IN_FETCH 0x2
+#define QEMU_IN_WRITE 0x1
+#define QEMU_IN_READ 0x0
+
+#if !defined(CONFIG_USER_ONLY)
+
+bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request) {
+ if (interrupt_request & CPU_INTERRUPT_HARD) {
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ int interruptno = cpu_riscv_hw_interrupts_pending(env);
+ if (interruptno + 1) {
+ cs->exception_index = 0x70000000U | interruptno;
+ riscv_cpu_do_interrupt(cs);
+ return true;
+ }
+ }
+ return false;
+}
+
+/* get_physical_address - get the physical address for this virtual address
+ *
+ * Do a page table walk to obtain the physical address corresponding to a
+ * virtual address.
+ *
+ * Returns 0 if the translation was successful
+*/
+static int get_physical_address (CPURISCVState *env, hwaddr *physical,
+ int *prot, target_ulong address,
+ int rw, int mmu_idx)
+{
+ /* NOTE: the env->active_tc.PC value visible here will not be
+ * correct, but the value visible to the exception handler
+ * (riscv_cpu_do_interrupt) is correct */
+
+ // rw is either QEMU_IN_FETCH, QEMU_IN_WRITE, or QEMU_IN_READ
+ *prot = 0;
+ CPUState *cs = CPU(riscv_env_get_cpu(env));
+
+ target_ulong mode = get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS_PRV);
+ if (rw != QEMU_IN_FETCH && get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS_MPRV)) {
+ mode = get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS_PRV1);
+ }
+ if (get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS_VM) == VM_MBARE) {
+ mode = PRV_M;
+ }
+
+ // check to make sure that mmu_idx and mode that we get matches
+ if (unlikely(mode != mmu_idx)) {
+ fprintf(stderr, "MODE, mmu_idx mismatch\n");
+ exit(1);
+ }
+
+ if (mode == PRV_M) {
+ target_ulong msb_mask = (2L << 63) - 1;
+ *physical = address & msb_mask;
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return TRANSLATE_SUCCESS;
+ }
+
+ target_ulong addr = address;
+ int supervisor = mode > PRV_U;
+
+ int levels, ptidxbits, ptesize;
+ switch (get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS_VM))
+ {
+ case VM_SV32:
+ printf("currently unsupported SV32\n");
+ exit(1);
+ levels = 2;
+ ptidxbits = 10;
+ ptesize = 4;
+ break;
+ case VM_SV39:
+ levels = 3;
+ ptidxbits = 9;
+ ptesize = 8;
+ break;
+ case VM_SV48:
+ levels = 4;
+ ptidxbits = 9;
+ ptesize = 8;
+ break;
+ default:
+ printf("unsupported MSTATUS_VM value\n");
+ exit(1);
+ }
+
+ int va_bits = PGSHIFT + levels * ptidxbits;
+ target_ulong mask = (1L << (64 - (va_bits-1))) - 1;
+ target_ulong masked_msbs = (addr >> (va_bits-1)) & mask;
+ if (masked_msbs != 0 && masked_msbs != mask) {
+ return TRANSLATE_FAIL;
+ }
+
+ target_ulong base = env->csr[NEW_CSR_SPTBR];
+ int ptshift = (levels - 1) * ptidxbits;
+ int i;
+ for (i = 0; i < levels; i++, ptshift -= ptidxbits) {
+ target_ulong idx = (addr >> (PGSHIFT + ptshift)) & ((1 << ptidxbits) - 1);
+
+ // check that physical address of PTE is legal
+ target_ulong pte_addr = base + idx * ptesize;
+ if (pte_addr >= env->memsize) {
+ break;
+ }
+
+ target_ulong pte = ldq_phys(cs->as, pte_addr);
+ target_ulong ppn = pte >> PTE_PPN_SHIFT;
+
+ if (PTE_TABLE(pte)) { // next level of page table
+ base = ppn << PGSHIFT;
+ } else if (!PTE_CHECK_PERM(pte, supervisor, rw == QEMU_IN_WRITE,
+ rw == QEMU_IN_FETCH)) {
+ break;
+ } else {
+ // set referenced and possibly dirty bits.
+ // we only put it in the TLB if it has the right stuff
+ stq_phys(cs->as, pte_addr, ldq_phys(cs->as, pte_addr) | PTE_R |
+ ((rw == QEMU_IN_WRITE) * PTE_D));
+
+ // for superpage mappings, make a fake leaf PTE for the TLB's benefit.
+ target_ulong vpn = addr >> PGSHIFT;
+ *physical = (ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT;
+
+ // we do not give all prots indicated by the PTE
+ // this is because future accesses need to do things like set the
+ // dirty bit on the PTE
+ if (supervisor) {
+ if (PTE_SX(pte) && rw == QEMU_IN_FETCH) {
+ *prot |= PAGE_EXEC;
+ } else if (PTE_SW(pte) && rw == QEMU_IN_WRITE) {
+ *prot |= PAGE_WRITE;
+ } else if (PTE_SR(pte) && rw == QEMU_IN_READ) {
+ *prot |= PAGE_READ;
+ } else {
+ printf("err in translation prots");
+ exit(1);
+ }
+ } else {
+ if (PTE_UX(pte) && rw == QEMU_IN_FETCH) {
+ *prot |= PAGE_EXEC;
+ } else if (PTE_UW(pte) && rw == QEMU_IN_WRITE) {
+ *prot |= PAGE_WRITE;
+ } else if (PTE_UR(pte) && rw == QEMU_IN_READ) {
+ *prot |= PAGE_READ;
+ } else {
+ printf("err in translation prots");
+ exit(1);
+ }
+ }
+ return TRANSLATE_SUCCESS;
+ }
+ }
+ return TRANSLATE_FAIL;
+}
+#endif
+
+static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
+ int rw)
+{
+ CPUState *cs = CPU(riscv_env_get_cpu(env));
+ int exception = 0;
+ if (rw == QEMU_IN_FETCH) { // inst access
+ exception = NEW_RISCV_EXCP_INST_ACCESS_FAULT;
+ env->csr[NEW_CSR_MBADADDR] = address;
+ } else if (rw == QEMU_IN_WRITE) { // store access
+ exception = NEW_RISCV_EXCP_STORE_AMO_ACCESS_FAULT;
+ env->csr[NEW_CSR_MBADADDR] = address;
+ } else if (rw == QEMU_IN_READ) { // load access
+ exception = NEW_RISCV_EXCP_LOAD_ACCESS_FAULT;
+ env->csr[NEW_CSR_MBADADDR] = address;
+ } else {
+ fprintf(stderr, "FAIL: invalid rw\n");
+ exit(1);
+ }
+ cs->exception_index = exception;
+}
+
+#if !defined(CONFIG_USER_ONLY)
+hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ hwaddr phys_addr;
+ int prot;
+ int mem_idx = cpu_mmu_index(&cpu->env, false);
+
+ if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mem_idx)) {
+ return -1;
+ }
+ return phys_addr;
+}
+#endif
+
+/* This is called when there is no QEMU "TLB" match
+ *
+ * Assuming system mode, only called in target-riscv/op_helper:tlb_fill
+ */
+int riscv_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, int mmu_idx)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ hwaddr physical;
+ physical = 0; // stop gcc complaining
+ int prot;
+ int ret = 0;
+
+ qemu_log("%s pc " TARGET_FMT_lx " ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
+ __func__, env->active_tc.PC, address, rw, mmu_idx);
+
+ ret = get_physical_address(env, &physical, &prot, address, rw, mmu_idx);
+ qemu_log("%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx
+ " prot %d\n",
+ __func__, address, ret, physical, prot);
+ if (ret == TRANSLATE_SUCCESS) {
+ tlb_set_page(cs, address & TARGET_PAGE_MASK, physical & TARGET_PAGE_MASK,
+ prot, mmu_idx, TARGET_PAGE_SIZE);
+ } else if (ret == TRANSLATE_FAIL) {
+ raise_mmu_exception(env, address, rw);
+ }
+ return ret;
+}
+
+static const char * const riscv_excp_names[12] = {
+ "Instruction Address Misaligned",
+ "Instruction Access Fault",
+ "Illegal Instruction",
+ "Breakpoint",
+ "Load Address Misaligned",
+ "Load Access Fault",
+ "Store/AMO Address Misaligned",
+ "Store/AMO Access Fault",
+ "User ECALL",
+ "Supervisor ECALL",
+ "Hypervisor ECALL",
+ "Machine ECALL",
+};
+
+static const char * const riscv_interrupt_names[3] = {
+ "Soft interrupt",
+ "Timer interrupt",
+ "Host interrupt"
+};
+
+target_ulong push_priv_stack(target_ulong start_mstatus) {
+ target_ulong s = start_mstatus;
+ s = set_field(s, MSTATUS_PRV2, get_field(start_mstatus, MSTATUS_PRV1));
+ s = set_field(s, MSTATUS_IE2, get_field(start_mstatus, MSTATUS_IE1));
+ s = set_field(s, MSTATUS_PRV1, get_field(start_mstatus, MSTATUS_PRV));
+ s = set_field(s, MSTATUS_IE1, get_field(start_mstatus, MSTATUS_IE));
+ s = set_field(s, MSTATUS_PRV, PRV_M);
+ s = set_field(s, MSTATUS_MPRV, 0);
+ s = set_field(s, MSTATUS_IE, 0);
+ return s;
+}
+
+target_ulong pop_priv_stack(target_ulong start_mstatus) {
+ target_ulong s = start_mstatus;
+ s = set_field(s, MSTATUS_PRV, get_field(start_mstatus, MSTATUS_PRV1));
+ s = set_field(s, MSTATUS_IE, get_field(start_mstatus, MSTATUS_IE1));
+ s = set_field(s, MSTATUS_PRV1, get_field(start_mstatus, MSTATUS_PRV2));
+ s = set_field(s, MSTATUS_IE1, get_field(start_mstatus, MSTATUS_IE2));
+ s = set_field(s, MSTATUS_PRV2, PRV_U);
+ s = set_field(s, MSTATUS_IE2, 1);
+ return s;
+}
+
+void riscv_cpu_do_interrupt(CPUState *cs)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+
+ #ifdef RISCV_DEBUG_INTERRUPT
+ if (cs->exception_index & 0x70000000) {
+ fprintf(stderr, "core 0: exception trap_%s, epc 0x%016lx\n",
+ riscv_interrupt_names[cs->exception_index & 0x0fffffff], env->active_tc.PC);
+ } else {
+ fprintf(stderr, "core 0: exception trap_%s, epc 0x%016lx\n",
+ riscv_excp_names[cs->exception_index], env->active_tc.PC);
+ }
+ #endif
+
+ // Store original PC to epc reg
+ // This is correct because the env->active_tc.PC value visible here is
+ // actually the correct value, unlike other places where env->active_tc.PC
+ // may be used.
+ env->csr[NEW_CSR_MEPC] = env->active_tc.PC;
+
+ // set PC to handler
+ env->active_tc.PC = DEFAULT_MTVEC + 0x40 * get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS_PRV);
+
+
+ // Store Cause in CSR_CAUSE. this comes from cs->exception_index
+ if (cs->exception_index & (0x70000000)) {
+ // hacky for now. the MSB (bit 63) indicates interrupt but cs->exception
+ // index is only 32 bits wide
+ env->csr[NEW_CSR_MCAUSE] = cs->exception_index & 0x0FFFFFFF;
+ env->csr[NEW_CSR_MCAUSE] |= (1L << 63);
+
+ } else {
+ // fixup User ECALL -> correct priv ECALL
+ if (cs->exception_index == NEW_RISCV_EXCP_U_ECALL) {
+ switch(get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS_PRV)) {
+ case PRV_U:
+ env->csr[NEW_CSR_MCAUSE] = NEW_RISCV_EXCP_U_ECALL;
+ break;
+ case PRV_S:
+ env->csr[NEW_CSR_MCAUSE] = NEW_RISCV_EXCP_S_ECALL;
+ break;
+ case PRV_H:
+ env->csr[NEW_CSR_MCAUSE] = NEW_RISCV_EXCP_H_ECALL;
+ break;
+ case PRV_M:
+ env->csr[NEW_CSR_MCAUSE] = NEW_RISCV_EXCP_M_ECALL;
+ break;
+ }
+ } else {
+ env->csr[NEW_CSR_MCAUSE] = cs->exception_index;
+ }
+ }
+
+ // handle stack
+ target_ulong next_mstatus = push_priv_stack(env->csr[NEW_CSR_MSTATUS]);
+ csr_write_helper(env, next_mstatus, NEW_CSR_MSTATUS);
+
+ // NOTE: CSR_BADVADDR should be set from the handler that raises the exception
+
+ cs->exception_index = EXCP_NONE; // mark handled to qemu
+}
new file mode 100644
@@ -0,0 +1,82 @@
+// Exceptions
+DEF_HELPER_2(raise_exception, noreturn, env, i32)
+DEF_HELPER_1(raise_exception_debug, noreturn, env)
+DEF_HELPER_3(raise_exception_err, noreturn, env, i32, tl)
+DEF_HELPER_3(raise_exception_mbadaddr, noreturn, env, i32, tl)
+
+// MULHSU helper
+DEF_HELPER_3(mulhsu, tl, env, tl, tl)
+
+// Floating Point - fused
+DEF_HELPER_5(fmadd_s, tl, env, tl, tl, tl, tl)
+DEF_HELPER_5(fmadd_d, tl, env, tl, tl, tl, tl)
+DEF_HELPER_5(fmsub_s, tl, env, tl, tl, tl, tl)
+DEF_HELPER_5(fmsub_d, tl, env, tl, tl, tl, tl)
+DEF_HELPER_5(fnmsub_s, tl, env, tl, tl, tl, tl)
+DEF_HELPER_5(fnmsub_d, tl, env, tl, tl, tl, tl)
+DEF_HELPER_5(fnmadd_s, tl, env, tl, tl, tl, tl)
+DEF_HELPER_5(fnmadd_d, tl, env, tl, tl, tl, tl)
+
+// Floating Point - Single Precision
+DEF_HELPER_4(fadd_s, tl, env, tl, tl, tl)
+DEF_HELPER_4(fsub_s, tl, env, tl, tl, tl)
+DEF_HELPER_4(fmul_s, tl, env, tl, tl, tl)
+DEF_HELPER_4(fdiv_s, tl, env, tl, tl, tl)
+DEF_HELPER_3(fsgnj_s, tl, env, tl, tl)
+DEF_HELPER_3(fsgnjn_s, tl, env, tl, tl)
+DEF_HELPER_3(fsgnjx_s, tl, env, tl, tl)
+DEF_HELPER_3(fmin_s, tl, env, tl, tl)
+DEF_HELPER_3(fmax_s, tl, env, tl, tl)
+DEF_HELPER_3(fsqrt_s, tl, env, tl, tl)
+DEF_HELPER_3(fle_s, tl, env, tl, tl)
+DEF_HELPER_3(flt_s, tl, env, tl, tl)
+DEF_HELPER_3(feq_s, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_w_s, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_wu_s, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_l_s, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_lu_s, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_s_w, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_s_wu, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_s_l, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_s_lu, tl, env, tl, tl)
+DEF_HELPER_2(fclass_s, tl, env, tl)
+
+// Floating Point - Double Precision
+DEF_HELPER_4(fadd_d, tl, env, tl, tl, tl)
+DEF_HELPER_4(fsub_d, tl, env, tl, tl, tl)
+DEF_HELPER_4(fmul_d, tl, env, tl, tl, tl)
+DEF_HELPER_4(fdiv_d, tl, env, tl, tl, tl)
+DEF_HELPER_3(fsgnj_d, tl, env, tl, tl)
+DEF_HELPER_3(fsgnjn_d, tl, env, tl, tl)
+DEF_HELPER_3(fsgnjx_d, tl, env, tl, tl)
+DEF_HELPER_3(fmin_d, tl, env, tl, tl)
+DEF_HELPER_3(fmax_d, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_s_d, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_d_s, tl, env, tl, tl)
+DEF_HELPER_3(fsqrt_d, tl, env, tl, tl)
+DEF_HELPER_3(fle_d, tl, env, tl, tl)
+DEF_HELPER_3(flt_d, tl, env, tl, tl)
+DEF_HELPER_3(feq_d, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_w_d, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_wu_d, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_l_d, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_lu_d, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_d_w, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_d_wu, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_d_l, tl, env, tl, tl)
+DEF_HELPER_3(fcvt_d_lu, tl, env, tl, tl)
+DEF_HELPER_2(fclass_d, tl, env, tl)
+
+/* Special functions */
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_4(csrrw, tl, env, tl, tl, tl)
+DEF_HELPER_4(csrrs, tl, env, tl, tl, tl)
+DEF_HELPER_4(csrrsi, tl, env, tl, tl, tl)
+DEF_HELPER_4(csrrc, tl, env, tl, tl, tl)
+DEF_HELPER_2(sret, tl, env, tl)
+DEF_HELPER_3(debug_print, void, env, tl, tl)
+DEF_HELPER_2(mrts, tl, env, tl)
+DEF_HELPER_1(tlb_flush, void, env)
+DEF_HELPER_1(fence_i, void, env)
+#endif /* !CONFIG_USER_ONLY */
+//DEF_HELPER_1(wait, void, env)
new file mode 100644
@@ -0,0 +1,311 @@
+/*
+ * RISC-V emulation for qemu: Instruction decode helpers
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define MASK_OP_MAJOR(op) (op & 0x7F)
+enum {
+ /* rv32i, rv64i, rv32m */
+ OPC_RISC_LUI = (0x37),
+ OPC_RISC_AUIPC = (0x17),
+ OPC_RISC_JAL = (0x6F),
+ OPC_RISC_JALR = (0x67),
+ OPC_RISC_BRANCH = (0x63),
+ OPC_RISC_LOAD = (0x03),
+ OPC_RISC_STORE = (0x23),
+ OPC_RISC_ARITH_IMM = (0x13),
+ OPC_RISC_ARITH = (0x33),
+ OPC_RISC_FENCE = (0x0F),
+ OPC_RISC_SYSTEM = (0x73),
+
+ /* rv64i, rv64m */
+ OPC_RISC_ARITH_IMM_W = (0x1B),
+ OPC_RISC_ARITH_W = (0x3B),
+
+ /* rv32a, rv64a */
+ OPC_RISC_ATOMIC = (0x2F),
+
+ /* floating point */
+ OPC_RISC_FP_LOAD = (0x7),
+ OPC_RISC_FP_STORE = (0x27),
+
+ OPC_RISC_FMADD = (0x43),
+ OPC_RISC_FMSUB = (0x47),
+ OPC_RISC_FNMSUB = (0x4B),
+ OPC_RISC_FNMADD = (0x4F),
+
+ OPC_RISC_FP_ARITH = (0x53),
+};
+
+#define MASK_OP_ARITH(op) (MASK_OP_MAJOR(op) | (op & ((0x7 << 12) | (0x7F << 25))))
+enum {
+ OPC_RISC_ADD = OPC_RISC_ARITH | (0x0 << 12) | (0x00 << 25),
+ OPC_RISC_SUB = OPC_RISC_ARITH | (0x0 << 12) | (0x20 << 25),
+ OPC_RISC_SLL = OPC_RISC_ARITH | (0x1 << 12) | (0x00 << 25),
+ OPC_RISC_SLT = OPC_RISC_ARITH | (0x2 << 12) | (0x00 << 25),
+ OPC_RISC_SLTU = OPC_RISC_ARITH | (0x3 << 12) | (0x00 << 25),
+ OPC_RISC_XOR = OPC_RISC_ARITH | (0x4 << 12) | (0x00 << 25),
+ OPC_RISC_SRL = OPC_RISC_ARITH | (0x5 << 12) | (0x00 << 25),
+ OPC_RISC_SRA = OPC_RISC_ARITH | (0x5 << 12) | (0x20 << 25),
+ OPC_RISC_OR = OPC_RISC_ARITH | (0x6 << 12) | (0x00 << 25),
+ OPC_RISC_AND = OPC_RISC_ARITH | (0x7 << 12) | (0x00 << 25),
+
+ /* RV64M */
+ OPC_RISC_MUL = OPC_RISC_ARITH | (0x0 << 12) | (0x01 << 25),
+ OPC_RISC_MULH = OPC_RISC_ARITH | (0x1 << 12) | (0x01 << 25),
+ OPC_RISC_MULHSU = OPC_RISC_ARITH | (0x2 << 12) | (0x01 << 25),
+ OPC_RISC_MULHU = OPC_RISC_ARITH | (0x3 << 12) | (0x01 << 25),
+
+ OPC_RISC_DIV = OPC_RISC_ARITH | (0x4 << 12) | (0x01 << 25),
+ OPC_RISC_DIVU = OPC_RISC_ARITH | (0x5 << 12) | (0x01 << 25),
+ OPC_RISC_REM = OPC_RISC_ARITH | (0x6 << 12) | (0x01 << 25),
+ OPC_RISC_REMU = OPC_RISC_ARITH | (0x7 << 12) | (0x01 << 25),
+};
+
+
+#define MASK_OP_ARITH_IMM(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_ADDI = OPC_RISC_ARITH_IMM | (0x0 << 12),
+ OPC_RISC_SLTI = OPC_RISC_ARITH_IMM | (0x2 << 12),
+ OPC_RISC_SLTIU = OPC_RISC_ARITH_IMM | (0x3 << 12),
+ OPC_RISC_XORI = OPC_RISC_ARITH_IMM | (0x4 << 12),
+ OPC_RISC_ORI = OPC_RISC_ARITH_IMM | (0x6 << 12),
+ OPC_RISC_ANDI = OPC_RISC_ARITH_IMM | (0x7 << 12),
+ OPC_RISC_SLLI = OPC_RISC_ARITH_IMM | (0x1 << 12), // additional part of IMM
+ OPC_RISC_SHIFT_RIGHT_I = OPC_RISC_ARITH_IMM | (0x5 << 12) // SRAI, SRLI
+};
+
+#define MASK_OP_BRANCH(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_BEQ = OPC_RISC_BRANCH | (0x0 << 12),
+ OPC_RISC_BNE = OPC_RISC_BRANCH | (0x1 << 12),
+ OPC_RISC_BLT = OPC_RISC_BRANCH | (0x4 << 12),
+ OPC_RISC_BGE = OPC_RISC_BRANCH | (0x5 << 12),
+ OPC_RISC_BLTU = OPC_RISC_BRANCH | (0x6 << 12),
+ OPC_RISC_BGEU = OPC_RISC_BRANCH | (0x7 << 12)
+};
+
+#define MASK_OP_ARITH_IMM_W(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_ADDIW = OPC_RISC_ARITH_IMM_W | (0x0 << 12),
+ OPC_RISC_SLLIW = OPC_RISC_ARITH_IMM_W | (0x1 << 12), // additional part of IMM
+ OPC_RISC_SHIFT_RIGHT_IW = OPC_RISC_ARITH_IMM_W | (0x5 << 12) // SRAI, SRLI
+};
+
+#define MASK_OP_ARITH_W(op) (MASK_OP_MAJOR(op) | (op & ((0x7 << 12) | (0x7F << 25))))
+enum {
+ OPC_RISC_ADDW = OPC_RISC_ARITH_W | (0x0 << 12) | (0x00 << 25),
+ OPC_RISC_SUBW = OPC_RISC_ARITH_W | (0x0 << 12) | (0x20 << 25),
+ OPC_RISC_SLLW = OPC_RISC_ARITH_W | (0x1 << 12) | (0x00 << 25),
+ OPC_RISC_SRLW = OPC_RISC_ARITH_W | (0x5 << 12) | (0x00 << 25),
+ OPC_RISC_SRAW = OPC_RISC_ARITH_W | (0x5 << 12) | (0x20 << 25),
+
+ /* RV64M */
+ OPC_RISC_MULW = OPC_RISC_ARITH_W | (0x0 << 12) | (0x01 << 25),
+ OPC_RISC_DIVW = OPC_RISC_ARITH_W | (0x4 << 12) | (0x01 << 25),
+ OPC_RISC_DIVUW = OPC_RISC_ARITH_W | (0x5 << 12) | (0x01 << 25),
+ OPC_RISC_REMW = OPC_RISC_ARITH_W | (0x6 << 12) | (0x01 << 25),
+ OPC_RISC_REMUW = OPC_RISC_ARITH_W | (0x7 << 12) | (0x01 << 25),
+};
+
+#define MASK_OP_LOAD(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_LB = OPC_RISC_LOAD | (0x0 << 12),
+ OPC_RISC_LH = OPC_RISC_LOAD | (0x1 << 12),
+ OPC_RISC_LW = OPC_RISC_LOAD | (0x2 << 12),
+ OPC_RISC_LD = OPC_RISC_LOAD | (0x3 << 12),
+ OPC_RISC_LBU = OPC_RISC_LOAD | (0x4 << 12),
+ OPC_RISC_LHU = OPC_RISC_LOAD | (0x5 << 12),
+ OPC_RISC_LWU = OPC_RISC_LOAD | (0x6 << 12),
+};
+
+#define MASK_OP_STORE(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_SB = OPC_RISC_STORE | (0x0 << 12),
+ OPC_RISC_SH = OPC_RISC_STORE | (0x1 << 12),
+ OPC_RISC_SW = OPC_RISC_STORE | (0x2 << 12),
+ OPC_RISC_SD = OPC_RISC_STORE | (0x3 << 12),
+};
+
+#define MASK_OP_JALR(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+// no enum since OPC_RISC_JALR is the actual value
+
+#define MASK_OP_ATOMIC(op) (MASK_OP_MAJOR(op) | (op & ((0x7 << 12) | (0x7F << 25))))
+#define MASK_OP_ATOMIC_NO_AQ_RL(op) (MASK_OP_MAJOR(op) | (op & ((0x7 << 12) | (0x1F << 27))))
+enum {
+ OPC_RISC_LR_W = OPC_RISC_ATOMIC | (0x2 << 12) | (0x02 << 27),
+ OPC_RISC_SC_W = OPC_RISC_ATOMIC | (0x2 << 12) | (0x03 << 27),
+ OPC_RISC_AMOSWAP_W = OPC_RISC_ATOMIC | (0x2 << 12) | (0x01 << 27),
+ OPC_RISC_AMOADD_W = OPC_RISC_ATOMIC | (0x2 << 12) | (0x00 << 27),
+ OPC_RISC_AMOXOR_W = OPC_RISC_ATOMIC | (0x2 << 12) | (0x04 << 27),
+ OPC_RISC_AMOAND_W = OPC_RISC_ATOMIC | (0x2 << 12) | (0x0C << 27),
+ OPC_RISC_AMOOR_W = OPC_RISC_ATOMIC | (0x2 << 12) | (0x08 << 27),
+ OPC_RISC_AMOMIN_W = OPC_RISC_ATOMIC | (0x2 << 12) | (0x10 << 27),
+ OPC_RISC_AMOMAX_W = OPC_RISC_ATOMIC | (0x2 << 12) | (0x14 << 27),
+ OPC_RISC_AMOMINU_W = OPC_RISC_ATOMIC | (0x2 << 12) | (0x18 << 27),
+ OPC_RISC_AMOMAXU_W = OPC_RISC_ATOMIC | (0x2 << 12) | (0x1C << 27),
+
+ OPC_RISC_LR_D = OPC_RISC_ATOMIC | (0x3 << 12) | (0x02 << 27),
+ OPC_RISC_SC_D = OPC_RISC_ATOMIC | (0x3 << 12) | (0x03 << 27),
+ OPC_RISC_AMOSWAP_D = OPC_RISC_ATOMIC | (0x3 << 12) | (0x01 << 27),
+ OPC_RISC_AMOADD_D = OPC_RISC_ATOMIC | (0x3 << 12) | (0x00 << 27),
+ OPC_RISC_AMOXOR_D = OPC_RISC_ATOMIC | (0x3 << 12) | (0x04 << 27),
+ OPC_RISC_AMOAND_D = OPC_RISC_ATOMIC | (0x3 << 12) | (0x0C << 27),
+ OPC_RISC_AMOOR_D = OPC_RISC_ATOMIC | (0x3 << 12) | (0x08 << 27),
+ OPC_RISC_AMOMIN_D = OPC_RISC_ATOMIC | (0x3 << 12) | (0x10 << 27),
+ OPC_RISC_AMOMAX_D = OPC_RISC_ATOMIC | (0x3 << 12) | (0x14 << 27),
+ OPC_RISC_AMOMINU_D = OPC_RISC_ATOMIC | (0x3 << 12) | (0x18 << 27),
+ OPC_RISC_AMOMAXU_D = OPC_RISC_ATOMIC | (0x3 << 12) | (0x1C << 27),
+};
+
+#define MASK_OP_SYSTEM(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_ECALL = OPC_RISC_SYSTEM | (0x0 << 12),
+ OPC_RISC_EBREAK = OPC_RISC_SYSTEM | (0x0 << 12),
+ OPC_RISC_ERET = OPC_RISC_SYSTEM | (0x0 << 12),
+ OPC_RISC_MRTS = OPC_RISC_SYSTEM | (0x0 << 12),
+ OPC_RISC_MRTH = OPC_RISC_SYSTEM | (0x0 << 12),
+ OPC_RISC_HRTS = OPC_RISC_SYSTEM | (0x0 << 12),
+ OPC_RISC_WFI = OPC_RISC_SYSTEM | (0x0 << 12),
+ OPC_RISC_SFENCEVM = OPC_RISC_SYSTEM | (0x0 << 12),
+
+ OPC_RISC_CSRRW = OPC_RISC_SYSTEM | (0x1 << 12),
+ OPC_RISC_CSRRS = OPC_RISC_SYSTEM | (0x2 << 12),
+ OPC_RISC_CSRRC = OPC_RISC_SYSTEM | (0x3 << 12),
+ OPC_RISC_CSRRWI = OPC_RISC_SYSTEM | (0x5 << 12),
+ OPC_RISC_CSRRSI = OPC_RISC_SYSTEM | (0x6 << 12),
+ OPC_RISC_CSRRCI = OPC_RISC_SYSTEM | (0x7 << 12),
+};
+
+#define MASK_OP_FP_LOAD(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_FLW = OPC_RISC_FP_LOAD | (0x2 << 12),
+ OPC_RISC_FLD = OPC_RISC_FP_LOAD | (0x3 << 12),
+};
+
+#define MASK_OP_FP_STORE(op) (MASK_OP_MAJOR(op) | (op & (0x7 << 12)))
+enum {
+ OPC_RISC_FSW = OPC_RISC_FP_STORE | (0x2 << 12),
+ OPC_RISC_FSD = OPC_RISC_FP_STORE | (0x3 << 12),
+};
+
+#define MASK_OP_FP_FMADD(op) (MASK_OP_MAJOR(op) | (op & (0x3 << 25)))
+enum {
+ OPC_RISC_FMADD_S = OPC_RISC_FMADD | (0x0 << 25),
+ OPC_RISC_FMADD_D = OPC_RISC_FMADD | (0x1 << 25),
+};
+
+#define MASK_OP_FP_FMSUB(op) (MASK_OP_MAJOR(op) | (op & (0x3 << 25)))
+enum {
+ OPC_RISC_FMSUB_S = OPC_RISC_FMSUB | (0x0 << 25),
+ OPC_RISC_FMSUB_D = OPC_RISC_FMSUB | (0x1 << 25),
+};
+
+#define MASK_OP_FP_FNMADD(op) (MASK_OP_MAJOR(op) | (op & (0x3 << 25)))
+enum {
+ OPC_RISC_FNMADD_S = OPC_RISC_FNMADD | (0x0 << 25),
+ OPC_RISC_FNMADD_D = OPC_RISC_FNMADD | (0x1 << 25),
+};
+
+#define MASK_OP_FP_FNMSUB(op) (MASK_OP_MAJOR(op) | (op & (0x3 << 25)))
+enum {
+ OPC_RISC_FNMSUB_S = OPC_RISC_FNMSUB | (0x0 << 25),
+ OPC_RISC_FNMSUB_D = OPC_RISC_FNMSUB | (0x1 << 25),
+};
+
+#define MASK_OP_FP_ARITH(op) (MASK_OP_MAJOR(op) | (op & (0x7F << 25)))
+enum {
+ // float
+ OPC_RISC_FADD_S = OPC_RISC_FP_ARITH | (0x0 << 25),
+ OPC_RISC_FSUB_S = OPC_RISC_FP_ARITH | (0x4 << 25),
+ OPC_RISC_FMUL_S = OPC_RISC_FP_ARITH | (0x8 << 25),
+ OPC_RISC_FDIV_S = OPC_RISC_FP_ARITH | (0xC << 25),
+
+ OPC_RISC_FSGNJ_S = OPC_RISC_FP_ARITH | (0x10 << 25),
+ OPC_RISC_FSGNJN_S = OPC_RISC_FP_ARITH | (0x10 << 25),
+ OPC_RISC_FSGNJX_S = OPC_RISC_FP_ARITH | (0x10 << 25),
+
+ OPC_RISC_FMIN_S = OPC_RISC_FP_ARITH | (0x14 << 25),
+ OPC_RISC_FMAX_S = OPC_RISC_FP_ARITH | (0x14 << 25),
+
+ OPC_RISC_FSQRT_S = OPC_RISC_FP_ARITH | (0x2C << 25),
+
+ OPC_RISC_FEQ_S = OPC_RISC_FP_ARITH | (0x50 << 25),
+ OPC_RISC_FLT_S = OPC_RISC_FP_ARITH | (0x50 << 25),
+ OPC_RISC_FLE_S = OPC_RISC_FP_ARITH | (0x50 << 25),
+
+ OPC_RISC_FCVT_W_S = OPC_RISC_FP_ARITH | (0x60 << 25),
+ OPC_RISC_FCVT_WU_S = OPC_RISC_FP_ARITH | (0x60 << 25),
+ OPC_RISC_FCVT_L_S = OPC_RISC_FP_ARITH | (0x60 << 25),
+ OPC_RISC_FCVT_LU_S = OPC_RISC_FP_ARITH | (0x60 << 25),
+
+ OPC_RISC_FCVT_S_W = OPC_RISC_FP_ARITH | (0x68 << 25),
+ OPC_RISC_FCVT_S_WU = OPC_RISC_FP_ARITH | (0x68 << 25),
+ OPC_RISC_FCVT_S_L = OPC_RISC_FP_ARITH | (0x68 << 25),
+ OPC_RISC_FCVT_S_LU = OPC_RISC_FP_ARITH | (0x68 << 25),
+
+ OPC_RISC_FMV_X_S = OPC_RISC_FP_ARITH | (0x70 << 25),
+ OPC_RISC_FCLASS_S = OPC_RISC_FP_ARITH | (0x70 << 25),
+
+ OPC_RISC_FMV_S_X = OPC_RISC_FP_ARITH | (0x78 << 25),
+
+ // double
+ OPC_RISC_FADD_D = OPC_RISC_FP_ARITH | (0x1 << 25),
+ OPC_RISC_FSUB_D = OPC_RISC_FP_ARITH | (0x5 << 25),
+ OPC_RISC_FMUL_D = OPC_RISC_FP_ARITH | (0x9 << 25),
+ OPC_RISC_FDIV_D = OPC_RISC_FP_ARITH | (0xD << 25),
+
+ OPC_RISC_FSGNJ_D = OPC_RISC_FP_ARITH | (0x11 << 25),
+ OPC_RISC_FSGNJN_D = OPC_RISC_FP_ARITH | (0x11 << 25),
+ OPC_RISC_FSGNJX_D = OPC_RISC_FP_ARITH | (0x11 << 25),
+
+ OPC_RISC_FMIN_D = OPC_RISC_FP_ARITH | (0x15 << 25),
+ OPC_RISC_FMAX_D = OPC_RISC_FP_ARITH | (0x15 << 25),
+
+ OPC_RISC_FCVT_S_D = OPC_RISC_FP_ARITH | (0x20 << 25),
+
+ OPC_RISC_FCVT_D_S = OPC_RISC_FP_ARITH | (0x21 << 25),
+
+ OPC_RISC_FSQRT_D = OPC_RISC_FP_ARITH | (0x2D << 25),
+
+ OPC_RISC_FEQ_D = OPC_RISC_FP_ARITH | (0x51 << 25),
+ OPC_RISC_FLT_D = OPC_RISC_FP_ARITH | (0x51 << 25),
+ OPC_RISC_FLE_D = OPC_RISC_FP_ARITH | (0x51 << 25),
+
+ OPC_RISC_FCVT_W_D = OPC_RISC_FP_ARITH | (0x61 << 25),
+ OPC_RISC_FCVT_WU_D = OPC_RISC_FP_ARITH | (0x61 << 25),
+ OPC_RISC_FCVT_L_D = OPC_RISC_FP_ARITH | (0x61 << 25),
+ OPC_RISC_FCVT_LU_D = OPC_RISC_FP_ARITH | (0x61 << 25),
+
+ OPC_RISC_FCVT_D_W = OPC_RISC_FP_ARITH | (0x69 << 25),
+ OPC_RISC_FCVT_D_WU = OPC_RISC_FP_ARITH | (0x69 << 25),
+ OPC_RISC_FCVT_D_L = OPC_RISC_FP_ARITH | (0x69 << 25),
+ OPC_RISC_FCVT_D_LU = OPC_RISC_FP_ARITH | (0x69 << 25),
+
+ OPC_RISC_FMV_X_D = OPC_RISC_FP_ARITH | (0x71 << 25),
+ OPC_RISC_FCLASS_D = OPC_RISC_FP_ARITH | (0x71 << 25),
+
+ OPC_RISC_FMV_D_X = OPC_RISC_FP_ARITH | (0x79 << 25),
+};
+
+#define GET_B_IMM(inst) ((int16_t)((((inst >> 25) & 0x3F) << 5) | ((((int32_t)inst) >> 31) << 12) | (((inst >> 8) & 0xF) << 1) | (((inst >> 7) & 0x1) << 11))) /* THIS BUILDS 13 bit imm (implicit zero is tacked on here), also note that bit #12 is obtained in a special way to get sign extension */
+#define GET_STORE_IMM(inst) ((int16_t)(((((int32_t)inst) >> 25) << 5) | ((inst >> 7) & 0x1F)))
+#define GET_JAL_IMM(inst) ((int32_t)((inst & 0xFF000) | (((inst >> 20) & 0x1) << 11) | (((inst >> 21) & 0x3FF) << 1) | ((((int32_t)inst) >> 31) << 20)))
+#define GET_RM(inst) ((inst >> 12) & 0x7)
+#define GET_RS3(inst) ((inst >> 27) & 0x1F)
+
new file mode 100644
@@ -0,0 +1,91 @@
+/*
+ * RISC-V CPU Machine State Helpers
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+#include "cpu.h"
+
+static void save_tc(QEMUFile *f, TCState *tc)
+{
+ int i;
+ /* Save active TC */
+ for (i = 0; i < 32; i++) {
+ qemu_put_betls(f, &tc->gpr[i]);
+ }
+ for (i = 0; i < 32; i++) {
+ qemu_put_betls(f, &tc->fpr[i]);
+ }
+ qemu_put_betls(f, &tc->PC);
+ qemu_put_betls(f, &tc->load_reservation);
+}
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+ CPURISCVState *env = opaque;
+ int i;
+
+ /* Save active TC */
+ save_tc(f, &env->active_tc);
+
+ /* Save CPU metastate */
+ qemu_put_be32s(f, &env->current_tc);
+
+ for (i = 0; i < 4096; i++) {
+ qemu_put_betls(f, &env->csr[i]);
+ }
+}
+
+static void load_tc(QEMUFile *f, TCState *tc)
+{
+ int i;
+ /* Save active TC */
+ for(i = 0; i < 32; i++) {
+ qemu_get_betls(f, &tc->gpr[i]);
+ }
+ for(i = 0; i < 32; i++) {
+ qemu_get_betls(f, &tc->fpr[i]);
+ }
+ qemu_get_betls(f, &tc->PC);
+ qemu_get_betls(f, &tc->load_reservation);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+ CPURISCVState *env = opaque;
+ RISCVCPU *cpu = riscv_env_get_cpu(env);
+ int i;
+
+ if (version_id != 3)
+ return -EINVAL;
+
+ /* Load active TC */
+ load_tc(f, &env->active_tc);
+
+ /* Load CPU metastate */
+ qemu_get_be32s(f, &env->current_tc);
+
+ for (i = 0; i < 4096; i++) {
+ qemu_get_betls(f, &env->csr[i]);
+ }
+
+ tlb_flush(CPU(cpu), 1);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,1037 @@
+/*
+ * RISC-V Emulation Helpers for QEMU.
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include "cpu.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+
+// custom floating point includes. use this instead of qemu's included
+// fpu/softmmu since we know it already works exactly as desired for riscv
+#include "fpu-custom-riscv/softfloat.h"
+#include "fpu-custom-riscv/platform.h"
+#include "fpu-custom-riscv/internals.h"
+
+static int validate_vm(target_ulong vm) {
+ return vm == VM_SV39 || vm == VM_SV48 || vm == VM_MBARE;
+}
+
+static int validate_priv(target_ulong priv) {
+ return priv == PRV_U || priv == PRV_S || priv == PRV_M;
+}
+
+/* Exceptions processing helpers */
+static inline void QEMU_NORETURN do_raise_exception_err(CPURISCVState *env,
+ uint32_t exception, uintptr_t pc)
+{
+ CPUState *cs = CPU(riscv_env_get_cpu(env));
+ qemu_log("%s: %d\n", __func__, exception);
+ cs->exception_index = exception;
+ cpu_loop_exit_restore(cs, pc);
+}
+
+void helper_raise_exception(CPURISCVState *env, uint32_t exception)
+{
+ do_raise_exception_err(env, exception, 0);
+}
+
+void helper_raise_exception_debug(CPURISCVState *env)
+{
+ do_raise_exception_err(env, EXCP_DEBUG, 0);
+}
+
+
+void helper_raise_exception_err(CPURISCVState *env, uint32_t exception, target_ulong pc)
+{
+ do_raise_exception_err(env, exception, pc);
+}
+
+void helper_raise_exception_mbadaddr(CPURISCVState *env, uint32_t exception,
+ target_ulong bad_pc) {
+ env->csr[NEW_CSR_MBADADDR] = bad_pc;
+ do_raise_exception_err(env, exception, 0);
+}
+
+/* floating point */
+uint64_t helper_fmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t frs3, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f32_mulAdd(frs1, frs2, frs3);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t frs3, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f64_mulAdd(frs1, frs2, frs3);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t frs3, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f32_mulAdd(frs1, frs2, frs3 ^ (uint32_t)INT32_MIN);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fmsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t frs3, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f64_mulAdd(frs1, frs2, frs3 ^ (uint64_t)INT64_MIN);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fnmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t frs3, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f32_mulAdd(frs1 ^ (uint32_t)INT32_MIN, frs2, frs3);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fnmsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t frs3, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f64_mulAdd(frs1 ^ (uint64_t)INT64_MIN, frs2, frs3);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fnmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t frs3, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f32_mulAdd(frs1 ^ (uint32_t)INT32_MIN, frs2, frs3 ^ (uint32_t)INT32_MIN);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t frs3, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f64_mulAdd(frs1 ^ (uint64_t)INT64_MIN, frs2, frs3 ^ (uint64_t)INT64_MIN);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f32_mulAdd(frs1, 0x3f800000, frs2);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f32_mulAdd(frs1, 0x3f800000, frs2 ^ (uint32_t)INT32_MIN);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fmul_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f32_mulAdd(frs1, frs2, (frs1 ^ frs2) & (uint32_t)INT32_MIN);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fdiv_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f32_div(frs1, frs2);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fsgnj_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = (frs1 &~ (uint32_t)INT32_MIN) | (frs2 & (uint32_t)INT32_MIN);
+ return frs1;
+}
+
+uint64_t helper_fsgnjn_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = (frs1 &~ (uint32_t)INT32_MIN) | ((~frs2) & (uint32_t)INT32_MIN);
+ return frs1;
+}
+
+uint64_t helper_fsgnjx_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = frs1 ^ (frs2 & (uint32_t)INT32_MIN);
+ return frs1;
+}
+
+uint64_t helper_fmin_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = isNaNF32UI(frs2) || f32_lt_quiet(frs1, frs2) ? frs1 : frs2;
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fmax_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = isNaNF32UI(frs2) || f32_le_quiet(frs2, frs1) ? frs1 : frs2;
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fsqrt_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f32_sqrt(frs1);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fle_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = f32_le(frs1, frs2);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_flt_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = f32_lt(frs1, frs2);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_feq_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = f32_eq(frs1, frs2);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fcvt_w_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = (int64_t)((int32_t)f32_to_i32(frs1, RISCV_RM, true));
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fcvt_wu_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = (int64_t)((int32_t)f32_to_ui32(frs1, RISCV_RM, true));
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fcvt_l_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f32_to_i64(frs1, RISCV_RM, true);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fcvt_lu_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f32_to_ui64(frs1, RISCV_RM, true);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fcvt_s_w(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ rs1 = i32_to_f32((int32_t)rs1);
+ set_fp_exceptions;
+ return rs1;
+}
+
+uint64_t helper_fcvt_s_wu(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ rs1 = ui32_to_f32((uint32_t)rs1);
+ set_fp_exceptions;
+ return rs1;
+}
+
+uint64_t helper_fcvt_s_l(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ rs1 = i64_to_f32(rs1);
+ set_fp_exceptions;
+ return rs1;
+}
+
+uint64_t helper_fcvt_s_lu(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ rs1 = ui64_to_f32(rs1);
+ set_fp_exceptions;
+ return rs1;
+}
+
+uint64_t helper_fclass_s(CPURISCVState *env, uint64_t frs1)
+{
+ frs1 = f32_classify(frs1);
+ return frs1;
+}
+
+uint64_t helper_fadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f64_mulAdd(frs1, 0x3ff0000000000000ULL, frs2);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f64_mulAdd(frs1, 0x3ff0000000000000ULL, frs2 ^ (uint64_t)INT64_MIN);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fmul_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f64_mulAdd(frs1, frs2, (frs1 ^ frs2) & (uint64_t)INT64_MIN);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fdiv_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f64_div(frs1, frs2);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fsgnj_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = (frs1 &~ INT64_MIN) | (frs2 & INT64_MIN);
+ return frs1;
+}
+
+uint64_t helper_fsgnjn_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = (frs1 &~ INT64_MIN) | ((~frs2) & INT64_MIN);
+ return frs1;
+}
+
+uint64_t helper_fsgnjx_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = frs1 ^ (frs2 & INT64_MIN);
+ return frs1;
+}
+
+uint64_t helper_fmin_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = isNaNF64UI(frs2) || f64_lt_quiet(frs1, frs2) ? frs1 : frs2;
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fmax_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = isNaNF64UI(frs2) || f64_le_quiet(frs2, frs1) ? frs1 : frs2;
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fcvt_s_d(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ rs1 = f64_to_f32(rs1);
+ set_fp_exceptions;
+ return rs1;
+}
+
+uint64_t helper_fcvt_d_s(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ rs1 = f32_to_f64(rs1);
+ set_fp_exceptions;
+ return rs1;
+}
+
+uint64_t helper_fsqrt_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f64_sqrt(frs1);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fle_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = f64_le(frs1, frs2);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_flt_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = f64_lt(frs1, frs2);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_feq_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = f64_eq(frs1, frs2);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fcvt_w_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = (int64_t)((int32_t)f64_to_i32(frs1, RISCV_RM, true));
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fcvt_wu_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = (int64_t)((int32_t)f64_to_ui32(frs1, RISCV_RM, true));
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f64_to_i64(frs1, RISCV_RM, true);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = f64_to_ui64(frs1, RISCV_RM, true);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fcvt_d_w(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = i32_to_f64((int32_t)frs1);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fcvt_d_wu(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = ui32_to_f64((uint32_t)frs1);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fcvt_d_l(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = i64_to_f64(frs1);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fcvt_d_lu(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ softfloat_roundingMode = RISCV_RM;
+ frs1 = ui64_to_f64(frs1);
+ set_fp_exceptions;
+ return frs1;
+}
+
+uint64_t helper_fclass_d(CPURISCVState *env, uint64_t frs1)
+{
+ frs1 = f64_classify(frs1);
+ return frs1;
+}
+
+target_ulong helper_mulhsu(CPURISCVState *env, target_ulong arg1,
+ target_ulong arg2)
+{
+ int64_t a = arg1;
+ uint64_t b = arg2;
+ return (int64_t)((__int128_t)a*b >> 64);
+}
+
+/*
+ * Handle writes to CSRs and any resulting special behavior
+ *
+ * Note: mtohost and mfromhost are not handled here
+ */
+inline void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
+ target_ulong csrno)
+{
+ #ifdef RISCV_DEBUG_PRINT
+ fprintf(stderr, "Write CSR reg: 0x" TARGET_FMT_lx "\n", csrno);
+ fprintf(stderr, "Write CSR val: 0x" TARGET_FMT_lx "\n", val_to_write);
+ #endif
+
+ switch (csrno)
+ {
+ case NEW_CSR_FFLAGS:
+ env->csr[NEW_CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD;
+ env->csr[NEW_CSR_FFLAGS] = val_to_write & (FSR_AEXC >> FSR_AEXC_SHIFT);
+ break;
+ case NEW_CSR_FRM:
+ env->csr[NEW_CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD;
+ env->csr[NEW_CSR_FRM] = val_to_write & (FSR_RD >> FSR_RD_SHIFT);
+ break;
+ case NEW_CSR_FCSR:
+ env->csr[NEW_CSR_MSTATUS] |= MSTATUS_FS | MSTATUS64_SD;
+ env->csr[NEW_CSR_FFLAGS] = (val_to_write & FSR_AEXC) >> FSR_AEXC_SHIFT;
+ env->csr[NEW_CSR_FRM] = (val_to_write & FSR_RD) >> FSR_RD_SHIFT;
+ break;
+ case NEW_CSR_MTIME:
+ case NEW_CSR_STIMEW:
+ // this implementation ignores writes to MTIME
+ break;
+ case NEW_CSR_MTIMEH:
+ case NEW_CSR_STIMEHW:
+ // this implementation ignores writes to MTIME
+ break;
+ case NEW_CSR_TIMEW:
+ cpu_riscv_store_timew(env, val_to_write);
+ break;
+ case NEW_CSR_TIMEHW:
+ fprintf(stderr, "CSR_TIMEHW unsupported on RV64I\n");
+ exit(1);
+ break;
+ case NEW_CSR_CYCLEW:
+ case NEW_CSR_INSTRETW:
+ cpu_riscv_store_instretw(env, val_to_write);
+ break;
+ case NEW_CSR_CYCLEHW:
+ case NEW_CSR_INSTRETHW:
+ fprintf(stderr, "CSR_CYCLEHW/INSTRETHW unsupported on RV64I\n");
+ exit(1);
+ break;
+ case NEW_CSR_MSTATUS: {
+ target_ulong mstatus = env->csr[NEW_CSR_MSTATUS];
+ #ifdef RISCV_DEBUG_PRINT
+ target_ulong debug_mstatus = mstatus;
+ #endif
+ if ((val_to_write ^ mstatus) &
+ (MSTATUS_VM | MSTATUS_PRV | MSTATUS_PRV1 | MSTATUS_MPRV)) {
+ #ifdef RISCV_DEBUG_PRINT
+ fprintf(stderr, "flushing TLB\n");
+ #endif
+ helper_tlb_flush(env);
+ }
+
+ // no extension support
+ target_ulong mask = MSTATUS_IE | MSTATUS_IE1 | MSTATUS_IE2
+ | MSTATUS_MPRV | MSTATUS_FS;
+
+ if (validate_vm(get_field(val_to_write, MSTATUS_VM))) {
+ mask |= MSTATUS_VM;
+ }
+ if (validate_priv(get_field(val_to_write, MSTATUS_PRV))) {
+ mask |= MSTATUS_PRV;
+ }
+ if (validate_priv(get_field(val_to_write, MSTATUS_PRV1))) {
+ mask |= MSTATUS_PRV1;
+ }
+ if (validate_priv(get_field(val_to_write, MSTATUS_PRV2))) {
+ mask |= MSTATUS_PRV2;
+ }
+
+ mstatus = (mstatus & ~mask) | (val_to_write & mask);
+
+ int dirty = (mstatus & MSTATUS_FS) == MSTATUS_FS;
+ dirty |= (mstatus & MSTATUS_XS) == MSTATUS_XS;
+ mstatus = set_field(mstatus, MSTATUS64_SD, dirty);
+ env->csr[NEW_CSR_MSTATUS] = mstatus;
+ break;
+ }
+ case NEW_CSR_MIP: {
+ target_ulong mask = MIP_SSIP | MIP_MSIP | MIP_STIP;
+ env->csr[NEW_CSR_MIP] = (env->csr[NEW_CSR_MIP] & ~mask) |
+ (val_to_write & mask);
+ CPUState *cs = CPU(riscv_env_get_cpu(env));
+ if (env->csr[NEW_CSR_MIP] & MIP_SSIP) {
+ stw_phys(cs->as, 0xFFFFFFFFF0000020, 0x1);
+ } else {
+ stw_phys(cs->as, 0xFFFFFFFFF0000020, 0x0);
+ }
+ if (env->csr[NEW_CSR_MIP] & MIP_STIP) {
+ stw_phys(cs->as, 0xFFFFFFFFF0000040, 0x1);
+ } else {
+ stw_phys(cs->as, 0xFFFFFFFFF0000040, 0x0);
+ }
+ if (env->csr[NEW_CSR_MIP] & MIP_MSIP) {
+ stw_phys(cs->as, 0xFFFFFFFFF0000060, 0x1);
+ } else {
+ stw_phys(cs->as, 0xFFFFFFFFF0000060, 0x0);
+ }
+ break;
+ }
+ case NEW_CSR_MIPI: {
+ CPUState *cs = CPU(riscv_env_get_cpu(env));
+ env->csr[NEW_CSR_MIP] = set_field(env->csr[NEW_CSR_MIP], MIP_MSIP, val_to_write & 1);
+ if (env->csr[NEW_CSR_MIP] & MIP_MSIP) {
+ stw_phys(cs->as, 0xFFFFFFFFF0000060, 0x1);
+ } else {
+ stw_phys(cs->as, 0xFFFFFFFFF0000060, 0x0);
+ }
+ break;
+ }
+ case NEW_CSR_MIE: {
+ target_ulong mask = MIP_SSIP | MIP_MSIP | MIP_STIP | MIP_MTIP;
+ env->csr[NEW_CSR_MIE] = (env->csr[NEW_CSR_MIE] & ~mask) |
+ (val_to_write & mask);
+ break;
+ }
+ case NEW_CSR_SSTATUS: {
+ target_ulong ms = env->csr[NEW_CSR_MSTATUS];
+ ms = set_field(ms, MSTATUS_IE, get_field(val_to_write, SSTATUS_IE));
+ ms = set_field(ms, MSTATUS_IE1, get_field(val_to_write, SSTATUS_PIE));
+ ms = set_field(ms, MSTATUS_PRV1, get_field(val_to_write, SSTATUS_PS));
+ ms = set_field(ms, MSTATUS_FS, get_field(val_to_write, SSTATUS_FS));
+ ms = set_field(ms, MSTATUS_XS, get_field(val_to_write, SSTATUS_XS));
+ ms = set_field(ms, MSTATUS_MPRV, get_field(val_to_write, SSTATUS_MPRV));
+ csr_write_helper(env, ms, NEW_CSR_MSTATUS);
+ break;
+ }
+ case NEW_CSR_SIP: {
+ target_ulong mask = MIP_SSIP;
+ env->csr[NEW_CSR_MIP] = (env->csr[NEW_CSR_MIP] & ~mask) |
+ (val_to_write & mask);
+ CPUState *cs = CPU(riscv_env_get_cpu(env));
+ if (env->csr[NEW_CSR_MIP] & MIP_SSIP) {
+ stw_phys(cs->as, 0xFFFFFFFFF0000020, 0x1);
+ } else {
+ stw_phys(cs->as, 0xFFFFFFFFF0000020, 0x0);
+ }
+ break;
+ }
+ case NEW_CSR_SIE: {
+ target_ulong mask = MIP_SSIP | MIP_STIP;
+ env->csr[NEW_CSR_MIE] = (env->csr[NEW_CSR_MIE] & ~mask) |
+ (val_to_write & mask);
+ break;
+ }
+ case NEW_CSR_SEPC:
+ env->csr[NEW_CSR_SEPC] = val_to_write;
+ break;
+ case NEW_CSR_STVEC:
+ env->csr[NEW_CSR_STVEC] = val_to_write >> 2 << 2;
+ break;
+ case NEW_CSR_SPTBR:
+ env->csr[NEW_CSR_SPTBR] = val_to_write & -(1L << PGSHIFT);
+ break;
+ case NEW_CSR_SSCRATCH:
+ env->csr[NEW_CSR_SSCRATCH] = val_to_write;
+ break;
+ case NEW_CSR_MEPC:
+ env->csr[NEW_CSR_MEPC] = val_to_write;
+ break;
+ case NEW_CSR_MSCRATCH:
+ env->csr[NEW_CSR_MSCRATCH] = val_to_write;
+ break;
+ case NEW_CSR_MCAUSE:
+ env->csr[NEW_CSR_MCAUSE] = val_to_write;
+ break;
+ case NEW_CSR_MBADADDR:
+ env->csr[NEW_CSR_MBADADDR] = val_to_write;
+ break;
+ case NEW_CSR_MTIMECMP:
+ // NOTE: clearing bit in MIP handled in cpu_riscv_store_compare
+ cpu_riscv_store_compare(env, val_to_write);
+ break;
+ case NEW_CSR_MTOHOST:
+ fprintf(stderr, "Write to mtohost should not be handled here\n");
+ exit(1);
+ break;
+ case NEW_CSR_MFROMHOST:
+ fprintf(stderr, "Write to mfromhost should not be handled here\n");
+ exit(1);
+ break;
+ }
+}
+
+/*
+ * Handle reads to CSRs and any resulting special behavior
+ *
+ * Note: mtohost and mfromhost are not handled here
+ */
+inline target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno)
+{
+ int csrno2 = (int)csrno;
+ #ifdef RISCV_DEBUG_PRINT
+ fprintf(stderr, "READ CSR 0x%x\n", csrno2);
+ #endif
+
+ switch (csrno2)
+ {
+ case NEW_CSR_FFLAGS:
+ return env->csr[NEW_CSR_FFLAGS];
+ case NEW_CSR_FRM:
+ return env->csr[NEW_CSR_FRM];
+ case NEW_CSR_FCSR:
+ return (env->csr[NEW_CSR_FFLAGS] << FSR_AEXC_SHIFT) |
+ (env->csr[NEW_CSR_FRM] << FSR_RD_SHIFT);
+ case NEW_CSR_MTIME:
+ return cpu_riscv_read_mtime(env);
+ case NEW_CSR_STIME:
+ case NEW_CSR_STIMEW:
+ return cpu_riscv_read_stime(env);
+ case NEW_CSR_MTIMEH:
+ case NEW_CSR_STIMEH:
+ case NEW_CSR_STIMEHW:
+ fprintf(stderr, "CSR_MTIMEH unsupported on RV64I\n");
+ exit(1);
+ case NEW_CSR_TIME:
+ case NEW_CSR_TIMEW:
+ return cpu_riscv_read_time(env);
+ case NEW_CSR_CYCLE:
+ case NEW_CSR_CYCLEW:
+ case NEW_CSR_INSTRET:
+ case NEW_CSR_INSTRETW:
+ return cpu_riscv_read_instretw(env);
+ case NEW_CSR_TIMEH:
+ case NEW_CSR_TIMEHW:
+ fprintf(stderr, "CSR_TIMEH unsupported on RV64I\n");
+ exit(1);
+ case NEW_CSR_CYCLEH:
+ case NEW_CSR_INSTRETH:
+ case NEW_CSR_CYCLEHW:
+ case NEW_CSR_INSTRETHW:
+ fprintf(stderr, "CSR_INSTRETH unsupported on RV64I\n");
+ exit(1);
+ case NEW_CSR_SSTATUS: {
+ target_ulong ss = 0;
+ ss = set_field(ss, SSTATUS_IE, get_field(env->csr[NEW_CSR_MSTATUS],
+ MSTATUS_IE));
+ ss = set_field(ss, SSTATUS_PIE, get_field(env->csr[NEW_CSR_MSTATUS],
+ MSTATUS_IE1));
+ ss = set_field(ss, SSTATUS_PS, get_field(env->csr[NEW_CSR_MSTATUS],
+ MSTATUS_PRV1));
+ ss = set_field(ss, SSTATUS_FS, get_field(env->csr[NEW_CSR_MSTATUS],
+ MSTATUS_FS));
+ ss = set_field(ss, SSTATUS_XS, get_field(env->csr[NEW_CSR_MSTATUS],
+ MSTATUS_XS));
+ ss = set_field(ss, SSTATUS_MPRV, get_field(env->csr[NEW_CSR_MSTATUS],
+ MSTATUS_MPRV));
+ if (get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS64_SD)) {
+ ss = set_field(ss, SSTATUS64_SD, 1);
+ }
+ return ss;
+ }
+ case NEW_CSR_SIP:
+ return env->csr[NEW_CSR_MIP] & (MIP_SSIP | MIP_STIP);
+ case NEW_CSR_SIE:
+ return env->csr[NEW_CSR_MIE] & (MIP_SSIP | MIP_STIP);
+ case NEW_CSR_SEPC:
+ return env->csr[NEW_CSR_SEPC];
+ case NEW_CSR_SBADADDR:
+ return env->csr[NEW_CSR_SBADADDR];
+ case NEW_CSR_STVEC:
+ return env->csr[NEW_CSR_STVEC];
+ case NEW_CSR_SCAUSE:
+ return env->csr[NEW_CSR_SCAUSE];
+ case NEW_CSR_SPTBR:
+ return env->csr[NEW_CSR_SPTBR];
+ case NEW_CSR_SASID:
+ return 0;
+ case NEW_CSR_SSCRATCH:
+ return env->csr[NEW_CSR_SSCRATCH];
+ case NEW_CSR_MSTATUS:
+ return env->csr[NEW_CSR_MSTATUS];
+ case NEW_CSR_MIP:
+ return env->csr[NEW_CSR_MIP];
+ case NEW_CSR_MIPI:
+ return 0;
+ case NEW_CSR_MIE:
+ return env->csr[NEW_CSR_MIE];
+ case NEW_CSR_MEPC:
+ return env->csr[NEW_CSR_MEPC];
+ case NEW_CSR_MSCRATCH:
+ return env->csr[NEW_CSR_MSCRATCH];
+ case NEW_CSR_MCAUSE:
+ return env->csr[NEW_CSR_MCAUSE];
+ case NEW_CSR_MBADADDR:
+ return env->csr[NEW_CSR_MBADADDR];
+ case NEW_CSR_MTIMECMP:
+ return env->csr[NEW_CSR_MTIMECMP];
+ case NEW_CSR_MCPUID:
+ return env->csr[NEW_CSR_MCPUID];
+ case NEW_CSR_MIMPID:
+ return 0x1; // "Rocket"
+ case NEW_CSR_MHARTID:
+ return 0;
+ case NEW_CSR_MTVEC:
+ return DEFAULT_MTVEC;
+ case NEW_CSR_MTDELEG:
+ return 0;
+ case NEW_CSR_MTOHOST:
+ fprintf(stderr, "Read from mtohost should not be handled here\n");
+ exit(1);
+ case NEW_CSR_MFROMHOST:
+ fprintf(stderr, "Read from mfromhost should not be handled here\n");
+ exit(1);
+ case NEW_CSR_MIOBASE:
+ return env->memsize;
+ case NEW_CSR_UARCH0:
+ case NEW_CSR_UARCH1:
+ case NEW_CSR_UARCH2:
+ case NEW_CSR_UARCH3:
+ case NEW_CSR_UARCH4:
+ case NEW_CSR_UARCH5:
+ case NEW_CSR_UARCH6:
+ case NEW_CSR_UARCH7:
+ case NEW_CSR_UARCH8:
+ case NEW_CSR_UARCH9:
+ case NEW_CSR_UARCH10:
+ case NEW_CSR_UARCH11:
+ case NEW_CSR_UARCH12:
+ case NEW_CSR_UARCH13:
+ case NEW_CSR_UARCH14:
+ case NEW_CSR_UARCH15:
+ return 0;
+ }
+ fprintf(stderr, "Attempt to read invalid csr!\n");
+ exit(1);
+}
+
+void validate_csr(CPURISCVState *env, uint64_t which, uint64_t write,
+ uint64_t new_pc) {
+ unsigned my_priv = get_field(env->csr[NEW_CSR_MSTATUS], MSTATUS_PRV);
+ unsigned csr_priv = get_field((which), 0x300);
+ unsigned csr_read_only = get_field((which), 0xC00) == 3;
+ if (((write) && csr_read_only) || (my_priv < csr_priv)) {
+ do_raise_exception_err(env, NEW_RISCV_EXCP_ILLEGAL_INST, new_pc);
+ }
+ return;
+}
+
+target_ulong helper_csrrw(CPURISCVState *env, target_ulong src,
+ target_ulong csr, target_ulong new_pc)
+{
+ validate_csr(env, csr, 1, new_pc);
+ uint64_t csr_backup = csr_read_helper(env, csr);
+ csr_write_helper(env, src, csr);
+ return csr_backup;
+}
+
+target_ulong helper_csrrs(CPURISCVState *env, target_ulong src,
+ target_ulong csr, target_ulong new_pc)
+{
+ validate_csr(env, csr, src != 0, new_pc);
+ uint64_t csr_backup = csr_read_helper(env, csr);
+ csr_write_helper(env, src | csr_backup, csr);
+ return csr_backup;
+}
+
+// match spike behavior for validate_csr write flag
+target_ulong helper_csrrsi(CPURISCVState *env, target_ulong src,
+ target_ulong csr, target_ulong new_pc)
+{
+ validate_csr(env, csr, 1, new_pc);
+ uint64_t csr_backup = csr_read_helper(env, csr);
+ csr_write_helper(env, src | csr_backup, csr);
+ return csr_backup;
+}
+
+target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
+ target_ulong csr, target_ulong new_pc) {
+ validate_csr(env, csr, 1, new_pc);
+ uint64_t csr_backup = csr_read_helper(env, csr);
+ csr_write_helper(env, (~src) & csr_backup, csr);
+ return csr_backup;
+}
+
+/*
+ * This is a debug print helper for printing trace.
+ * Currently calls spike-dasm, so very slow.
+ * Probably not useful unless you're debugging riscv-qemu
+ */
+void helper_debug_print(CPURISCVState *env, target_ulong cpu_pc_deb,
+ target_ulong instruction)
+{
+/* int buflen = 100;
+ char runbuf[buflen];
+ char path[buflen];
+
+ snprintf(runbuf, buflen, "echo 'DASM(%08lx)\n' | spike-dasm", instruction);
+
+ FILE *fp;
+ fp = popen(runbuf, "r");
+ if (fp == NULL) {
+ printf("popen fail\n");
+ exit(1);
+ }
+ if (fgets(path, sizeof(path)-1, fp) != NULL) {
+ fprintf(stderr, ": core 0: 0x" TARGET_FMT_lx " (0x%08lx) %s",
+ cpu_pc_deb, instruction, path);
+ } else {*/
+ fprintf(stderr, ": core 0: 0x" TARGET_FMT_lx " (0x%08lx) %s",
+ cpu_pc_deb, instruction, "DASM BAD RESULT\n");
+/* }
+ pclose(fp);*/
+}
+
+target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
+{
+ target_ulong mstatus = env->csr[NEW_CSR_MSTATUS];
+ if(!(get_field(mstatus, MSTATUS_PRV) >= PRV_S)) {
+ // TODO: real illegal instruction trap
+ printf("ILLEGAL INST");
+ exit(1);
+ }
+
+ target_ulong retpc = 0;
+ switch(get_field(mstatus, MSTATUS_PRV)) {
+ case PRV_S:
+ // set PC val to sepc
+ retpc = env->csr[NEW_CSR_SEPC];
+ break;
+ case PRV_M:
+ // set PC val to mepc
+ retpc = env->csr[NEW_CSR_MEPC];
+ break;
+ default:
+ // TODO: illegal inst
+ printf("ILLEGAL INST");
+ exit(1);
+ break;
+ }
+ if (retpc & 0x3) {
+ // check for misaligned fetch
+ helper_raise_exception_mbadaddr(env, NEW_RISCV_EXCP_INST_ADDR_MIS,
+ cpu_pc_deb);
+ return cpu_pc_deb;
+ }
+
+ target_ulong next_mstatus = pop_priv_stack(env->csr[NEW_CSR_MSTATUS]);
+ csr_write_helper(env, next_mstatus, NEW_CSR_MSTATUS);
+ return retpc;
+}
+
+target_ulong helper_mrts(CPURISCVState *env, target_ulong curr_pc)
+{
+ target_ulong mstatus = env->csr[NEW_CSR_MSTATUS];
+ if(!(get_field(mstatus, MSTATUS_PRV) >= PRV_M)) {
+ // TODO: real illegal instruction trap
+ printf("ILLEGAL INST");
+ exit(1);
+ }
+
+ csr_write_helper(env, set_field(mstatus, MSTATUS_PRV, PRV_S),
+ NEW_CSR_MSTATUS);
+ env->csr[NEW_CSR_SBADADDR] = env->csr[NEW_CSR_MBADADDR];
+ env->csr[NEW_CSR_SCAUSE] = env->csr[NEW_CSR_MCAUSE];
+ env->csr[NEW_CSR_SEPC] = env->csr[NEW_CSR_MEPC];
+
+ if (env->csr[NEW_CSR_STVEC] & 0x3) {
+ helper_raise_exception_mbadaddr(env, NEW_RISCV_EXCP_INST_ADDR_MIS,
+ curr_pc);
+ return curr_pc;
+ }
+ return env->csr[NEW_CSR_STVEC];
+}
+
+
+#ifndef CONFIG_USER_ONLY
+
+/* TLB and translation cache management functions */
+
+inline void cpu_riscv_tlb_flush (CPURISCVState *env, int flush_global)
+{
+ RISCVCPU *cpu = riscv_env_get_cpu(env);
+ // Flush QEMU's TLB
+ tlb_flush(CPU(cpu), flush_global);
+}
+
+void helper_fence_i(CPURISCVState *env) {
+ RISCVCPU *cpu = riscv_env_get_cpu(env);
+ CPUState *cs = CPU(cpu);
+ // Flush QEMU's TLB
+ tlb_flush(cs, 1);
+ // ARM port seems to not know if this is okay inside a TB...
+ // But we need to do it
+ tb_flush(cs);
+}
+
+void helper_tlb_flush(CPURISCVState *env)
+{
+ cpu_riscv_tlb_flush(env, 1);
+}
+
+#endif /* !CONFIG_USER_ONLY */
+
+#if !defined(CONFIG_USER_ONLY)
+
+void riscv_cpu_do_unaligned_access(CPUState *cs, target_ulong addr,
+ int rw, int is_user, uintptr_t retaddr)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ printf("addr: %016lx\n", addr);
+ if (rw & 0x2) {
+ fprintf(stderr, "unaligned inst fetch not handled here\n");
+ exit(1);
+ } else if (rw == 0x1) {
+ printf("Store\n");
+ cs->exception_index = NEW_RISCV_EXCP_STORE_AMO_ADDR_MIS;
+ env->csr[NEW_CSR_MBADADDR] = addr;
+ } else {
+ printf("Load\n");
+ cs->exception_index = NEW_RISCV_EXCP_LOAD_ADDR_MIS;
+ env->csr[NEW_CSR_MBADADDR] = addr;
+ }
+ do_raise_exception_err(env, cs->exception_index, retaddr);
+}
+
+/* called by qemu's softmmu to fill the qemu tlb */
+void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
+ uintptr_t retaddr)
+{
+ int ret;
+ ret = riscv_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
+ if (ret == TRANSLATE_FAIL) {
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ do_raise_exception_err(env, cs->exception_index, retaddr);
+ }
+}
+
+void riscv_cpu_unassigned_access(CPUState *cs, hwaddr addr, bool is_write,
+ bool is_exec, int unused, unsigned size)
+{
+ printf("unassigned address not implemented for riscv\n");
+ printf("unassigned Address: %016lX\n", addr);
+ exit(1);
+}
+
+#endif /* !CONFIG_USER_ONLY */
new file mode 100644
@@ -0,0 +1,14 @@
+#if !defined (__QEMU_RISCV_DEFS_H__)
+#define __QEMU_RISCV_DEFS_H__
+
+#define TARGET_PAGE_BITS 12 // 4 KiB Pages
+//#define RISCV_TLB_MAX 0 not used. was for MIPS tlb
+// if you're looking to change the QEMU softmmu size, look for TLB_
+// #define CPU_TLB_BITS 2 in /include/exec/cpu-defs.h
+
+#define TARGET_LONG_BITS 64 // this defs TCGv as TCGv_i64 in tcg/tcg-op.h
+// according to spec? 38 PPN + 12 Offset
+#define TARGET_PHYS_ADDR_SPACE_BITS 50
+#define TARGET_VIRT_ADDR_SPACE_BITS 39
+
+#endif /* !defined (__QEMU_RISCV_DEFS_H__) */
new file mode 100644
@@ -0,0 +1,2155 @@
+/*
+ * RISC-V emulation for qemu: main translation routines.
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "disas/disas.h"
+#include "tcg-op.h"
+#include "exec/cpu_ldst.h"
+
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
+
+#include "instmap.h"
+
+//#define DISABLE_CHAINING_BRANCH
+//#define DISABLE_CHAINING_JAL
+
+#define RISCV_DEBUG_DISAS 0
+
+/* global register indices */
+static TCGv_ptr cpu_env;
+static TCGv cpu_gpr[32], cpu_PC, cpu_fpr[32];
+static TCGv load_reservation;
+
+#include "exec/gen-icount.h"
+
+typedef struct DisasContext {
+ struct TranslationBlock *tb;
+ target_ulong pc;
+ uint32_t opcode;
+ int singlestep_enabled;
+ int mem_idx;
+ int bstate;
+} DisasContext;
+
+static inline void kill_unknown(DisasContext *ctx, int excp);
+
+enum {
+ BS_NONE = 0, // When seen outside of translation while loop, indicates
+ // need to exit tb due to end of page.
+ BS_STOP = 1, // Need to exit tb for syscall, sret, etc.
+ BS_BRANCH = 2, // Need to exit tb for branch, jal, etc.
+};
+
+static const char * const regnames[] = {
+ "zero", "ra ", "sp ", "gp ", "tp ", "t0 ", "t1 ", "t2 ",
+ "s0 ", "s1 ", "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ",
+ "a6 ", "a7 ", "s2 ", "s3 ", "s4 ", "s5 ", "s6 ", "s7 ",
+ "s8 ", "s9 ", "s10 ", "s11 ", "t3 ", "t4 ", "t5 ", "t6 "
+};
+
+static const char * const fpr_regnames[] = {
+ "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
+ "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
+ "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
+ "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
+};
+
+#define RISCV_DEBUG(fmt, ...) \
+ do { \
+ if (RISCV_DEBUG_DISAS) { \
+ qemu_log_mask(CPU_LOG_TB_IN_ASM, \
+ TARGET_FMT_lx ": %08x " fmt "\n", \
+ ctx->pc, ctx->opcode , ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+#define LOG_DISAS(...) \
+ do { \
+ if (RISCV_DEBUG_DISAS) { \
+ qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+static inline void generate_exception (DisasContext *ctx, int excp)
+{
+ tcg_gen_movi_tl(cpu_PC, ctx->pc);
+ TCGv_i32 helper_tmp = tcg_const_i32(excp);
+ gen_helper_raise_exception(cpu_env, helper_tmp);
+ tcg_temp_free_i32(helper_tmp);
+}
+
+static inline void generate_exception_mbadaddr(DisasContext *ctx, int excp)
+{
+ tcg_gen_movi_tl(cpu_PC, ctx->pc);
+ TCGv_i32 helper_tmp = tcg_const_i32(excp);
+ gen_helper_raise_exception_mbadaddr(cpu_env, helper_tmp, cpu_PC);
+ tcg_temp_free_i32(helper_tmp);
+}
+
+static inline void generate_exception_err (DisasContext *ctx, int excp)
+{
+ tcg_gen_movi_tl(cpu_PC, ctx->pc);
+ TCGv_i32 helper_tmp = tcg_const_i32(excp);
+ gen_helper_raise_exception_err(cpu_env, helper_tmp, cpu_PC);
+ tcg_temp_free_i32(helper_tmp);
+}
+
+
+// unknown instruction / fp disabled
+static inline void kill_unknown(DisasContext *ctx, int excp) {
+ generate_exception(ctx, excp);
+ ctx->bstate = BS_STOP;
+}
+
+static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+{
+ TranslationBlock *tb;
+ tb = ctx->tb;
+ if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
+ likely(!ctx->singlestep_enabled)) {
+ // we only allow direct chaining when the jump is to the same page
+ // otherwise, we could produce incorrect chains when address spaces
+ // change. see
+ // http://lists.gnu.org/archive/html/qemu-devel/2007-06/msg00213.html
+ tcg_gen_goto_tb(n);
+ tcg_gen_movi_tl(cpu_PC, dest);
+ tcg_gen_exit_tb((uintptr_t)tb + n);
+ } else {
+ tcg_gen_movi_tl(cpu_PC, dest);
+ if (ctx->singlestep_enabled) {
+ gen_helper_raise_exception_debug(cpu_env);
+ }
+ tcg_gen_exit_tb(0);
+ }
+}
+
+/* Wrapper for getting reg values - need to check of reg is zero since
+ * cpu_gpr[0] is not actually allocated
+ */
+static inline void gen_get_gpr (TCGv t, int reg_num)
+{
+ if (reg_num == 0) {
+ tcg_gen_movi_tl(t, 0);
+ } else {
+ tcg_gen_mov_tl(t, cpu_gpr[reg_num]);
+ }
+}
+
+/* Wrapper for setting reg values - need to check of reg is zero since
+ * cpu_gpr[0] is not actually allocated. this is more for safety purposes,
+ * since we usually avoid calling the OP_TYPE_gen function if we see a write to
+ * $zero
+ */
+static inline void gen_set_gpr (int reg_num_dst, TCGv t)
+{
+ if (reg_num_dst != 0) {
+ tcg_gen_mov_tl(cpu_gpr[reg_num_dst], t);
+ }
+}
+
+inline static void gen_arith(DisasContext *ctx, uint32_t opc,
+ int rd, int rs1, int rs2)
+{
+ TCGv source1, source2;
+
+ source1 = tcg_temp_new();
+ source2 = tcg_temp_new();
+
+ gen_get_gpr(source1, rs1);
+ gen_get_gpr(source2, rs2);
+
+ switch (opc) {
+
+ case OPC_RISC_ADD:
+ tcg_gen_add_tl(source1, source1, source2);
+ break;
+ case OPC_RISC_SUB:
+ tcg_gen_sub_tl(source1, source1, source2);
+ break;
+ case OPC_RISC_SLL:
+ tcg_gen_andi_tl(source2, source2, 0x3F);
+ tcg_gen_shl_tl(source1, source1, source2);
+ break;
+ case OPC_RISC_SLT:
+ tcg_gen_setcond_tl(TCG_COND_LT, source1, source1, source2);
+ break;
+ case OPC_RISC_SLTU:
+ tcg_gen_setcond_tl(TCG_COND_LTU, source1, source1, source2);
+ break;
+ case OPC_RISC_XOR:
+ tcg_gen_xor_tl(source1, source1, source2);
+ break;
+ case OPC_RISC_SRL:
+ tcg_gen_andi_tl(source2, source2, 0x3F);
+ tcg_gen_shr_tl(source1, source1, source2);
+ break;
+ case OPC_RISC_SRA:
+ tcg_gen_andi_tl(source2, source2, 0x3F);
+ tcg_gen_sar_tl(source1, source1, source2);
+ break;
+ case OPC_RISC_OR:
+ tcg_gen_or_tl(source1, source1, source2);
+ break;
+ case OPC_RISC_AND:
+ tcg_gen_and_tl(source1, source1, source2);
+ break;
+ case OPC_RISC_MUL:
+ tcg_gen_muls2_tl(source1, source2, source1, source2);
+ break;
+ case OPC_RISC_MULH:
+ tcg_gen_muls2_tl(source2, source1, source1, source2);
+ break;
+ case OPC_RISC_MULHSU:
+ gen_helper_mulhsu(source1, cpu_env, source1, source2);
+ break;
+ case OPC_RISC_MULHU:
+ tcg_gen_mulu2_tl(source2, source1, source1, source2);
+ break;
+ case OPC_RISC_DIV:
+ {
+ TCGv spec_source1, spec_source2;
+ TCGv cond1, cond2;
+ TCGLabel* handle_zero = gen_new_label();
+ TCGLabel* handle_overflow = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ spec_source1 = tcg_temp_local_new();
+ spec_source2 = tcg_temp_local_new();
+ cond1 = tcg_temp_local_new();
+ cond2 = tcg_temp_local_new();
+
+ gen_get_gpr(spec_source1, rs1);
+ gen_get_gpr(spec_source2, rs2);
+ tcg_gen_brcondi_tl(TCG_COND_EQ, spec_source2, 0x0, handle_zero);
+
+ // now, use temp reg to check if both overflow conditions satisfied
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, spec_source2, 0xFFFFFFFFFFFFFFFF); // divisor = -1
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, spec_source1, 0x8000000000000000);
+ tcg_gen_and_tl(cond1, cond1, cond2);
+
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cond1, 1, handle_overflow);
+ // normal case
+ tcg_gen_div_tl(spec_source1, spec_source1, spec_source2);
+ tcg_gen_br(done);
+ // special zero case
+ gen_set_label(handle_zero);
+ tcg_gen_movi_tl(spec_source1, -1);
+ tcg_gen_br(done);
+ // special overflow case
+ gen_set_label(handle_overflow);
+ tcg_gen_movi_tl(spec_source1, 0x8000000000000000);
+ // done
+ gen_set_label(done);
+ tcg_gen_mov_tl(source1, spec_source1);
+ tcg_temp_free(spec_source1);
+ tcg_temp_free(spec_source2);
+ tcg_temp_free(cond1);
+ tcg_temp_free(cond2);
+ }
+ break;
+ case OPC_RISC_DIVU:
+ {
+ TCGv spec_source1, spec_source2;
+ TCGLabel* handle_zero = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ spec_source1 = tcg_temp_local_new();
+ spec_source2 = tcg_temp_local_new();
+
+ gen_get_gpr(spec_source1, rs1);
+ gen_get_gpr(spec_source2, rs2);
+ tcg_gen_brcondi_tl(TCG_COND_EQ, spec_source2, 0x0, handle_zero);
+
+ // normal case
+ tcg_gen_divu_tl(spec_source1, spec_source1, spec_source2);
+ tcg_gen_br(done);
+ // special zero case
+ gen_set_label(handle_zero);
+ tcg_gen_movi_tl(spec_source1, -1);
+ tcg_gen_br(done);
+ // done
+ gen_set_label(done);
+ tcg_gen_mov_tl(source1, spec_source1);
+ tcg_temp_free(spec_source1);
+ tcg_temp_free(spec_source2);
+ }
+ break;
+ case OPC_RISC_REM:
+ {
+ TCGv spec_source1, spec_source2;
+ TCGv cond1, cond2;
+ TCGLabel* handle_zero = gen_new_label();
+ TCGLabel* handle_overflow = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ spec_source1 = tcg_temp_local_new();
+ spec_source2 = tcg_temp_local_new();
+ cond1 = tcg_temp_local_new();
+ cond2 = tcg_temp_local_new();
+
+ gen_get_gpr(spec_source1, rs1);
+ gen_get_gpr(spec_source2, rs2);
+ tcg_gen_brcondi_tl(TCG_COND_EQ, spec_source2, 0x0, handle_zero);
+
+ // now, use temp reg to check if both overflow conditions satisfied
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, spec_source2, 0xFFFFFFFFFFFFFFFF); // divisor = -1
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, spec_source1, 0x8000000000000000);
+ tcg_gen_and_tl(cond1, cond1, cond2);
+
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cond1, 1, handle_overflow);
+ // normal case
+ tcg_gen_rem_tl(spec_source1, spec_source1, spec_source2);
+ tcg_gen_br(done);
+ // special zero case
+ gen_set_label(handle_zero);
+ tcg_gen_mov_tl(spec_source1, spec_source1); // even though it's a nop, just for clarity
+ tcg_gen_br(done);
+ // special overflow case
+ gen_set_label(handle_overflow);
+ tcg_gen_movi_tl(spec_source1, 0);
+ // done
+ gen_set_label(done);
+ tcg_gen_mov_tl(source1, spec_source1);
+ tcg_temp_free(spec_source1);
+ tcg_temp_free(spec_source2);
+ tcg_temp_free(cond1);
+ tcg_temp_free(cond2);
+ }
+ break;
+ case OPC_RISC_REMU:
+ {
+ TCGv spec_source1, spec_source2;
+ TCGLabel* handle_zero = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ spec_source1 = tcg_temp_local_new();
+ spec_source2 = tcg_temp_local_new();
+
+ gen_get_gpr(spec_source1, rs1);
+ gen_get_gpr(spec_source2, rs2);
+ tcg_gen_brcondi_tl(TCG_COND_EQ, spec_source2, 0x0, handle_zero);
+
+ // normal case
+ tcg_gen_remu_tl(spec_source1, spec_source1, spec_source2);
+ tcg_gen_br(done);
+ // special zero case
+ gen_set_label(handle_zero);
+ tcg_gen_mov_tl(spec_source1, spec_source1); // even though it's a nop, just for clarity
+ tcg_gen_br(done);
+ // done
+ gen_set_label(done);
+ tcg_gen_mov_tl(source1, spec_source1);
+ tcg_temp_free(spec_source1);
+ tcg_temp_free(spec_source2);
+ }
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+
+ }
+
+ // set and free
+ gen_set_gpr(rd, source1);
+ tcg_temp_free(source1);
+ tcg_temp_free(source2);
+}
+
+/* lower 12 bits of imm are valid */
+inline static void gen_arith_imm(DisasContext *ctx, uint32_t opc,
+ int rd, int rs1, int16_t imm)
+{
+ TCGv source1;
+ source1 = tcg_temp_new();
+ gen_get_gpr(source1, rs1);
+ target_long uimm = (target_long)imm; /* sign ext 16->64 bits */
+
+ switch (opc) {
+ case OPC_RISC_ADDI:
+ tcg_gen_addi_tl(source1, source1, uimm);
+ break;
+ case OPC_RISC_SLTI:
+ tcg_gen_setcondi_tl(TCG_COND_LT, source1, source1, uimm);
+ break;
+ case OPC_RISC_SLTIU:
+ tcg_gen_setcondi_tl(TCG_COND_LTU, source1, source1, uimm);
+ break;
+ case OPC_RISC_XORI:
+ tcg_gen_xori_tl(source1, source1, uimm);
+ break;
+ case OPC_RISC_ORI:
+ tcg_gen_ori_tl(source1, source1, uimm);
+ break;
+ case OPC_RISC_ANDI:
+ tcg_gen_andi_tl(source1, source1, uimm);
+ break;
+ case OPC_RISC_SLLI: // TODO: add immediate upper bits check?
+ tcg_gen_shli_tl(source1, source1, uimm);
+ break;
+ case OPC_RISC_SHIFT_RIGHT_I: // SRLI, SRAI, TODO: upper bits check
+ // differentiate on IMM
+ if (uimm & 0x400) {
+ // SRAI
+ tcg_gen_sari_tl(source1, source1, uimm ^ 0x400);
+ } else {
+ tcg_gen_shri_tl(source1, source1, uimm);
+ }
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+
+ gen_set_gpr(rd, source1);
+ tcg_temp_free(source1);
+}
+
+/* lower 12 bits of imm are valid */
+inline static void gen_arith_imm_w(DisasContext *ctx, uint32_t opc,
+ int rd, int rs1, int16_t imm)
+{
+ TCGv source1;
+ source1 = tcg_temp_new();
+ gen_get_gpr(source1, rs1);
+ target_long uimm = (target_long)imm; /* sign ext 16->64 bits */
+
+ switch (opc) {
+ case OPC_RISC_ADDIW:
+ tcg_gen_addi_tl(source1, source1, uimm);
+ tcg_gen_ext32s_tl(source1, source1);
+ break;
+ case OPC_RISC_SLLIW: // TODO: add immediate upper bits check?
+ tcg_gen_shli_tl(source1, source1, uimm);
+ tcg_gen_ext32s_tl(source1, source1);
+ break;
+ case OPC_RISC_SHIFT_RIGHT_IW: // SRLIW, SRAIW, TODO: upper bits check
+ // differentiate on IMM
+ if (uimm & 0x400) {
+ // SRAI
+ // first, trick to get it to act like working on 32 bits:
+ tcg_gen_shli_tl(source1, source1, 32);
+ // now shift back to the right by shamt + 32 to get proper upper
+ // bits filling
+ tcg_gen_sari_tl(source1, source1, (uimm ^ 0x400) + 32);
+ tcg_gen_ext32s_tl(source1, source1);
+ } else {
+ // first, trick to get it to act like working on 32 bits (get rid
+ // of upper 32):
+ tcg_gen_shli_tl(source1, source1, 32);
+ // now shift back to the right by shamt + 32 to get proper upper
+ // bits filling
+ tcg_gen_shri_tl(source1, source1, uimm + 32);
+ tcg_gen_ext32s_tl(source1, source1);
+ }
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+ gen_set_gpr(rd, source1);
+ tcg_temp_free(source1);
+}
+
+inline static void gen_arith_w(DisasContext *ctx, uint32_t opc,
+ int rd, int rs1, int rs2)
+{
+ TCGv source1, source2;
+ source1 = tcg_temp_new();
+ source2 = tcg_temp_new();
+ gen_get_gpr(source1, rs1);
+ gen_get_gpr(source2, rs2);
+
+ switch (opc) {
+ case OPC_RISC_ADDW:
+ tcg_gen_add_tl(source1, source1, source2);
+ tcg_gen_ext32s_tl(source1, source1);
+ break;
+ case OPC_RISC_SUBW:
+ tcg_gen_sub_tl(source1, source1, source2);
+ tcg_gen_ext32s_tl(source1, source1);
+ break;
+ case OPC_RISC_SLLW:
+ tcg_gen_andi_tl(source2, source2, 0x1F);
+ tcg_gen_shl_tl(source1, source1, source2);
+ tcg_gen_ext32s_tl(source1, source1);
+ break;
+ case OPC_RISC_SRLW:
+ tcg_gen_andi_tl(source1, source1, 0x00000000FFFFFFFFLL); // clear upper 32
+ tcg_gen_andi_tl(source2, source2, 0x1F);
+ tcg_gen_shr_tl(source1, source1, source2); // do actual right shift
+ tcg_gen_ext32s_tl(source1, source1); // sign ext
+ break;
+ case OPC_RISC_SRAW:
+ // first, trick to get it to act like working on 32 bits (get rid of
+ // upper 32)
+ tcg_gen_shli_tl(source1, source1, 32); // clear upper 32
+ tcg_gen_sari_tl(source1, source1, 32); // smear the sign bit into upper 32
+ tcg_gen_andi_tl(source2, source2, 0x1F);
+ tcg_gen_sar_tl(source1, source1, source2); // do the actual right shift
+ tcg_gen_ext32s_tl(source1, source1); // sign ext
+ break;
+ case OPC_RISC_MULW:
+ tcg_gen_muls2_tl(source1, source2, source1, source2);
+ tcg_gen_ext32s_tl(source1, source1);
+ break;
+ case OPC_RISC_DIVW:
+ {
+ TCGv spec_source1, spec_source2;
+ TCGv cond1, cond2;
+ TCGLabel* handle_zero = gen_new_label();
+ TCGLabel* handle_overflow = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ spec_source1 = tcg_temp_local_new();
+ spec_source2 = tcg_temp_local_new();
+ cond1 = tcg_temp_local_new();
+ cond2 = tcg_temp_local_new();
+
+ gen_get_gpr(spec_source1, rs1);
+ gen_get_gpr(spec_source2, rs2);
+ tcg_gen_ext32s_tl(spec_source1, spec_source1);
+ tcg_gen_ext32s_tl(spec_source2, spec_source2);
+
+ tcg_gen_brcondi_tl(TCG_COND_EQ, spec_source2, 0x0, handle_zero);
+
+ // now, use temp reg to check if both overflow conditions satisfied
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, spec_source2, 0xFFFFFFFFFFFFFFFF); // divisor = -1
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, spec_source1, 0x8000000000000000);
+ tcg_gen_and_tl(cond1, cond1, cond2);
+
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cond1, 1, handle_overflow);
+ // normal case
+ tcg_gen_div_tl(spec_source1, spec_source1, spec_source2);
+ tcg_gen_br(done);
+ // special zero case
+ gen_set_label(handle_zero);
+ tcg_gen_movi_tl(spec_source1, -1);
+ tcg_gen_br(done);
+ // special overflow case
+ gen_set_label(handle_overflow);
+ tcg_gen_movi_tl(spec_source1, 0x8000000000000000);
+ // done
+ gen_set_label(done);
+ tcg_gen_mov_tl(source1, spec_source1);
+ tcg_temp_free(spec_source1);
+ tcg_temp_free(spec_source2);
+ tcg_temp_free(cond1);
+ tcg_temp_free(cond2);
+ tcg_gen_ext32s_tl(source1, source1);
+ }
+ break;
+ case OPC_RISC_DIVUW:
+ {
+ TCGv spec_source1, spec_source2;
+ TCGLabel* handle_zero = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ spec_source1 = tcg_temp_local_new();
+ spec_source2 = tcg_temp_local_new();
+
+ gen_get_gpr(spec_source1, rs1);
+ gen_get_gpr(spec_source2, rs2);
+ tcg_gen_ext32u_tl(spec_source1, spec_source1);
+ tcg_gen_ext32u_tl(spec_source2, spec_source2);
+
+ tcg_gen_brcondi_tl(TCG_COND_EQ, spec_source2, 0x0, handle_zero);
+
+ // normal case
+ tcg_gen_divu_tl(spec_source1, spec_source1, spec_source2);
+ tcg_gen_br(done);
+ // special zero case
+ gen_set_label(handle_zero);
+ tcg_gen_movi_tl(spec_source1, -1);
+ tcg_gen_br(done);
+ // done
+ gen_set_label(done);
+ tcg_gen_mov_tl(source1, spec_source1);
+ tcg_temp_free(spec_source1);
+ tcg_temp_free(spec_source2);
+ tcg_gen_ext32s_tl(source1, source1);
+ }
+ break;
+ case OPC_RISC_REMW:
+ {
+ TCGv spec_source1, spec_source2;
+ TCGv cond1, cond2;
+ TCGLabel* handle_zero = gen_new_label();
+ TCGLabel* handle_overflow = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ spec_source1 = tcg_temp_local_new();
+ spec_source2 = tcg_temp_local_new();
+ cond1 = tcg_temp_local_new();
+ cond2 = tcg_temp_local_new();
+
+ gen_get_gpr(spec_source1, rs1);
+ gen_get_gpr(spec_source2, rs2);
+ tcg_gen_ext32s_tl(spec_source1, spec_source1);
+ tcg_gen_ext32s_tl(spec_source2, spec_source2);
+
+ tcg_gen_brcondi_tl(TCG_COND_EQ, spec_source2, 0x0, handle_zero);
+
+ // now, use temp reg to check if both overflow conditions satisfied
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond2, spec_source2, 0xFFFFFFFFFFFFFFFF); // divisor = -1
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cond1, spec_source1, 0x8000000000000000);
+ tcg_gen_and_tl(cond1, cond1, cond2);
+
+ tcg_gen_brcondi_tl(TCG_COND_EQ, cond1, 1, handle_overflow);
+ // normal case
+ tcg_gen_rem_tl(spec_source1, spec_source1, spec_source2);
+ tcg_gen_br(done);
+ // special zero case
+ gen_set_label(handle_zero);
+ tcg_gen_mov_tl(spec_source1, spec_source1); // even though it's a nop, just for clarity
+ tcg_gen_br(done);
+ // special overflow case
+ gen_set_label(handle_overflow);
+ tcg_gen_movi_tl(spec_source1, 0);
+ // done
+ gen_set_label(done);
+ tcg_gen_mov_tl(source1, spec_source1);
+ tcg_temp_free(spec_source1);
+ tcg_temp_free(spec_source2);
+ tcg_temp_free(cond1);
+ tcg_temp_free(cond2);
+ tcg_gen_ext32s_tl(source1, source1);
+ }
+ break;
+ case OPC_RISC_REMUW:
+ {
+ TCGv spec_source1, spec_source2;
+ TCGLabel* handle_zero = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ spec_source1 = tcg_temp_local_new();
+ spec_source2 = tcg_temp_local_new();
+
+ gen_get_gpr(spec_source1, rs1);
+ gen_get_gpr(spec_source2, rs2);
+ tcg_gen_ext32u_tl(spec_source1, spec_source1);
+ tcg_gen_ext32u_tl(spec_source2, spec_source2);
+
+ tcg_gen_brcondi_tl(TCG_COND_EQ, spec_source2, 0x0, handle_zero);
+ // normal case
+ tcg_gen_remu_tl(spec_source1, spec_source1, spec_source2);
+ tcg_gen_br(done);
+ // special zero case
+ gen_set_label(handle_zero);
+ tcg_gen_mov_tl(spec_source1, spec_source1); // even though it's a nop, just for clarity
+ tcg_gen_br(done);
+ // done
+ gen_set_label(done);
+ tcg_gen_mov_tl(source1, spec_source1);
+ tcg_temp_free(spec_source1);
+ tcg_temp_free(spec_source2);
+ tcg_gen_ext32s_tl(source1, source1);
+ }
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+ gen_set_gpr(rd, source1);
+ tcg_temp_free(source1);
+ tcg_temp_free(source2);
+}
+
+inline static void gen_branch(DisasContext *ctx, uint32_t opc,
+ int rs1, int rs2, int16_t bimm) {
+
+ // TODO: misaligned insn (see jalr)
+ TCGLabel* l = gen_new_label();
+ TCGv source1, source2;
+ source1 = tcg_temp_new();
+ source2 = tcg_temp_new();
+ gen_get_gpr(source1, rs1);
+ gen_get_gpr(source2, rs2);
+ target_ulong ubimm = (target_long)bimm; /* sign ext 16->64 bits */
+
+ switch (opc) {
+ case OPC_RISC_BEQ:
+ tcg_gen_brcond_tl(TCG_COND_EQ, source1, source2, l);
+ break;
+ case OPC_RISC_BNE:
+ tcg_gen_brcond_tl(TCG_COND_NE, source1, source2, l);
+ break;
+ case OPC_RISC_BLT:
+ tcg_gen_brcond_tl(TCG_COND_LT, source1, source2, l);
+ break;
+ case OPC_RISC_BGE:
+ tcg_gen_brcond_tl(TCG_COND_GE, source1, source2, l);
+ break;
+ case OPC_RISC_BLTU:
+ tcg_gen_brcond_tl(TCG_COND_LTU, source1, source2, l);
+ break;
+ case OPC_RISC_BGEU:
+ tcg_gen_brcond_tl(TCG_COND_GEU, source1, source2, l);
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+
+#ifdef DISABLE_CHAINING_BRANCH
+ tcg_gen_movi_tl(cpu_PC, ctx->pc + 4);
+ tcg_gen_exit_tb(0);
+#else
+ gen_goto_tb(ctx, 1, ctx->pc + 4); // must use this for safety
+#endif
+ gen_set_label(l); // branch taken
+#ifdef DISABLE_CHAINING_BRANCH
+ tcg_gen_movi_tl(cpu_PC, ctx->pc + ubimm);
+ tcg_gen_exit_tb(0);
+#else
+ gen_goto_tb(ctx, 0, ctx->pc + ubimm); // must use this for safety
+#endif
+ tcg_temp_free(source1);
+ tcg_temp_free(source2);
+ ctx->bstate = BS_BRANCH;
+}
+
+inline static void gen_load(DisasContext *ctx, uint32_t opc,
+ int rd, int rs1, int16_t imm)
+{
+
+ target_long uimm = (target_long)imm; /* sign ext 16->64 bits */
+
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+
+ gen_get_gpr(t0, rs1);
+ tcg_gen_addi_tl(t0, t0, uimm); //
+
+ switch (opc) {
+
+ case OPC_RISC_LB:
+ tcg_gen_qemu_ld8s(t1, t0, ctx->mem_idx);
+ break;
+ case OPC_RISC_LH:
+ tcg_gen_qemu_ld16s(t1, t0, ctx->mem_idx);
+ break;
+ case OPC_RISC_LW:
+ tcg_gen_qemu_ld32s(t1, t0, ctx->mem_idx);
+ break;
+ case OPC_RISC_LD:
+ tcg_gen_qemu_ld64(t1, t0, ctx->mem_idx);
+ break;
+ case OPC_RISC_LBU:
+ tcg_gen_qemu_ld8u(t1, t0, ctx->mem_idx);
+ break;
+ case OPC_RISC_LHU:
+ tcg_gen_qemu_ld16u(t1, t0, ctx->mem_idx);
+ break;
+ case OPC_RISC_LWU:
+ tcg_gen_qemu_ld32u(t1, t0, ctx->mem_idx);
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+
+ }
+
+ gen_set_gpr(rd, t1);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+}
+
+
+inline static void gen_store(DisasContext *ctx, uint32_t opc,
+ int rs1, int rs2, int16_t imm)
+{
+ target_long uimm = (target_long)imm; /* sign ext 16->64 bits */
+
+ TCGv t0 = tcg_temp_new();
+ TCGv dat = tcg_temp_new();
+ gen_get_gpr(t0, rs1);
+ tcg_gen_addi_tl(t0, t0, uimm);
+ gen_get_gpr(dat, rs2);
+
+ switch (opc) {
+
+ case OPC_RISC_SB:
+ tcg_gen_qemu_st8(dat, t0, ctx->mem_idx);
+ break;
+ case OPC_RISC_SH:
+ tcg_gen_qemu_st16(dat, t0, ctx->mem_idx);
+ break;
+ case OPC_RISC_SW:
+ tcg_gen_qemu_st32(dat, t0, ctx->mem_idx);
+ break;
+ case OPC_RISC_SD:
+ tcg_gen_qemu_st64(dat, t0, ctx->mem_idx);
+ break;
+
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+
+ tcg_temp_free(t0);
+ tcg_temp_free(dat);
+}
+
+inline static void gen_jalr(DisasContext *ctx, uint32_t opc,
+ int rd, int rs1, int16_t imm)
+{
+ TCGLabel* misaligned = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ target_long uimm = (target_long)imm; /* sign ext 16->64 bits */
+ TCGv t0, t1, t2, t3;
+ t0 = tcg_temp_local_new();
+ t1 = tcg_temp_local_new();
+ t2 = tcg_temp_local_new(); // old_pc
+ t3 = tcg_temp_local_new();
+
+ switch (opc) {
+
+ case OPC_RISC_JALR: // CANNOT HAVE CHAINING WITH JALR
+ gen_get_gpr(t0, rs1);
+ tcg_gen_addi_tl(t0, t0, uimm);
+ tcg_gen_andi_tl(t0, t0, 0xFFFFFFFFFFFFFFFEll);
+
+ tcg_gen_andi_tl(t3, t0, 0x2);
+ tcg_gen_movi_tl(t2, ctx->pc);
+
+ tcg_gen_brcondi_tl(TCG_COND_NE, t3, 0x0, misaligned);
+ tcg_gen_mov_tl(cpu_PC, t0);
+ tcg_gen_addi_tl(t1, t2, 4);
+ gen_set_gpr(rd, t1);
+ tcg_gen_br(done);
+
+ gen_set_label(misaligned);
+ generate_exception_mbadaddr(ctx, NEW_RISCV_EXCP_INST_ADDR_MIS);
+
+ gen_set_label(done);
+ tcg_gen_exit_tb(0); // exception or not, NO CHAINING FOR JALR
+ ctx->bstate = BS_BRANCH;
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+
+ }
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ tcg_temp_free(t2);
+ tcg_temp_free(t3);
+
+}
+
+inline static void gen_atomic(DisasContext *ctx, uint32_t opc,
+ int rd, int rs1, int rs2)
+{
+ // TODO: handle aq, rl bits? - for now just get rid of them:
+ opc = MASK_OP_ATOMIC_NO_AQ_RL(opc);
+
+ TCGv source1, source2, dat;
+
+ source1 = tcg_temp_local_new();
+ source2 = tcg_temp_local_new();
+ dat = tcg_temp_new();
+
+ gen_get_gpr(source1, rs1);
+ gen_get_gpr(source2, rs2);
+
+ switch (opc) {
+ // all currently implemented as non-atomics
+ case OPC_RISC_LR_W:
+ // put addr in load_reservation
+ tcg_gen_mov_tl(load_reservation, source1);
+ tcg_gen_qemu_ld32s(source1, source1, ctx->mem_idx);
+ break;
+ case OPC_RISC_SC_W: {
+ TCGLabel* fail = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ tcg_gen_brcond_tl(TCG_COND_NE, load_reservation, source1, fail);
+ tcg_gen_qemu_st32(source2, source1, ctx->mem_idx);
+ tcg_gen_movi_tl(source1, 0); //success
+ tcg_gen_br(done);
+ gen_set_label(fail);
+ tcg_gen_movi_tl(source1, 1); //fail
+ gen_set_label(done);
+ }
+ break;
+ case OPC_RISC_AMOSWAP_W:
+ tcg_gen_qemu_ld32s(dat, source1, ctx->mem_idx);
+ tcg_gen_qemu_st32(source2, source1, ctx->mem_idx);
+ tcg_gen_mov_tl(source1, dat);
+ break;
+ case OPC_RISC_AMOADD_W:
+ tcg_gen_qemu_ld32s(dat, source1, ctx->mem_idx);
+ tcg_gen_add_tl(source2, dat, source2);
+ tcg_gen_qemu_st32(source2, source1, ctx->mem_idx);
+ tcg_gen_mov_tl(source1, dat);
+ break;
+ case OPC_RISC_AMOXOR_W:
+ tcg_gen_qemu_ld32s(dat, source1, ctx->mem_idx);
+ tcg_gen_xor_tl(source2, dat, source2);
+ tcg_gen_qemu_st32(source2, source1, ctx->mem_idx);
+ tcg_gen_mov_tl(source1, dat);
+ break;
+ case OPC_RISC_AMOAND_W:
+ tcg_gen_qemu_ld32s(dat, source1, ctx->mem_idx);
+ tcg_gen_and_tl(source2, dat, source2);
+ tcg_gen_qemu_st32(source2, source1, ctx->mem_idx);
+ tcg_gen_mov_tl(source1, dat);
+ break;
+ case OPC_RISC_AMOOR_W:
+ tcg_gen_qemu_ld32s(dat, source1, ctx->mem_idx);
+ tcg_gen_or_tl(source2, dat, source2);
+ tcg_gen_qemu_st32(source2, source1, ctx->mem_idx);
+ tcg_gen_mov_tl(source1, dat);
+ break;
+ case OPC_RISC_AMOMIN_W:
+ {
+ TCGv source1_l, source2_l, dat_l;
+ source1_l = tcg_temp_local_new();
+ source2_l = tcg_temp_local_new();
+ dat_l = tcg_temp_local_new();
+ TCGLabel* j = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ tcg_gen_mov_tl(source1_l, source1);
+ tcg_gen_ext32s_tl(source2_l, source2);
+ tcg_gen_qemu_ld32s(dat_l, source1_l, ctx->mem_idx);
+ tcg_gen_brcond_tl(TCG_COND_LT, dat_l, source2_l, j);
+ tcg_gen_qemu_st32(source2_l, source1_l, ctx->mem_idx);
+ tcg_gen_br(done);
+ // here we store the thing on the left
+ gen_set_label(j);
+ tcg_gen_qemu_st32(dat_l, source1_l, ctx->mem_idx);
+ //done
+ gen_set_label(done);
+ tcg_gen_mov_tl(source1, dat_l);
+ tcg_temp_free(source1_l);
+ tcg_temp_free(source2_l);
+ tcg_temp_free(dat_l);
+ }
+ break;
+ case OPC_RISC_AMOMAX_W:
+ {
+ TCGv source1_l, source2_l, dat_l;
+ source1_l = tcg_temp_local_new();
+ source2_l = tcg_temp_local_new();
+ dat_l = tcg_temp_local_new();
+ TCGLabel* j = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ tcg_gen_mov_tl(source1_l, source1);
+ tcg_gen_ext32s_tl(source2_l, source2);
+ tcg_gen_qemu_ld32s(dat_l, source1_l, ctx->mem_idx);
+ tcg_gen_brcond_tl(TCG_COND_GT, dat_l, source2_l, j);
+ tcg_gen_qemu_st32(source2_l, source1_l, ctx->mem_idx);
+ tcg_gen_br(done);
+ // here we store the thing on the left
+ gen_set_label(j);
+ tcg_gen_qemu_st32(dat_l, source1_l, ctx->mem_idx);
+ //done
+ gen_set_label(done);
+ tcg_gen_mov_tl(source1, dat_l);
+ tcg_temp_free(source1_l);
+ tcg_temp_free(source2_l);
+ tcg_temp_free(dat_l);
+ }
+ break;
+ case OPC_RISC_AMOMINU_W:
+ {
+ TCGv source1_l, source2_l, dat_l;
+ source1_l = tcg_temp_local_new();
+ source2_l = tcg_temp_local_new();
+ dat_l = tcg_temp_local_new();
+ TCGLabel* j = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ tcg_gen_mov_tl(source1_l, source1);
+ tcg_gen_ext32u_tl(source2_l, source2);
+ tcg_gen_qemu_ld32u(dat_l, source1_l, ctx->mem_idx);
+ tcg_gen_brcond_tl(TCG_COND_LTU, dat_l, source2_l, j);
+ tcg_gen_qemu_st32(source2_l, source1_l, ctx->mem_idx);
+ tcg_gen_br(done);
+ // here we store the thing on the left
+ gen_set_label(j);
+ tcg_gen_qemu_st32(dat_l, source1_l, ctx->mem_idx);
+ //done
+ gen_set_label(done);
+ tcg_gen_ext32s_tl(source1, dat_l);
+ tcg_temp_free(source1_l);
+ tcg_temp_free(source2_l);
+ tcg_temp_free(dat_l);
+ }
+ break;
+ case OPC_RISC_AMOMAXU_W:
+ {
+ TCGv source1_l, source2_l, dat_l;
+ source1_l = tcg_temp_local_new();
+ source2_l = tcg_temp_local_new();
+ dat_l = tcg_temp_local_new();
+ TCGLabel* j = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ tcg_gen_mov_tl(source1_l, source1);
+ tcg_gen_ext32u_tl(source2_l, source2);
+ tcg_gen_qemu_ld32u(dat_l, source1_l, ctx->mem_idx);
+ tcg_gen_brcond_tl(TCG_COND_GTU, dat_l, source2_l, j);
+ tcg_gen_qemu_st32(source2_l, source1_l, ctx->mem_idx);
+ tcg_gen_br(done);
+ // here we store the thing on the left
+ gen_set_label(j);
+ tcg_gen_qemu_st32(dat_l, source1_l, ctx->mem_idx);
+ //done
+ gen_set_label(done);
+ tcg_gen_ext32s_tl(source1, dat_l);
+ tcg_temp_free(source1_l);
+ tcg_temp_free(source2_l);
+ tcg_temp_free(dat_l);
+ }
+ break;
+ case OPC_RISC_LR_D:
+ // put addr in load_reservation
+ tcg_gen_mov_tl(load_reservation, source1);
+ tcg_gen_qemu_ld64(source1, source1, ctx->mem_idx);
+ break;
+ case OPC_RISC_SC_D: {
+ TCGLabel* fail = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ tcg_gen_brcond_tl(TCG_COND_NE, load_reservation, source1, fail);
+ tcg_gen_qemu_st64(source2, source1, ctx->mem_idx);
+ tcg_gen_movi_tl(source1, 0); //success
+ tcg_gen_br(done);
+ gen_set_label(fail);
+ tcg_gen_movi_tl(source1, 1); //fail
+ gen_set_label(done);
+ break;
+ }
+ case OPC_RISC_AMOSWAP_D:
+ tcg_gen_qemu_ld64(dat, source1, ctx->mem_idx);
+ tcg_gen_qemu_st64(source2, source1, ctx->mem_idx);
+ tcg_gen_mov_tl(source1, dat);
+ break;
+ case OPC_RISC_AMOADD_D:
+ tcg_gen_qemu_ld64(dat, source1, ctx->mem_idx);
+ tcg_gen_add_tl(source2, dat, source2);
+ tcg_gen_qemu_st64(source2, source1, ctx->mem_idx);
+ tcg_gen_mov_tl(source1, dat);
+ break;
+ case OPC_RISC_AMOXOR_D:
+ tcg_gen_qemu_ld64(dat, source1, ctx->mem_idx);
+ tcg_gen_xor_tl(source2, dat, source2);
+ tcg_gen_qemu_st64(source2, source1, ctx->mem_idx);
+ tcg_gen_mov_tl(source1, dat);
+ break;
+ case OPC_RISC_AMOAND_D:
+ tcg_gen_qemu_ld64(dat, source1, ctx->mem_idx);
+ tcg_gen_and_tl(source2, dat, source2);
+ tcg_gen_qemu_st64(source2, source1, ctx->mem_idx);
+ tcg_gen_mov_tl(source1, dat);
+ break;
+ case OPC_RISC_AMOOR_D:
+ tcg_gen_qemu_ld64(dat, source1, ctx->mem_idx);
+ tcg_gen_or_tl(source2, dat, source2);
+ tcg_gen_qemu_st64(source2, source1, ctx->mem_idx);
+ tcg_gen_mov_tl(source1, dat);
+ break;
+ case OPC_RISC_AMOMIN_D:
+ {
+ TCGv source1_l, source2_l, dat_l;
+ source1_l = tcg_temp_local_new();
+ source2_l = tcg_temp_local_new();
+ dat_l = tcg_temp_local_new();
+ TCGLabel* j = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ tcg_gen_mov_tl(source1_l, source1);
+ tcg_gen_mov_tl(source2_l, source2);
+ tcg_gen_qemu_ld64(dat_l, source1_l, ctx->mem_idx);
+ tcg_gen_brcond_tl(TCG_COND_LT, dat_l, source2_l, j);
+ tcg_gen_qemu_st64(source2_l, source1_l, ctx->mem_idx);
+ tcg_gen_br(done);
+ // here we store the thing on the left
+ gen_set_label(j);
+ tcg_gen_qemu_st64(dat_l, source1_l, ctx->mem_idx);
+ //done
+ gen_set_label(done);
+ tcg_gen_mov_tl(source1, dat_l);
+ tcg_temp_free(source1_l);
+ tcg_temp_free(source2_l);
+ tcg_temp_free(dat_l);
+ }
+ break;
+ case OPC_RISC_AMOMAX_D:
+ {
+ TCGv source1_l, source2_l, dat_l;
+ source1_l = tcg_temp_local_new();
+ source2_l = tcg_temp_local_new();
+ dat_l = tcg_temp_local_new();
+ TCGLabel* j = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ tcg_gen_mov_tl(source1_l, source1);
+ tcg_gen_mov_tl(source2_l, source2);
+ tcg_gen_qemu_ld64(dat_l, source1_l, ctx->mem_idx);
+ tcg_gen_brcond_tl(TCG_COND_GT, dat_l, source2_l, j);
+ tcg_gen_qemu_st64(source2_l, source1_l, ctx->mem_idx);
+ tcg_gen_br(done);
+ // here we store the thing on the left
+ gen_set_label(j);
+ tcg_gen_qemu_st64(dat_l, source1_l, ctx->mem_idx);
+ //done
+ gen_set_label(done);
+ tcg_gen_mov_tl(source1, dat_l);
+ tcg_temp_free(source1_l);
+ tcg_temp_free(source2_l);
+ tcg_temp_free(dat_l);
+ }
+ break;
+ case OPC_RISC_AMOMINU_D:
+ {
+ TCGv source1_l, source2_l, dat_l;
+ source1_l = tcg_temp_local_new();
+ source2_l = tcg_temp_local_new();
+ dat_l = tcg_temp_local_new();
+ TCGLabel* j = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ tcg_gen_mov_tl(source1_l, source1);
+ tcg_gen_mov_tl(source2_l, source2);
+ tcg_gen_qemu_ld64(dat_l, source1_l, ctx->mem_idx);
+ tcg_gen_brcond_tl(TCG_COND_LTU, dat_l, source2_l, j);
+ tcg_gen_qemu_st64(source2_l, source1_l, ctx->mem_idx);
+ tcg_gen_br(done);
+ // here we store the thing on the left
+ gen_set_label(j);
+ tcg_gen_qemu_st64(dat_l, source1_l, ctx->mem_idx);
+ //done
+ gen_set_label(done);
+ tcg_gen_mov_tl(source1, dat_l);
+ tcg_temp_free(source1_l);
+ tcg_temp_free(source2_l);
+ tcg_temp_free(dat_l);
+ }
+ break;
+ case OPC_RISC_AMOMAXU_D:
+ {
+ TCGv source1_l, source2_l, dat_l;
+ source1_l = tcg_temp_local_new();
+ source2_l = tcg_temp_local_new();
+ dat_l = tcg_temp_local_new();
+ TCGLabel* j = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ tcg_gen_mov_tl(source1_l, source1);
+ tcg_gen_mov_tl(source2_l, source2);
+ tcg_gen_qemu_ld64(dat_l, source1_l, ctx->mem_idx);
+ tcg_gen_brcond_tl(TCG_COND_GTU, dat_l, source2_l, j);
+ tcg_gen_qemu_st64(source2_l, source1_l, ctx->mem_idx);
+ tcg_gen_br(done);
+ // here we store the thing on the left
+ gen_set_label(j);
+ tcg_gen_qemu_st64(dat_l, source1_l, ctx->mem_idx);
+ //done
+ gen_set_label(done);
+ tcg_gen_mov_tl(source1, dat_l);
+ tcg_temp_free(source1_l);
+ tcg_temp_free(source2_l);
+ tcg_temp_free(dat_l);
+ }
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+
+ }
+
+ // set and free
+ gen_set_gpr(rd, source1);
+ tcg_temp_free(source1);
+ tcg_temp_free(source2);
+ tcg_temp_free(dat);
+}
+
+
+inline static void gen_csr_htif(DisasContext *ctx, uint32_t opc, uint64_t addr, int rd, int rs1) {
+ TCGv source1, csr_store, htif_addr;
+ source1 = tcg_temp_new();
+ csr_store = tcg_temp_new();
+ htif_addr = tcg_temp_new();
+ gen_get_gpr(source1, rs1); // load rs1 val
+ tcg_gen_movi_tl(htif_addr, addr);
+ tcg_gen_qemu_ld64(csr_store, htif_addr, ctx->mem_idx); // get htif "reg" val
+
+ switch (opc) {
+
+ case OPC_RISC_CSRRW:
+ break;
+ case OPC_RISC_CSRRS:
+ tcg_gen_or_tl(source1, csr_store, source1);
+ break;
+ case OPC_RISC_CSRRC:
+ tcg_gen_not_tl(source1, source1);
+ tcg_gen_and_tl(source1, csr_store, source1);
+ break;
+ case OPC_RISC_CSRRWI:
+ tcg_gen_movi_tl(source1, rs1);
+ break;
+ case OPC_RISC_CSRRSI:
+ tcg_gen_ori_tl(source1, csr_store, rs1);
+ break;
+ case OPC_RISC_CSRRCI:
+ tcg_gen_andi_tl(source1, csr_store, ~((uint64_t)rs1));
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+
+ }
+ tcg_gen_qemu_st64(source1, htif_addr, ctx->mem_idx);
+ gen_set_gpr(rd, csr_store);
+ tcg_temp_free(source1);
+ tcg_temp_free(csr_store);
+ tcg_temp_free(htif_addr);
+}
+
+inline static void gen_system(DisasContext *ctx, uint32_t opc,
+ int rd, int rs1, int csr)
+{
+ // get index into csr array
+ int backup_csr = csr;
+
+ if (csr == NEW_CSR_MTOHOST) {
+ gen_csr_htif(ctx, opc, 0xFFFFFFFFF0000000L, rd, rs1);
+ return;
+ } else if (csr == NEW_CSR_MFROMHOST) {
+ gen_csr_htif(ctx, opc, 0xFFFFFFFFF0000008L, rd, rs1);
+ return;
+ }
+
+ TCGv source1, csr_store, dest;
+ source1 = tcg_temp_new();
+ csr_store = tcg_temp_new();
+ dest = tcg_temp_new();
+ gen_get_gpr(source1, rs1);
+ tcg_gen_movi_tl(csr_store, csr); // copy into temp reg to feed to helper
+
+ switch (opc) {
+
+ case OPC_RISC_ECALL:
+ switch (backup_csr) {
+ case 0x0: // ECALL
+ // always generates U-level ECALL, fixed in do_interrupt handler
+ generate_exception(ctx, NEW_RISCV_EXCP_U_ECALL);
+ tcg_gen_exit_tb(0); // no chaining
+ ctx->bstate = BS_BRANCH;
+ break;
+ case 0x1: // EBREAK
+ generate_exception(ctx, NEW_RISCV_EXCP_BREAKPOINT);
+ tcg_gen_exit_tb(0); // no chaining
+ ctx->bstate = BS_BRANCH;
+ break;
+ case 0x100: // ERET
+ // temporarily added second cpu_PC for debug
+ tcg_gen_movi_tl(cpu_PC, ctx->pc);
+ gen_helper_sret(cpu_PC, cpu_env, cpu_PC);
+ tcg_gen_exit_tb(0); // no chaining
+ ctx->bstate = BS_BRANCH;
+ break;
+ case 0x305: // MRTS
+ tcg_gen_movi_tl(cpu_PC, ctx->pc); // mrts helper may cause misaligned exception
+ gen_helper_mrts(cpu_PC, cpu_env, cpu_PC);
+ tcg_gen_exit_tb(0); // no chaining
+ ctx->bstate = BS_BRANCH;
+ break;
+ case 0x306: // MRTH
+ printf("SYSTEM INST NOT YET IMPLEMENTED 0x%x\n", backup_csr);
+ exit(1);
+ break;
+ case 0x205: // HRTS
+ printf("SYSTEM INST NOT YET IMPLEMENTED 0x%x\n", backup_csr);
+ exit(1);
+ break;
+ case 0x102: // WFI
+ // nop for now, as in spike
+ break;
+ case 0x101: // SFENCE.VM
+ gen_helper_tlb_flush(cpu_env);
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+ break;
+ case OPC_RISC_CSRRW:
+ tcg_gen_movi_tl(cpu_PC, ctx->pc);
+ gen_helper_csrrw(dest, cpu_env, source1, csr_store, cpu_PC);
+ gen_set_gpr(rd, dest);
+ // end tb since we may be changing priv modes
+ tcg_gen_movi_tl(cpu_PC, ctx->pc + 4);
+ tcg_gen_exit_tb(0); // no chaining
+ ctx->bstate = BS_BRANCH;
+ break;
+ case OPC_RISC_CSRRS:
+ tcg_gen_movi_tl(cpu_PC, ctx->pc);
+ gen_helper_csrrs(dest, cpu_env, source1, csr_store, cpu_PC);
+ gen_set_gpr(rd, dest);
+ // end tb since we may be changing priv modes
+ tcg_gen_movi_tl(cpu_PC, ctx->pc + 4);
+ tcg_gen_exit_tb(0); // no chaining
+ ctx->bstate = BS_BRANCH;
+ break;
+ case OPC_RISC_CSRRC:
+ tcg_gen_movi_tl(cpu_PC, ctx->pc);
+ gen_helper_csrrc(dest, cpu_env, source1, csr_store, cpu_PC);
+ gen_set_gpr(rd, dest);
+ // end tb since we may be changing priv modes
+ tcg_gen_movi_tl(cpu_PC, ctx->pc + 4);
+ tcg_gen_exit_tb(0); // no chaining
+ ctx->bstate = BS_BRANCH;
+ break;
+ case OPC_RISC_CSRRWI:
+ {
+ tcg_gen_movi_tl(cpu_PC, ctx->pc);
+ TCGv imm_rs1 = tcg_temp_new();
+ tcg_gen_movi_tl(imm_rs1, rs1);
+ gen_helper_csrrw(dest, cpu_env, imm_rs1, csr_store, cpu_PC);
+ gen_set_gpr(rd, dest);
+ tcg_temp_free(imm_rs1);
+ // end tb since we may be changing priv modes
+ tcg_gen_movi_tl(cpu_PC, ctx->pc + 4);
+ tcg_gen_exit_tb(0); // no chaining
+ ctx->bstate = BS_BRANCH;
+ }
+ break;
+ case OPC_RISC_CSRRSI:
+ {
+ tcg_gen_movi_tl(cpu_PC, ctx->pc);
+ TCGv imm_rs1 = tcg_temp_new();
+ tcg_gen_movi_tl(imm_rs1, rs1);
+ gen_helper_csrrsi(dest, cpu_env, imm_rs1, csr_store, cpu_PC);
+ gen_set_gpr(rd, dest);
+ tcg_temp_free(imm_rs1);
+ // end tb since we may be changing priv modes
+ tcg_gen_movi_tl(cpu_PC, ctx->pc + 4);
+ tcg_gen_exit_tb(0); // no chaining
+ ctx->bstate = BS_BRANCH;
+ }
+ break;
+ case OPC_RISC_CSRRCI:
+ {
+ tcg_gen_movi_tl(cpu_PC, ctx->pc);
+ TCGv imm_rs1 = tcg_temp_new();
+ tcg_gen_movi_tl(imm_rs1, rs1);
+ gen_helper_csrrc(dest, cpu_env, imm_rs1, csr_store, cpu_PC);
+ gen_set_gpr(rd, dest);
+ tcg_temp_free(imm_rs1);
+ // end tb since we may be changing priv modes
+ tcg_gen_movi_tl(cpu_PC, ctx->pc + 4);
+ tcg_gen_exit_tb(0); // no chaining
+ ctx->bstate = BS_BRANCH;
+ }
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+
+ }
+ tcg_temp_free(source1);
+ tcg_temp_free(dest);
+ tcg_temp_free(csr_store);
+}
+
+
+inline static void gen_fp_load(DisasContext *ctx, uint32_t opc,
+ int rd, int rs1, int16_t imm)
+{
+ target_long uimm = (target_long)imm; /* sign ext 16->64 bits */
+
+ TCGv t0 = tcg_temp_new();
+ gen_get_gpr(t0, rs1);
+ tcg_gen_addi_tl(t0, t0, uimm);
+
+ switch (opc) {
+
+ case OPC_RISC_FLW:
+ tcg_gen_qemu_ld32u(t0, t0, ctx->mem_idx);
+ break;
+ case OPC_RISC_FLD:
+ tcg_gen_qemu_ld64(t0, t0, ctx->mem_idx);
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+
+ }
+ tcg_gen_mov_tl(cpu_fpr[rd], t0); // probably can just get rid of this and
+ // store directly to cpu_fpr[rd]
+ tcg_temp_free(t0);
+}
+
+inline static void gen_fp_store(DisasContext *ctx, uint32_t opc,
+ int rs1, int rs2, int16_t imm)
+{
+ target_long uimm = (target_long)imm; /* sign ext 16->64 bits */
+
+ TCGv t0 = tcg_temp_new();
+ TCGv dat = tcg_temp_new();
+ gen_get_gpr(t0, rs1);
+ tcg_gen_addi_tl(t0, t0, uimm);
+ tcg_gen_mov_tl(dat, cpu_fpr[rs2]);
+
+ switch (opc) {
+
+ case OPC_RISC_FSW:
+ tcg_gen_qemu_st32(dat, t0, ctx->mem_idx);
+ break;
+ case OPC_RISC_FSD:
+ tcg_gen_qemu_st64(dat, t0, ctx->mem_idx);
+ break;
+
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+
+ tcg_temp_free(t0);
+ tcg_temp_free(dat);
+}
+
+inline static void gen_fp_fmadd(DisasContext *ctx, uint32_t opc,
+ int rd, int rs1, int rs2, int rs3, int rm)
+{
+ TCGv rm_reg = tcg_temp_new();
+ tcg_gen_movi_tl(rm_reg, rm);
+
+ switch (opc) {
+
+ case OPC_RISC_FMADD_S:
+ gen_helper_fmadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], cpu_fpr[rs3], rm_reg);
+ break;
+ case OPC_RISC_FMADD_D:
+ gen_helper_fmadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], cpu_fpr[rs3], rm_reg);
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+ tcg_temp_free(rm_reg);
+
+}
+
+inline static void gen_fp_fmsub(DisasContext *ctx, uint32_t opc,
+ int rd, int rs1, int rs2, int rs3, int rm)
+{
+ TCGv rm_reg = tcg_temp_new();
+ tcg_gen_movi_tl(rm_reg, rm);
+
+ switch (opc) {
+
+ case OPC_RISC_FMSUB_S:
+ gen_helper_fmsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], cpu_fpr[rs3], rm_reg);
+ break;
+ case OPC_RISC_FMSUB_D:
+ gen_helper_fmsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], cpu_fpr[rs3], rm_reg);
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+ tcg_temp_free(rm_reg);
+}
+
+inline static void gen_fp_fnmsub(DisasContext *ctx, uint32_t opc,
+ int rd, int rs1, int rs2, int rs3, int rm)
+{
+ TCGv rm_reg = tcg_temp_new();
+ tcg_gen_movi_tl(rm_reg, rm);
+
+ switch (opc) {
+
+ case OPC_RISC_FNMSUB_S:
+ gen_helper_fnmsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], cpu_fpr[rs3], rm_reg);
+ break;
+ case OPC_RISC_FNMSUB_D:
+ gen_helper_fnmsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], cpu_fpr[rs3], rm_reg);
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+ tcg_temp_free(rm_reg);
+}
+
+inline static void gen_fp_fnmadd(DisasContext *ctx, uint32_t opc,
+ int rd, int rs1, int rs2, int rs3, int rm)
+{
+ TCGv rm_reg = tcg_temp_new();
+ tcg_gen_movi_tl(rm_reg, rm);
+
+ switch (opc) {
+
+ case OPC_RISC_FNMADD_S:
+ gen_helper_fnmadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], cpu_fpr[rs3], rm_reg);
+ break;
+ case OPC_RISC_FNMADD_D:
+ gen_helper_fnmadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], cpu_fpr[rs3], rm_reg);
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+ tcg_temp_free(rm_reg);
+}
+
+inline static void gen_fp_arith(DisasContext *ctx, uint32_t opc,
+ int rd, int rs1, int rs2, int rm)
+{
+ TCGv rm_reg = tcg_temp_new();
+ TCGv write_int_rd = tcg_temp_new();
+ tcg_gen_movi_tl(rm_reg, rm);
+
+ switch (opc) {
+ case OPC_RISC_FADD_S:
+ gen_helper_fadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], rm_reg);
+ break;
+ case OPC_RISC_FSUB_S:
+ gen_helper_fsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], rm_reg);
+ break;
+ case OPC_RISC_FMUL_S:
+ gen_helper_fmul_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], rm_reg);
+ break;
+ case OPC_RISC_FDIV_S:
+ gen_helper_fdiv_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], rm_reg);
+ break;
+ case OPC_RISC_FSGNJ_S:
+ // also handles: OPC_RISC_FSGNJN_S, OPC_RISC_FSGNJX_S
+ // TODO: probably don't need to use helpers here
+ if (rm == 0x0) {
+ gen_helper_fsgnj_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else if (rm == 0x1) {
+ gen_helper_fsgnjn_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else if (rm == 0x2) {
+ gen_helper_fsgnjx_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else {
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+ case OPC_RISC_FMIN_S:
+ // also handles: OPC_RISC_FMAX_S
+ if (rm == 0x0) {
+ gen_helper_fmin_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else if (rm == 0x1) {
+ gen_helper_fmax_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else {
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+
+ case OPC_RISC_FSQRT_S:
+ gen_helper_fsqrt_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], rm_reg);
+ break;
+
+ case OPC_RISC_FEQ_S:
+ // also handles: OPC_RISC_FLT_S, OPC_RISC_FLE_S
+ if (rm == 0x0) {
+ gen_helper_fle_s(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else if (rm == 0x1) {
+ gen_helper_flt_s(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else if (rm == 0x2) {
+ gen_helper_feq_s(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else {
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ }
+ gen_set_gpr(rd, write_int_rd);
+ break;
+
+ case OPC_RISC_FCVT_W_S:
+ // also OPC_RISC_FCVT_WU_S, OPC_RISC_FCVT_L_S, OPC_RISC_FCVT_LU_S
+ if (rs2 == 0x0) { // FCVT_W_S
+ gen_helper_fcvt_w_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+ } else if (rs2 == 0x1) { // FCVT_WU_S
+ gen_helper_fcvt_wu_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+ } else if (rs2 == 0x2) { // FCVT_L_S
+ gen_helper_fcvt_l_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+ } else if (rs2 == 0x3) { // FCVT_LU_S
+ gen_helper_fcvt_lu_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+ } else {
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ }
+ gen_set_gpr(rd, write_int_rd);
+ break;
+
+ case OPC_RISC_FCVT_S_W:
+ // also OPC_RISC_FCVT_S_WU, OPC_RISC_FCVT_S_L, OPC_RISC_FCVT_S_LU
+ gen_get_gpr(write_int_rd, rs1);
+ if (rs2 == 0) { // FCVT_S_W
+ gen_helper_fcvt_s_w(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+ } else if (rs2 == 0x1) { // FCVT_S_WU
+ gen_helper_fcvt_s_wu(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+ } else if (rs2 == 0x2) { // FCVT_S_L
+ gen_helper_fcvt_s_l(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+ } else if (rs2 == 0x3) { // FCVT_S_LU
+ gen_helper_fcvt_s_lu(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+ } else {
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+
+ case OPC_RISC_FMV_X_S:
+ // also OPC_RISC_FCLASS_S
+ if (rm == 0x0) { // FMV
+ tcg_gen_ext32s_tl(write_int_rd, cpu_fpr[rs1]);
+ } else if (rm == 0x1) {
+ gen_helper_fclass_s(write_int_rd, cpu_env, cpu_fpr[rs1]);
+ } else {
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ }
+ gen_set_gpr(rd, write_int_rd);
+ break;
+
+ case OPC_RISC_FMV_S_X:
+ gen_get_gpr(write_int_rd, rs1);
+ tcg_gen_mov_tl(cpu_fpr[rd], write_int_rd);
+ break;
+
+ // double
+ case OPC_RISC_FADD_D:
+ gen_helper_fadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], rm_reg);
+ break;
+ case OPC_RISC_FSUB_D:
+ gen_helper_fsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], rm_reg);
+ break;
+ case OPC_RISC_FMUL_D:
+ gen_helper_fmul_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], rm_reg);
+ break;
+ case OPC_RISC_FDIV_D:
+ gen_helper_fdiv_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2], rm_reg);
+ break;
+ case OPC_RISC_FSGNJ_D:
+ // also OPC_RISC_FSGNJN_D, OPC_RISC_FSGNJX_D
+ if (rm == 0x0) {
+ gen_helper_fsgnj_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else if (rm == 0x1) {
+ gen_helper_fsgnjn_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else if (rm == 0x2) {
+ gen_helper_fsgnjx_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else {
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+ case OPC_RISC_FMIN_D:
+ // also OPC_RISC_FMAX_D
+ if (rm == 0x0) {
+ gen_helper_fmin_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else if (rm == 0x1) {
+ gen_helper_fmax_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else {
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+ case OPC_RISC_FCVT_S_D:
+ if (rs2 == 0x1) {
+ gen_helper_fcvt_s_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], rm_reg);
+ } else {
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+ case OPC_RISC_FCVT_D_S:
+ if (rs2 == 0x0) {
+ gen_helper_fcvt_d_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], rm_reg);
+ } else {
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+ case OPC_RISC_FSQRT_D:
+ gen_helper_fsqrt_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], rm_reg);
+ break;
+ case OPC_RISC_FEQ_D:
+ // also OPC_RISC_FLT_D, OPC_RISC_FLE_D
+ if (rm == 0x0) {
+ gen_helper_fle_d(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else if (rm == 0x1) {
+ gen_helper_flt_d(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else if (rm == 0x2) {
+ gen_helper_feq_d(write_int_rd, cpu_env, cpu_fpr[rs1], cpu_fpr[rs2]);
+ } else {
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ }
+ gen_set_gpr(rd, write_int_rd);
+ break;
+ case OPC_RISC_FCVT_W_D:
+ // also OPC_RISC_FCVT_WU_D, OPC_RISC_FCVT_L_D, OPC_RISC_FCVT_LU_D
+ if (rs2 == 0x0) {
+ gen_helper_fcvt_w_d(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+ } else if (rs2 == 0x1) {
+ gen_helper_fcvt_wu_d(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+ } else if (rs2 == 0x2) {
+ gen_helper_fcvt_l_d(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+ } else if (rs2 == 0x3) {
+ gen_helper_fcvt_lu_d(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+ } else {
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ }
+ gen_set_gpr(rd, write_int_rd);
+ break;
+ case OPC_RISC_FCVT_D_W:
+ // also OPC_RISC_FCVT_D_WU, OPC_RISC_FCVT_D_L, OPC_RISC_FCVT_D_LU
+ gen_get_gpr(write_int_rd, rs1);
+ if (rs2 == 0x0) {
+ gen_helper_fcvt_d_w(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+ } else if (rs2 == 0x1) {
+ gen_helper_fcvt_d_wu(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+ } else if (rs2 == 0x2) {
+ gen_helper_fcvt_d_l(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+ } else if (rs2 == 0x3) {
+ gen_helper_fcvt_d_lu(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+ } else {
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+ case OPC_RISC_FMV_X_D:
+ // also OPC_RISC_FCLASS_D
+ if (rm == 0x0) { // FMV
+ tcg_gen_mov_tl(write_int_rd, cpu_fpr[rs1]);
+ } else if (rm == 0x1) {
+ gen_helper_fclass_d(write_int_rd, cpu_env, cpu_fpr[rs1]);
+ } else {
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ }
+ gen_set_gpr(rd, write_int_rd);
+ break;
+ case OPC_RISC_FMV_D_X:
+ gen_get_gpr(write_int_rd, rs1);
+ tcg_gen_mov_tl(cpu_fpr[rd], write_int_rd);
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+ tcg_temp_free(rm_reg);
+ tcg_temp_free(write_int_rd);
+}
+
+#ifdef RISCV_DEBUG_PRINT
+int monitor_region = 0;
+#endif
+
+static void decode_opc (CPURISCVState *env, DisasContext *ctx)
+{
+
+ int rs1;
+ int rs2;
+ int rd;
+ uint32_t op;
+ int16_t imm;
+ target_long ubimm;
+
+ // do not do misaligned address check here, address should never be
+ // misaligned
+ //
+ // instead, all control flow instructions check for themselves
+ //
+ // this is because epc must be the address of the control flow instruction
+ // that "caused" to the misaligned instruction access
+ //
+ // we leave this check here for now, since not all control flow
+ // instructions have been updated yet
+
+ /* make sure instructions are on a word boundary */
+ if (unlikely(ctx->pc & 0x3)) {
+ printf("addr misaligned\n");
+ printf("misaligned instruction, not completely implemented for riscv\n");
+ exit(1);
+ return;
+ }
+
+ op = MASK_OP_MAJOR(ctx->opcode);
+ rs1 = (ctx->opcode >> 15) & 0x1f;
+ rs2 = (ctx->opcode >> 20) & 0x1f;
+ rd = (ctx->opcode >> 7) & 0x1f;
+ imm = (int16_t)(((int32_t)ctx->opcode) >> 20); /* sign extends */
+
+#ifdef RISCV_DEBUG_PRINT
+ // this will print a log similar to spike, should be left off unless
+ // you're debugging QEMU
+ int start = 1; //0 && ctx->pc == 0x8ccac;
+ TCGv print_helper_tmp = tcg_temp_local_new();
+ TCGv printpc = tcg_temp_local_new();
+ tcg_gen_movi_tl(print_helper_tmp, ctx->opcode);
+ tcg_gen_movi_tl(printpc, ctx->pc);
+
+ if (monitor_region || start) {
+ gen_helper_debug_print(cpu_env, printpc, print_helper_tmp);
+ monitor_region = 1;
+
+ // can print some reg val too
+ gen_helper_debug_print(cpu_env, cpu_fpr[28], cpu_fpr[28]);
+
+ }
+ tcg_temp_free(print_helper_tmp);
+ tcg_temp_free(printpc);
+#endif
+
+ switch (op) {
+
+ case OPC_RISC_LUI:
+ if (rd == 0) {
+ break; // NOP
+ }
+ tcg_gen_movi_tl(cpu_gpr[rd], (ctx->opcode & 0xFFFFF000));
+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+ break;
+ case OPC_RISC_AUIPC:
+ if (rd == 0) {
+ break; // NOP
+ }
+ tcg_gen_movi_tl(cpu_gpr[rd], (ctx->opcode & 0xFFFFF000));
+ tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
+ tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rd], tcg_const_tl(ctx->pc));
+ break;
+ case OPC_RISC_JAL: {
+ TCGv nextpc = tcg_temp_local_new();
+ TCGv testpc = tcg_temp_local_new();
+ TCGLabel* misaligned = gen_new_label();
+ TCGLabel* done = gen_new_label();
+ ubimm = (target_long) (GET_JAL_IMM(ctx->opcode));
+ tcg_gen_movi_tl(nextpc, ctx->pc + ubimm);
+ // check misaligned:
+ tcg_gen_andi_tl(testpc, nextpc, 0x3);
+ tcg_gen_brcondi_tl(TCG_COND_NE, testpc, 0x0, misaligned);
+ if (rd != 0) {
+ tcg_gen_movi_tl(cpu_gpr[rd], 4);
+ tcg_gen_addi_tl(cpu_gpr[rd], cpu_gpr[rd], ctx->pc);
+ }
+
+#ifdef DISABLE_CHAINING_JAL
+ tcg_gen_movi_tl(cpu_PC, ctx->pc + ubimm);
+ tcg_gen_exit_tb(0);
+#else
+ gen_goto_tb(ctx, 0, ctx->pc + ubimm); // must use this for safety
+#endif
+ tcg_gen_br(done);
+ gen_set_label(misaligned);
+ // throw exception for misaligned case
+ generate_exception_mbadaddr(ctx, NEW_RISCV_EXCP_INST_ADDR_MIS);
+ gen_set_label(done);
+ ctx->bstate = BS_BRANCH;
+ tcg_temp_free(nextpc);
+ tcg_temp_free(testpc);
+ }
+ break;
+ case OPC_RISC_JALR:
+ gen_jalr(ctx, MASK_OP_JALR(ctx->opcode), rd, rs1, imm);
+ break;
+ case OPC_RISC_BRANCH:
+ gen_branch(ctx, MASK_OP_BRANCH(ctx->opcode), rs1, rs2, GET_B_IMM(ctx->opcode));
+ break;
+ case OPC_RISC_LOAD:
+ gen_load(ctx, MASK_OP_LOAD(ctx->opcode), rd, rs1, imm);
+ break;
+ case OPC_RISC_STORE:
+ gen_store(ctx, MASK_OP_STORE(ctx->opcode), rs1, rs2, GET_STORE_IMM(ctx->opcode));
+ break;
+ case OPC_RISC_ARITH_IMM:
+ if (rd == 0) {
+ break; // NOP
+ }
+ gen_arith_imm(ctx, MASK_OP_ARITH_IMM(ctx->opcode), rd, rs1, imm);
+ break;
+ case OPC_RISC_ARITH:
+ if (rd == 0) {
+ break; // NOP
+ }
+ gen_arith(ctx, MASK_OP_ARITH(ctx->opcode), rd, rs1, rs2);
+ break;
+ case OPC_RISC_ARITH_IMM_W:
+ if (rd == 0) {
+ break; // NOP
+ }
+ gen_arith_imm_w(ctx, MASK_OP_ARITH_IMM_W(ctx->opcode), rd, rs1, imm);
+ break;
+ case OPC_RISC_ARITH_W:
+ if (rd == 0) {
+ break; // NOP
+ }
+ gen_arith_w(ctx, MASK_OP_ARITH_W(ctx->opcode), rd, rs1, rs2);
+ break;
+ case OPC_RISC_FENCE:
+ // standard fence is nop
+ // fence_i flushes TB (like an icache):
+ if (ctx->opcode & 0x1000) { // FENCE_I
+ gen_helper_fence_i(cpu_env);
+ tcg_gen_movi_tl(cpu_PC, ctx->pc + 4);
+ tcg_gen_exit_tb(0); // no chaining
+ ctx->bstate = BS_BRANCH;
+ }
+ break;
+ case OPC_RISC_SYSTEM:
+ gen_system(ctx, MASK_OP_SYSTEM(ctx->opcode), rd, rs1, (ctx->opcode & 0xFFF00000) >> 20);
+ break;
+ case OPC_RISC_ATOMIC:
+ gen_atomic(ctx, MASK_OP_ATOMIC(ctx->opcode), rd, rs1, rs2);
+ break;
+ case OPC_RISC_FP_LOAD:
+ gen_fp_load(ctx, MASK_OP_FP_LOAD(ctx->opcode), rd, rs1, imm);
+ break;
+ case OPC_RISC_FP_STORE:
+ gen_fp_store(ctx, MASK_OP_FP_STORE(ctx->opcode), rs1, rs2, GET_STORE_IMM(ctx->opcode));
+ break;
+ case OPC_RISC_FMADD:
+ gen_fp_fmadd(ctx, MASK_OP_FP_FMADD(ctx->opcode), rd, rs1, rs2, GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
+ break;
+ case OPC_RISC_FMSUB:
+ gen_fp_fmsub(ctx, MASK_OP_FP_FMSUB(ctx->opcode), rd, rs1, rs2, GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
+ break;
+ case OPC_RISC_FNMSUB:
+ gen_fp_fnmsub(ctx, MASK_OP_FP_FNMSUB(ctx->opcode), rd, rs1, rs2, GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
+ break;
+ case OPC_RISC_FNMADD:
+ gen_fp_fnmadd(ctx, MASK_OP_FP_FNMADD(ctx->opcode), rd, rs1, rs2, GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
+ break;
+ case OPC_RISC_FP_ARITH:
+ gen_fp_arith(ctx, MASK_OP_FP_ARITH(ctx->opcode), rd, rs1, rs2, GET_RM(ctx->opcode));
+ break;
+ default:
+ kill_unknown(ctx, NEW_RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+}
+
+static inline void
+gen_intermediate_code_internal(CPURISCVState *env, TranslationBlock *tb,
+ bool search_pc)
+{
+ RISCVCPU *cpu = riscv_env_get_cpu(env);
+ CPUState *cs = CPU(cpu);
+ DisasContext ctx;
+ target_ulong pc_start;
+ target_ulong next_page_start; // new
+ int num_insns;
+ int max_insns;
+ pc_start = tb->pc;
+ next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
+ ctx.pc = pc_start;
+
+ // once we have GDB, the rest of the translate.c implementation should be
+ // ready for singlestep
+ ctx.singlestep_enabled = cs->singlestep_enabled;
+
+ ctx.tb = tb;
+ ctx.bstate = BS_NONE;
+
+ // restore_cpu_state?
+
+ ctx.mem_idx = cpu_mmu_index(env, false);
+ num_insns = 0;
+ max_insns = tb->cflags & CF_COUNT_MASK;
+ if (max_insns == 0) {
+ max_insns = CF_COUNT_MASK;
+ }
+ if (max_insns > TCG_MAX_INSNS) {
+ max_insns = TCG_MAX_INSNS;
+ }
+ gen_tb_start(tb);
+
+ while (ctx.bstate == BS_NONE) {
+ tcg_gen_insn_start(ctx.pc);
+ num_insns++;
+
+ if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
+ tcg_gen_movi_tl(cpu_PC, ctx.pc);
+ ctx.bstate = BS_BRANCH;
+ gen_helper_raise_exception_debug(cpu_env);
+ /* The address covered by the breakpoint must be included in
+ [tb->pc, tb->pc + tb->size) in order to for it to be
+ properly cleared -- thus we increment the PC here so that
+ the logic setting tb->size below does the right thing. */
+ ctx.pc += 4;
+ goto done_generating;
+ }
+
+ if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
+ gen_io_start();
+ }
+
+ ctx.opcode = cpu_ldl_code(env, ctx.pc);
+ decode_opc(env, &ctx);
+ ctx.pc += 4;
+
+ if (cs->singlestep_enabled) {
+ break;
+ }
+ if (ctx.pc >= next_page_start) {
+ break;
+ }
+ if (tcg_op_buf_full()) {
+ break;
+ }
+ if (num_insns >= max_insns) {
+ break;
+ }
+ if(singlestep) {
+ break;
+ }
+
+ }
+ if (tb->cflags & CF_LAST_IO) {
+ gen_io_end();
+ }
+ if (cs->singlestep_enabled && ctx.bstate != BS_BRANCH) {
+ if (ctx.bstate == BS_NONE) {
+ tcg_gen_movi_tl(cpu_PC, ctx.pc); // NOT PC+4, that was already done
+ }
+ gen_helper_raise_exception_debug(cpu_env);
+ } else {
+ switch (ctx.bstate) {
+ case BS_STOP:
+ gen_goto_tb(&ctx, 0, ctx.pc);
+ break;
+ case BS_NONE:
+ // DO NOT CHAIN. This is for END-OF-PAGE. See gen_goto_tb.
+ tcg_gen_movi_tl(cpu_PC, ctx.pc); // NOT PC+4, that was already done
+ tcg_gen_exit_tb(0);
+ break;
+ case BS_BRANCH:
+ // anything using BS_BRANCH will have generated it's own exit seq
+ default:
+ break;
+ }
+ }
+done_generating:
+ gen_tb_end(tb, num_insns);
+ tb->size = ctx.pc - pc_start;
+ tb->icount = num_insns;
+
+/*
+#ifdef DEBUG_DISAS // TODO: riscv disassembly
+ LOG_DISAS("\n");
+ if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+ qemu_log("IN: %s\n", lookup_symbol(pc_start));
+ log_target_disas(env, pc_start, ctx.pc - pc_start, 0);
+ qemu_log("\n");
+ }
+#endif*/
+}
+
+void gen_intermediate_code (CPURISCVState *env, struct TranslationBlock *tb)
+{
+ gen_intermediate_code_internal(env, tb, false);
+}
+
+void riscv_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
+ int flags)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
+ int i;
+
+ cpu_fprintf(f, "pc=0x" TARGET_FMT_lx "\n", env->active_tc.PC);
+ for (i = 0; i < 32; i++) {
+ cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->active_tc.gpr[i]);
+ if ((i & 3) == 3) {
+ cpu_fprintf(f, "\n");
+ }
+ }
+
+ cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "MSTATUS ", env->csr[NEW_CSR_MSTATUS]);
+ cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "MTIMECMP", env->csr[NEW_CSR_MTIMECMP]);
+ cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "MTIME ", cpu_riscv_read_mtime(env));
+ cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "TIME ", cpu_riscv_read_time(env));
+
+ cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "MIP ", env->csr[NEW_CSR_MIP]);
+
+ cpu_fprintf(f, " %s " TARGET_FMT_lx "\n", "MIE ", env->csr[NEW_CSR_MIE]);
+
+ for (i = 0; i < 32; i++) {
+ if ((i & 3) == 0) {
+ cpu_fprintf(f, "FPR%02d:", i);
+ }
+ cpu_fprintf(f, " %s " TARGET_FMT_lx, fpr_regnames[i], env->active_tc.fpr[i]);
+ if ((i & 3) == 3) {
+ cpu_fprintf(f, "\n");
+ }
+ }
+}
+
+void riscv_tcg_init(void)
+{
+ int i;
+ static int inited;
+
+ /* Initialize various static tables. */
+ if (inited) {
+ return;
+ }
+
+ cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+ // WARNING: cpu_gpr[0] is not allocated ON PURPOSE. Do not use it.
+ // Use the gen_set_gpr and gen_get_gpr helper functions when accessing
+ // registers, unless you specifically block reads/writes to reg 0
+ TCGV_UNUSED(cpu_gpr[0]);
+ for (i = 1; i < 32; i++) {
+ cpu_gpr[i] = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPURISCVState, active_tc.gpr[i]),
+ regnames[i]);
+ }
+
+ for (i = 0; i < 32; i++) {
+ cpu_fpr[i] = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPURISCVState, active_tc.fpr[i]),
+ fpr_regnames[i]);
+ }
+
+ cpu_PC = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPURISCVState, active_tc.PC), "PC");
+
+ load_reservation = tcg_global_mem_new(TCG_AREG0,
+ offsetof(CPURISCVState, active_tc.load_reservation),
+ "load_reservation");
+ inited = 1;
+}
+
+#include "translate_init.c"
+
+RISCVCPU *cpu_riscv_init(const char *cpu_model)
+{
+ RISCVCPU *cpu;
+ CPURISCVState *env;
+ const riscv_def_t *def;
+
+ def = cpu_riscv_find_by_name(cpu_model);
+ if (!def)
+ return NULL;
+ cpu = RISCV_CPU(object_new(TYPE_RISCV_CPU));
+ env = &cpu->env;
+ env->cpu_model = def;
+
+ memset(env->csr, 0, 4096*sizeof(uint64_t));
+
+ // init mstatus
+ target_ulong start_mstatus = 0;
+ start_mstatus = set_field(start_mstatus, MSTATUS_PRV, PRV_M);
+ start_mstatus = set_field(start_mstatus, MSTATUS_PRV1, PRV_U);
+ start_mstatus = set_field(start_mstatus, MSTATUS_PRV2, PRV_U);
+ env->csr[NEW_CSR_MSTATUS] = start_mstatus;
+
+ // set mcpuid from def
+ env->csr[NEW_CSR_MCPUID] = def->init_mcpuid_reg;
+ object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
+
+ return cpu;
+}
+
+void cpu_state_reset(CPURISCVState *env)
+{
+ RISCVCPU *cpu = riscv_env_get_cpu(env);
+ CPUState *cs = CPU(cpu);
+
+ env->active_tc.PC = RISCV_START_PC; // STARTING PC VALUE def'd in cpu.h
+ cs->exception_index = EXCP_NONE;
+}
+
+void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb, target_ulong *data)
+{
+ env->active_tc.PC = data[0];
+}
new file mode 100644
@@ -0,0 +1,63 @@
+/*
+ * RISC-V emulation for qemu: CPU Initialization Routines.
+ *
+ * Author: Sagar Karandikar, sagark@eecs.berkeley.edu
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define MCPUID_RV64I (2L << 62)
+#define MCPUID_SUPER (1L << ('S' - 'A'))
+#define MCPUID_USER (1L << ('U' - 'A'))
+#define MCPUID_I (1L << ('I' - 'A'))
+#define MCPUID_M (1L << ('M' - 'A'))
+#define MCPUID_A (1L << ('A' - 'A'))
+#define MCPUID_F (1L << ('F' - 'A'))
+#define MCPUID_D (1L << ('D' - 'A'))
+
+struct riscv_def_t {
+ const char *name;
+ target_ulong init_mcpuid_reg;
+};
+
+/* RISC-V CPU definitions */
+static const riscv_def_t riscv_defs[] =
+{
+ {
+ .name = "riscv-generic",
+ // for now, hardcode RV64G:
+ .init_mcpuid_reg = MCPUID_RV64I | MCPUID_SUPER | /*MCPUID_USER |*/ MCPUID_I
+ | MCPUID_M | MCPUID_A | MCPUID_F | MCPUID_D,
+ },
+};
+
+static const riscv_def_t *cpu_riscv_find_by_name (const char *name)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(riscv_defs); i++) {
+ if (strcasecmp(name, riscv_defs[i].name) == 0) {
+ return &riscv_defs[i];
+ }
+ }
+ return NULL;
+}
+
+void riscv_cpu_list (FILE *f, fprintf_function cpu_fprintf)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(riscv_defs); i++) {
+ (*cpu_fprintf)(f, "RISCV '%s'\n", riscv_defs[i].name);
+ }
+}
Signed-off-by: Sagar Karandikar <sagark@eecs.berkeley.edu> --- arch_init.c | 2 + configure | 13 + cpus.c | 6 + default-configs/riscv-linux-user.mak | 1 + default-configs/riscv-softmmu.mak | 38 + disas.c | 2 + disas/Makefile.objs | 1 + disas/riscv.c | 46 + hw/riscv/Makefile.objs | 5 + hw/riscv/cputimer.c | 170 ++ hw/riscv/htif/frontend.c | 215 ++ hw/riscv/htif/htif.c | 459 +++++ hw/riscv/riscv_board.c | 330 +++ hw/riscv/riscv_int.c | 84 + hw/riscv/softint.c | 121 ++ include/disas/bfd.h | 1 + include/elf.h | 2 + include/exec/poison.h | 1 + include/exec/user/thunk.h | 2 +- include/hw/riscv/bios.h | 4 + include/hw/riscv/cpudevs.h | 14 + include/hw/riscv/cputimer.h | 4 + include/hw/riscv/htif/frontend.h | 30 + include/hw/riscv/htif/htif.h | 76 + include/hw/riscv/riscv.h | 10 + include/hw/riscv/softint.h | 50 + include/sysemu/arch_init.h | 1 + target-riscv/Makefile.objs | 114 ++ target-riscv/TODO | 17 + target-riscv/cpu-qom.h | 86 + target-riscv/cpu.c | 143 ++ target-riscv/cpu.h | 449 ++++ .../fpu-custom-riscv/8086/OLD-specialize.c | 40 + .../fpu-custom-riscv/8086/OLD-specialize.h | 379 ++++ target-riscv/fpu-custom-riscv/8086/platform.h | 38 + .../fpu-custom-riscv/8086/s_commonNaNToF32UI.c | 17 + .../fpu-custom-riscv/8086/s_commonNaNToF64UI.c | 19 + .../fpu-custom-riscv/8086/s_f32UIToCommonNaN.c | 25 + .../fpu-custom-riscv/8086/s_f64UIToCommonNaN.c | 25 + .../fpu-custom-riscv/8086/s_isSigNaNF32UI.c | 13 + .../fpu-custom-riscv/8086/s_isSigNaNF64UI.c | 15 + .../fpu-custom-riscv/8086/s_propagateNaNF32UI.c | 55 + .../fpu-custom-riscv/8086/s_propagateNaNF64UI.c | 55 + .../fpu-custom-riscv/8086/softfloat_raiseFlags.c | 51 + .../fpu-custom-riscv/8086/softfloat_types.h | 16 + target-riscv/fpu-custom-riscv/8086/specialize.h | 113 + target-riscv/fpu-custom-riscv/f32_add.c | 29 + target-riscv/fpu-custom-riscv/f32_classify.c | 33 + target-riscv/fpu-custom-riscv/f32_div.c | 96 + target-riscv/fpu-custom-riscv/f32_eq.c | 34 + target-riscv/fpu-custom-riscv/f32_eq_signaling.c | 29 + target-riscv/fpu-custom-riscv/f32_isSignalingNaN.c | 16 + target-riscv/fpu-custom-riscv/f32_le.c | 34 + target-riscv/fpu-custom-riscv/f32_le_quiet.c | 39 + target-riscv/fpu-custom-riscv/f32_lt.c | 34 + target-riscv/fpu-custom-riscv/f32_lt_quiet.c | 39 + target-riscv/fpu-custom-riscv/f32_mul.c | 89 + target-riscv/fpu-custom-riscv/f32_mulAdd.c | 25 + target-riscv/fpu-custom-riscv/f32_rem.c | 124 ++ target-riscv/fpu-custom-riscv/f32_roundToInt.c | 78 + target-riscv/fpu-custom-riscv/f32_sqrt.c | 74 + target-riscv/fpu-custom-riscv/f32_sub.c | 29 + target-riscv/fpu-custom-riscv/f32_to_f64.c | 47 + target-riscv/fpu-custom-riscv/f32_to_i32.c | 34 + .../fpu-custom-riscv/f32_to_i32_r_minMag.c | 45 + target-riscv/fpu-custom-riscv/f32_to_i64.c | 44 + .../fpu-custom-riscv/f32_to_i64_r_minMag.c | 52 + target-riscv/fpu-custom-riscv/f32_to_ui32.c | 33 + .../fpu-custom-riscv/f32_to_ui32_r_minMag.c | 41 + target-riscv/fpu-custom-riscv/f32_to_ui64.c | 42 + .../fpu-custom-riscv/f32_to_ui64_r_minMag.c | 45 + target-riscv/fpu-custom-riscv/f64_add.c | 29 + target-riscv/fpu-custom-riscv/f64_classify.c | 33 + target-riscv/fpu-custom-riscv/f64_div.c | 104 + target-riscv/fpu-custom-riscv/f64_eq.c | 35 + target-riscv/fpu-custom-riscv/f64_eq_signaling.c | 30 + target-riscv/fpu-custom-riscv/f64_isSignalingNaN.c | 16 + target-riscv/fpu-custom-riscv/f64_le.c | 35 + target-riscv/fpu-custom-riscv/f64_le_quiet.c | 40 + target-riscv/fpu-custom-riscv/f64_lt.c | 35 + target-riscv/fpu-custom-riscv/f64_lt_quiet.c | 40 + target-riscv/fpu-custom-riscv/f64_mul.c | 91 + target-riscv/fpu-custom-riscv/f64_mulAdd.c | 25 + target-riscv/fpu-custom-riscv/f64_rem.c | 113 + target-riscv/fpu-custom-riscv/f64_roundToInt.c | 80 + target-riscv/fpu-custom-riscv/f64_sqrt.c | 74 + target-riscv/fpu-custom-riscv/f64_sub.c | 29 + target-riscv/fpu-custom-riscv/f64_to_f32.c | 43 + target-riscv/fpu-custom-riscv/f64_to_i32.c | 30 + .../fpu-custom-riscv/f64_to_i32_r_minMag.c | 50 + target-riscv/fpu-custom-riscv/f64_to_i64.c | 46 + .../fpu-custom-riscv/f64_to_i64_r_minMag.c | 52 + target-riscv/fpu-custom-riscv/f64_to_ui32.c | 29 + .../fpu-custom-riscv/f64_to_ui32_r_minMag.c | 40 + target-riscv/fpu-custom-riscv/f64_to_ui64.c | 41 + .../fpu-custom-riscv/f64_to_ui64_r_minMag.c | 45 + target-riscv/fpu-custom-riscv/i32_to_f32.c | 21 + target-riscv/fpu-custom-riscv/i32_to_f64.c | 31 + target-riscv/fpu-custom-riscv/i64_to_f32.c | 36 + target-riscv/fpu-custom-riscv/i64_to_f64.c | 21 + target-riscv/fpu-custom-riscv/internals.h | 232 +++ target-riscv/fpu-custom-riscv/platform.h | 42 + target-riscv/fpu-custom-riscv/primitives.h | 628 ++++++ target-riscv/fpu-custom-riscv/s_add128.c | 17 + target-riscv/fpu-custom-riscv/s_add192.c | 30 + target-riscv/fpu-custom-riscv/s_addMagsF32.c | 75 + target-riscv/fpu-custom-riscv/s_addMagsF64.c | 77 + target-riscv/fpu-custom-riscv/s_commonNaNToF32UI.c | 17 + target-riscv/fpu-custom-riscv/s_commonNaNToF64UI.c | 17 + .../fpu-custom-riscv/s_countLeadingZeros32.c | 22 + .../fpu-custom-riscv/s_countLeadingZeros64.c | 32 + .../fpu-custom-riscv/s_countLeadingZeros8.c | 24 + target-riscv/fpu-custom-riscv/s_eq128.c | 13 + .../fpu-custom-riscv/s_estimateDiv128To64.c | 28 + target-riscv/fpu-custom-riscv/s_estimateSqrt32.c | 37 + target-riscv/fpu-custom-riscv/s_f32UIToCommonNaN.c | 25 + target-riscv/fpu-custom-riscv/s_f64UIToCommonNaN.c | 25 + target-riscv/fpu-custom-riscv/s_isSigNaNF32UI.c | 13 + target-riscv/fpu-custom-riscv/s_isSigNaNF64UI.c | 15 + target-riscv/fpu-custom-riscv/s_le128.c | 13 + target-riscv/fpu-custom-riscv/s_lt128.c | 13 + target-riscv/fpu-custom-riscv/s_mul128By64To192.c | 20 + target-riscv/fpu-custom-riscv/s_mul128To256.c | 28 + target-riscv/fpu-custom-riscv/s_mul64To128.c | 28 + target-riscv/fpu-custom-riscv/s_mulAddF32.c | 171 ++ target-riscv/fpu-custom-riscv/s_mulAddF64.c | 188 ++ .../fpu-custom-riscv/s_normRoundPackToF32.c | 24 + .../fpu-custom-riscv/s_normRoundPackToF64.c | 24 + .../fpu-custom-riscv/s_normSubnormalF32Sig.c | 18 + .../fpu-custom-riscv/s_normSubnormalF64Sig.c | 18 + .../fpu-custom-riscv/s_propagateNaNF32UI.c | 25 + .../fpu-custom-riscv/s_propagateNaNF64UI.c | 25 + target-riscv/fpu-custom-riscv/s_roundPackToF32.c | 65 + target-riscv/fpu-custom-riscv/s_roundPackToF64.c | 66 + target-riscv/fpu-custom-riscv/s_roundPackToI32.c | 48 + target-riscv/fpu-custom-riscv/s_roundPackToI64.c | 52 + target-riscv/fpu-custom-riscv/s_roundPackToUI32.c | 44 + target-riscv/fpu-custom-riscv/s_roundPackToUI64.c | 46 + .../fpu-custom-riscv/s_shift128ExtraRightJam.c | 38 + target-riscv/fpu-custom-riscv/s_shift128RightJam.c | 31 + target-riscv/fpu-custom-riscv/s_shift32RightJam.c | 15 + .../fpu-custom-riscv/s_shift64ExtraRightJam.c | 23 + target-riscv/fpu-custom-riscv/s_shift64RightJam.c | 15 + .../s_shortShift128ExtraRightJam.c | 20 + .../fpu-custom-riscv/s_shortShift128Left.c | 16 + .../fpu-custom-riscv/s_shortShift128Right.c | 16 + .../fpu-custom-riscv/s_shortShift192Left.c | 20 + .../fpu-custom-riscv/s_shortShift32Right1Jam.c | 12 + .../fpu-custom-riscv/s_shortShift64ExtraRightJam.c | 17 + .../fpu-custom-riscv/s_shortShift64RightJam.c | 12 + target-riscv/fpu-custom-riscv/s_sub128.c | 17 + target-riscv/fpu-custom-riscv/s_sub192.c | 30 + target-riscv/fpu-custom-riscv/s_subMagsF32.c | 81 + target-riscv/fpu-custom-riscv/s_subMagsF64.c | 81 + target-riscv/fpu-custom-riscv/softfloat.ac | 0 target-riscv/fpu-custom-riscv/softfloat.h | 235 +++ target-riscv/fpu-custom-riscv/softfloat.mk.in | 126 ++ .../fpu-custom-riscv/softfloat_raiseFlags.c | 51 + target-riscv/fpu-custom-riscv/softfloat_state.c | 19 + target-riscv/fpu-custom-riscv/softfloat_types.h | 16 + target-riscv/fpu-custom-riscv/specialize.h | 113 + target-riscv/fpu-custom-riscv/ui32_to_f32.c | 25 + target-riscv/fpu-custom-riscv/ui32_to_f64.c | 26 + target-riscv/fpu-custom-riscv/ui64_to_f32.c | 31 + target-riscv/fpu-custom-riscv/ui64_to_f64.c | 25 + target-riscv/gdbstub.c | 177 ++ target-riscv/helper.c | 356 ++++ target-riscv/helper.h | 82 + target-riscv/instmap.h | 311 +++ target-riscv/machine.c | 91 + target-riscv/op_helper.c | 1037 ++++++++++ target-riscv/riscv-defs.h | 14 + target-riscv/translate.c | 2155 ++++++++++++++++++++ target-riscv/translate_init.c | 63 + 174 files changed, 13518 insertions(+), 1 deletion(-) create mode 100644 default-configs/riscv-linux-user.mak create mode 100644 default-configs/riscv-softmmu.mak create mode 100644 disas/riscv.c create mode 100644 hw/riscv/Makefile.objs create mode 100644 hw/riscv/cputimer.c create mode 100644 hw/riscv/htif/frontend.c create mode 100644 hw/riscv/htif/htif.c create mode 100644 hw/riscv/riscv_board.c create mode 100644 hw/riscv/riscv_int.c create mode 100644 hw/riscv/softint.c create mode 100644 include/hw/riscv/bios.h create mode 100644 include/hw/riscv/cpudevs.h create mode 100644 include/hw/riscv/cputimer.h create mode 100644 include/hw/riscv/htif/frontend.h create mode 100644 include/hw/riscv/htif/htif.h create mode 100644 include/hw/riscv/riscv.h create mode 100644 include/hw/riscv/softint.h create mode 100644 target-riscv/Makefile.objs create mode 100644 target-riscv/TODO create mode 100644 target-riscv/cpu-qom.h create mode 100644 target-riscv/cpu.c create mode 100644 target-riscv/cpu.h create mode 100755 target-riscv/fpu-custom-riscv/8086/OLD-specialize.c create mode 100755 target-riscv/fpu-custom-riscv/8086/OLD-specialize.h create mode 100755 target-riscv/fpu-custom-riscv/8086/platform.h create mode 100755 target-riscv/fpu-custom-riscv/8086/s_commonNaNToF32UI.c create mode 100755 target-riscv/fpu-custom-riscv/8086/s_commonNaNToF64UI.c create mode 100755 target-riscv/fpu-custom-riscv/8086/s_f32UIToCommonNaN.c create mode 100755 target-riscv/fpu-custom-riscv/8086/s_f64UIToCommonNaN.c create mode 100755 target-riscv/fpu-custom-riscv/8086/s_isSigNaNF32UI.c create mode 100755 target-riscv/fpu-custom-riscv/8086/s_isSigNaNF64UI.c create mode 100755 target-riscv/fpu-custom-riscv/8086/s_propagateNaNF32UI.c create mode 100755 target-riscv/fpu-custom-riscv/8086/s_propagateNaNF64UI.c create mode 100755 target-riscv/fpu-custom-riscv/8086/softfloat_raiseFlags.c create mode 100755 target-riscv/fpu-custom-riscv/8086/softfloat_types.h create mode 100755 target-riscv/fpu-custom-riscv/8086/specialize.h create mode 100755 target-riscv/fpu-custom-riscv/f32_add.c create mode 100755 target-riscv/fpu-custom-riscv/f32_classify.c create mode 100755 target-riscv/fpu-custom-riscv/f32_div.c create mode 100755 target-riscv/fpu-custom-riscv/f32_eq.c create mode 100755 target-riscv/fpu-custom-riscv/f32_eq_signaling.c create mode 100755 target-riscv/fpu-custom-riscv/f32_isSignalingNaN.c create mode 100755 target-riscv/fpu-custom-riscv/f32_le.c create mode 100755 target-riscv/fpu-custom-riscv/f32_le_quiet.c create mode 100755 target-riscv/fpu-custom-riscv/f32_lt.c create mode 100755 target-riscv/fpu-custom-riscv/f32_lt_quiet.c create mode 100755 target-riscv/fpu-custom-riscv/f32_mul.c create mode 100755 target-riscv/fpu-custom-riscv/f32_mulAdd.c create mode 100755 target-riscv/fpu-custom-riscv/f32_rem.c create mode 100755 target-riscv/fpu-custom-riscv/f32_roundToInt.c create mode 100755 target-riscv/fpu-custom-riscv/f32_sqrt.c create mode 100755 target-riscv/fpu-custom-riscv/f32_sub.c create mode 100755 target-riscv/fpu-custom-riscv/f32_to_f64.c create mode 100755 target-riscv/fpu-custom-riscv/f32_to_i32.c create mode 100755 target-riscv/fpu-custom-riscv/f32_to_i32_r_minMag.c create mode 100755 target-riscv/fpu-custom-riscv/f32_to_i64.c create mode 100755 target-riscv/fpu-custom-riscv/f32_to_i64_r_minMag.c create mode 100755 target-riscv/fpu-custom-riscv/f32_to_ui32.c create mode 100755 target-riscv/fpu-custom-riscv/f32_to_ui32_r_minMag.c create mode 100755 target-riscv/fpu-custom-riscv/f32_to_ui64.c create mode 100755 target-riscv/fpu-custom-riscv/f32_to_ui64_r_minMag.c create mode 100755 target-riscv/fpu-custom-riscv/f64_add.c create mode 100755 target-riscv/fpu-custom-riscv/f64_classify.c create mode 100755 target-riscv/fpu-custom-riscv/f64_div.c create mode 100755 target-riscv/fpu-custom-riscv/f64_eq.c create mode 100755 target-riscv/fpu-custom-riscv/f64_eq_signaling.c create mode 100755 target-riscv/fpu-custom-riscv/f64_isSignalingNaN.c create mode 100755 target-riscv/fpu-custom-riscv/f64_le.c create mode 100755 target-riscv/fpu-custom-riscv/f64_le_quiet.c create mode 100755 target-riscv/fpu-custom-riscv/f64_lt.c create mode 100755 target-riscv/fpu-custom-riscv/f64_lt_quiet.c create mode 100755 target-riscv/fpu-custom-riscv/f64_mul.c create mode 100755 target-riscv/fpu-custom-riscv/f64_mulAdd.c create mode 100755 target-riscv/fpu-custom-riscv/f64_rem.c create mode 100755 target-riscv/fpu-custom-riscv/f64_roundToInt.c create mode 100755 target-riscv/fpu-custom-riscv/f64_sqrt.c create mode 100755 target-riscv/fpu-custom-riscv/f64_sub.c create mode 100755 target-riscv/fpu-custom-riscv/f64_to_f32.c create mode 100755 target-riscv/fpu-custom-riscv/f64_to_i32.c create mode 100755 target-riscv/fpu-custom-riscv/f64_to_i32_r_minMag.c create mode 100755 target-riscv/fpu-custom-riscv/f64_to_i64.c create mode 100755 target-riscv/fpu-custom-riscv/f64_to_i64_r_minMag.c create mode 100755 target-riscv/fpu-custom-riscv/f64_to_ui32.c create mode 100755 target-riscv/fpu-custom-riscv/f64_to_ui32_r_minMag.c create mode 100755 target-riscv/fpu-custom-riscv/f64_to_ui64.c create mode 100755 target-riscv/fpu-custom-riscv/f64_to_ui64_r_minMag.c create mode 100755 target-riscv/fpu-custom-riscv/i32_to_f32.c create mode 100755 target-riscv/fpu-custom-riscv/i32_to_f64.c create mode 100755 target-riscv/fpu-custom-riscv/i64_to_f32.c create mode 100755 target-riscv/fpu-custom-riscv/i64_to_f64.c create mode 100755 target-riscv/fpu-custom-riscv/internals.h create mode 100755 target-riscv/fpu-custom-riscv/platform.h create mode 100755 target-riscv/fpu-custom-riscv/primitives.h create mode 100755 target-riscv/fpu-custom-riscv/s_add128.c create mode 100755 target-riscv/fpu-custom-riscv/s_add192.c create mode 100755 target-riscv/fpu-custom-riscv/s_addMagsF32.c create mode 100755 target-riscv/fpu-custom-riscv/s_addMagsF64.c create mode 100755 target-riscv/fpu-custom-riscv/s_commonNaNToF32UI.c create mode 100755 target-riscv/fpu-custom-riscv/s_commonNaNToF64UI.c create mode 100755 target-riscv/fpu-custom-riscv/s_countLeadingZeros32.c create mode 100755 target-riscv/fpu-custom-riscv/s_countLeadingZeros64.c create mode 100755 target-riscv/fpu-custom-riscv/s_countLeadingZeros8.c create mode 100755 target-riscv/fpu-custom-riscv/s_eq128.c create mode 100755 target-riscv/fpu-custom-riscv/s_estimateDiv128To64.c create mode 100755 target-riscv/fpu-custom-riscv/s_estimateSqrt32.c create mode 100755 target-riscv/fpu-custom-riscv/s_f32UIToCommonNaN.c create mode 100755 target-riscv/fpu-custom-riscv/s_f64UIToCommonNaN.c create mode 100755 target-riscv/fpu-custom-riscv/s_isSigNaNF32UI.c create mode 100755 target-riscv/fpu-custom-riscv/s_isSigNaNF64UI.c create mode 100755 target-riscv/fpu-custom-riscv/s_le128.c create mode 100755 target-riscv/fpu-custom-riscv/s_lt128.c create mode 100755 target-riscv/fpu-custom-riscv/s_mul128By64To192.c create mode 100755 target-riscv/fpu-custom-riscv/s_mul128To256.c create mode 100755 target-riscv/fpu-custom-riscv/s_mul64To128.c create mode 100755 target-riscv/fpu-custom-riscv/s_mulAddF32.c create mode 100755 target-riscv/fpu-custom-riscv/s_mulAddF64.c create mode 100755 target-riscv/fpu-custom-riscv/s_normRoundPackToF32.c create mode 100755 target-riscv/fpu-custom-riscv/s_normRoundPackToF64.c create mode 100755 target-riscv/fpu-custom-riscv/s_normSubnormalF32Sig.c create mode 100755 target-riscv/fpu-custom-riscv/s_normSubnormalF64Sig.c create mode 100755 target-riscv/fpu-custom-riscv/s_propagateNaNF32UI.c create mode 100755 target-riscv/fpu-custom-riscv/s_propagateNaNF64UI.c create mode 100755 target-riscv/fpu-custom-riscv/s_roundPackToF32.c create mode 100755 target-riscv/fpu-custom-riscv/s_roundPackToF64.c create mode 100755 target-riscv/fpu-custom-riscv/s_roundPackToI32.c create mode 100755 target-riscv/fpu-custom-riscv/s_roundPackToI64.c create mode 100755 target-riscv/fpu-custom-riscv/s_roundPackToUI32.c create mode 100755 target-riscv/fpu-custom-riscv/s_roundPackToUI64.c create mode 100755 target-riscv/fpu-custom-riscv/s_shift128ExtraRightJam.c create mode 100755 target-riscv/fpu-custom-riscv/s_shift128RightJam.c create mode 100755 target-riscv/fpu-custom-riscv/s_shift32RightJam.c create mode 100755 target-riscv/fpu-custom-riscv/s_shift64ExtraRightJam.c create mode 100755 target-riscv/fpu-custom-riscv/s_shift64RightJam.c create mode 100755 target-riscv/fpu-custom-riscv/s_shortShift128ExtraRightJam.c create mode 100755 target-riscv/fpu-custom-riscv/s_shortShift128Left.c create mode 100755 target-riscv/fpu-custom-riscv/s_shortShift128Right.c create mode 100755 target-riscv/fpu-custom-riscv/s_shortShift192Left.c create mode 100755 target-riscv/fpu-custom-riscv/s_shortShift32Right1Jam.c create mode 100755 target-riscv/fpu-custom-riscv/s_shortShift64ExtraRightJam.c create mode 100755 target-riscv/fpu-custom-riscv/s_shortShift64RightJam.c create mode 100755 target-riscv/fpu-custom-riscv/s_sub128.c create mode 100755 target-riscv/fpu-custom-riscv/s_sub192.c create mode 100755 target-riscv/fpu-custom-riscv/s_subMagsF32.c create mode 100755 target-riscv/fpu-custom-riscv/s_subMagsF64.c create mode 100644 target-riscv/fpu-custom-riscv/softfloat.ac create mode 100755 target-riscv/fpu-custom-riscv/softfloat.h create mode 100644 target-riscv/fpu-custom-riscv/softfloat.mk.in create mode 100755 target-riscv/fpu-custom-riscv/softfloat_raiseFlags.c create mode 100755 target-riscv/fpu-custom-riscv/softfloat_state.c create mode 100755 target-riscv/fpu-custom-riscv/softfloat_types.h create mode 100755 target-riscv/fpu-custom-riscv/specialize.h create mode 100755 target-riscv/fpu-custom-riscv/ui32_to_f32.c create mode 100755 target-riscv/fpu-custom-riscv/ui32_to_f64.c create mode 100755 target-riscv/fpu-custom-riscv/ui64_to_f32.c create mode 100755 target-riscv/fpu-custom-riscv/ui64_to_f64.c create mode 100644 target-riscv/gdbstub.c create mode 100644 target-riscv/helper.c create mode 100644 target-riscv/helper.h create mode 100644 target-riscv/instmap.h create mode 100644 target-riscv/machine.c create mode 100644 target-riscv/op_helper.c create mode 100644 target-riscv/riscv-defs.h create mode 100644 target-riscv/translate.c create mode 100644 target-riscv/translate_init.c