Repository: agra-uni-bremen/riscv-vp Branch: master Commit: 48b2f5877b23 Files: 513 Total size: 1.5 MB Directory structure: gitextract_zs0_rad3/ ├── .clang-format ├── .gitignore ├── .gitlab-ci.yml ├── .gitmodules ├── CITATION.cff ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── env/ │ └── basic/ │ └── vp-display/ │ ├── CMakeLists.txt │ ├── VP-Display.pro │ ├── framebuffer.h │ ├── main.cpp │ ├── mainwindow.cpp │ ├── mainwindow.h │ ├── mainwindow.ui │ ├── vpdisplayserver.cpp │ └── vpdisplayserver.h ├── sw/ │ ├── .gitignore │ ├── Makefile │ ├── Makefile.common │ ├── README.md │ ├── basic-asm/ │ │ ├── Makefile │ │ └── sum.S │ ├── basic-c/ │ │ ├── Makefile │ │ ├── bootstrap.S │ │ ├── main.c │ │ └── sum.c │ ├── basic-debug/ │ │ ├── Makefile │ │ ├── bootstrap.S │ │ ├── eclipse-remote-debug-readme.txt │ │ ├── main.c │ │ ├── remote-debug-readme.txt │ │ └── test-ignore │ ├── basic-dma/ │ │ ├── Makefile │ │ ├── bootstrap.S │ │ ├── irq.c │ │ ├── irq.h │ │ └── main.c │ ├── basic-e/ │ │ ├── Makefile │ │ └── sum.S │ ├── basic-gcov/ │ │ ├── Makefile │ │ └── test-ignore │ ├── basic-gpio/ │ │ ├── Makefile │ │ ├── bootstrap.S │ │ ├── gpio.h │ │ ├── link.ld │ │ ├── main.c │ │ ├── platform.h │ │ ├── uart.c │ │ ├── uart.h │ │ ├── util.c │ │ └── util.h │ ├── basic-multicore/ │ │ ├── Makefile │ │ ├── bootstrap.S │ │ └── main.c │ ├── blocking-sleep/ │ │ ├── Makefile │ │ ├── bootstrap.S │ │ ├── irq.S │ │ └── main.c │ ├── busy-wait-sleep/ │ │ ├── Makefile │ │ ├── bootstrap.S │ │ └── main.c │ ├── c++-lib/ │ │ ├── Makefile │ │ └── main.cpp │ ├── clock-ticks/ │ │ ├── Makefile │ │ ├── bootstrap.S │ │ ├── irq.c │ │ ├── irq.h │ │ └── main.c │ ├── crc8/ │ │ ├── Makefile │ │ ├── bootstrap.S │ │ ├── link.ld │ │ ├── main.c │ │ ├── platform.h │ │ ├── uart.c │ │ ├── uart.h │ │ ├── util.c │ │ └── util.h │ ├── flashTest/ │ │ ├── Makefile │ │ ├── main.cpp │ │ └── test-ignore │ ├── mramTest/ │ │ ├── Makefile │ │ └── main.cpp │ ├── mrv32-uart/ │ │ ├── Makefile │ │ ├── bootstrap.S │ │ ├── link.ld │ │ ├── main.c │ │ ├── platform.h │ │ ├── uart.c │ │ ├── uart.h │ │ ├── util.c │ │ └── util.h │ ├── peripheral-in-the-loop/ │ │ ├── Makefile │ │ └── main.c │ ├── printf/ │ │ ├── Makefile │ │ ├── entry.S │ │ └── main.c │ ├── simple-display/ │ │ ├── Makefile │ │ ├── libDisplay.cpp │ │ ├── libDisplay.hpp │ │ ├── main.cpp │ │ └── test-ignore │ ├── simple-scheduler/ │ │ ├── Makefile │ │ ├── cor.S │ │ ├── main.c │ │ └── no-clib/ │ │ ├── Makefile │ │ ├── bootstrap.S │ │ ├── cor.S │ │ └── main.c │ ├── simple-sensor/ │ │ ├── Makefile │ │ ├── bootstrap.S │ │ ├── irq.c │ │ ├── irq.h │ │ └── main.c │ ├── sys-read/ │ │ ├── Makefile │ │ ├── main.c │ │ └── test-ignore │ └── test.sh └── vp/ ├── .gitignore ├── CMakeLists.txt ├── cmake/ │ └── AddGitSubmodule.cmake └── src/ ├── CMakeLists.txt ├── core/ │ ├── CMakeLists.txt │ ├── common/ │ │ ├── CMakeLists.txt │ │ ├── bus_lock_if.h │ │ ├── clint.h │ │ ├── clint_if.h │ │ ├── core_defs.h │ │ ├── debug.h │ │ ├── debug_memory.cpp │ │ ├── debug_memory.h │ │ ├── dmi.h │ │ ├── elf_loader.h │ │ ├── fp.h │ │ ├── gdb-mc/ │ │ │ ├── CMakeLists.txt │ │ │ ├── gdb_runner.cpp │ │ │ ├── gdb_runner.h │ │ │ ├── gdb_server.cpp │ │ │ ├── gdb_server.h │ │ │ ├── handler.cpp │ │ │ ├── libgdb/ │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── README.md │ │ │ │ ├── include/ │ │ │ │ │ └── libgdb/ │ │ │ │ │ ├── parser1.h │ │ │ │ │ ├── parser2.h │ │ │ │ │ └── response.h │ │ │ │ ├── internal.h │ │ │ │ ├── parser1.c │ │ │ │ ├── parser2.c │ │ │ │ ├── parser2.h │ │ │ │ ├── response.c │ │ │ │ └── util.c │ │ │ ├── register_format.cpp │ │ │ └── register_format.h │ │ ├── instr.cpp │ │ ├── instr.h │ │ ├── irq_if.h │ │ ├── load_if.h │ │ ├── mmu.h │ │ ├── mmu_mem_if.h │ │ ├── rawmode.cpp │ │ ├── rawmode.h │ │ ├── real_clint.cpp │ │ ├── real_clint.h │ │ ├── timer.cpp │ │ ├── timer.h │ │ └── trap.h │ ├── rv32/ │ │ ├── CMakeLists.txt │ │ ├── csr.h │ │ ├── elf_loader.h │ │ ├── iss.cpp │ │ ├── iss.h │ │ ├── mem.h │ │ ├── mem_if.h │ │ ├── mmu.h │ │ ├── syscall.cpp │ │ ├── syscall.h │ │ ├── syscall_if.h │ │ └── timing/ │ │ ├── timing_external.h │ │ └── timing_simple.h │ └── rv64/ │ ├── CMakeLists.txt │ ├── csr.h │ ├── elf_loader.h │ ├── iss.cpp │ ├── iss.h │ ├── mem.h │ ├── mem_if.h │ ├── mmu.h │ ├── syscall.cpp │ ├── syscall.h │ └── syscall_if.h ├── platform/ │ ├── CMakeLists.txt │ ├── basic/ │ │ ├── CMakeLists.txt │ │ ├── basic_timer.h │ │ ├── display.cpp │ │ ├── display.hpp │ │ ├── dma.h │ │ ├── ethernet.cpp │ │ ├── ethernet.h │ │ ├── flash.h │ │ ├── main.cpp │ │ ├── random_source.h │ │ ├── sensor.h │ │ └── sensor2.h │ ├── common/ │ │ ├── CMakeLists.txt │ │ ├── async_event.h │ │ ├── bus.h │ │ ├── fd_abstract_uart.cpp │ │ ├── fd_abstract_uart.h │ │ ├── fe310_plic.cpp │ │ ├── fe310_plic.h │ │ ├── fu540_plic.cpp │ │ ├── fu540_plic.h │ │ ├── memory.h │ │ ├── memory_mapped_file.h │ │ ├── options.cpp │ │ ├── options.h │ │ ├── slip.cpp │ │ ├── slip.h │ │ ├── terminal.h │ │ ├── uart.cpp │ │ ├── uart.h │ │ ├── uart16550.h │ │ ├── uart_if.cpp │ │ ├── uart_if.h │ │ └── util.h │ ├── hifive/ │ │ ├── CMakeLists.txt │ │ ├── aon.h │ │ ├── can/ │ │ │ ├── 90-slcan.rules │ │ │ ├── CAN-Howto.md │ │ │ ├── cantest.cpp │ │ │ ├── mcp_can_dfs.h │ │ │ ├── slcan_add.sh │ │ │ └── slcan_remove.sh │ │ ├── can.cpp │ │ ├── can.h │ │ ├── gpio.cpp │ │ ├── gpio.h │ │ ├── hifive_main.cpp │ │ ├── maskROM.h │ │ ├── oled/ │ │ │ ├── common.cpp │ │ │ ├── common.hpp │ │ │ ├── oled.cpp │ │ │ └── oled.hpp │ │ ├── otp.h │ │ ├── prci.h │ │ ├── spi.h │ │ ├── tunnel-uart.cpp │ │ └── tunnel-uart.hpp │ ├── hwitl/ │ │ ├── CMakeLists.txt │ │ ├── main.cpp │ │ ├── virtual_bus_tlm_connector.cpp │ │ └── virtual_bus_tlm_connector.hpp │ ├── linux/ │ │ ├── CMakeLists.txt │ │ ├── linux_main.cpp │ │ └── prci.h │ ├── linux32/ │ │ ├── CMakeLists.txt │ │ ├── linux32_main.cpp │ │ └── prci.h │ ├── microrv32/ │ │ ├── CMakeLists.txt │ │ ├── main.cpp │ │ ├── microrv32_gpio.h │ │ ├── microrv32_led.h │ │ └── microrv32_uart.h │ ├── test32/ │ │ ├── CMakeLists.txt │ │ ├── htif.h │ │ └── test32_main.cpp │ ├── tiny32/ │ │ ├── CMakeLists.txt │ │ └── tiny32_main.cpp │ ├── tiny32-mc/ │ │ ├── CMakeLists.txt │ │ └── mc_main.cpp │ ├── tiny64/ │ │ ├── CMakeLists.txt │ │ └── tiny64_main.cpp │ └── tiny64-mc/ │ ├── CMakeLists.txt │ └── mc_main.cpp ├── util/ │ ├── common.h │ ├── elegantEnums.cpp │ ├── elegantEnums.hpp │ ├── gtkwave_riscv-filter/ │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ └── riscv-filter.cpp │ ├── gtkwave_riscv-filter.py │ ├── memory_map.h │ ├── options.h │ └── tlm_map.h └── vendor/ ├── CMakeLists.txt └── softfloat/ ├── CMakeLists.txt ├── f128_add.c ├── f128_classify.c ├── f128_div.c ├── f128_eq.c ├── f128_eq_signaling.c ├── f128_isSignalingNaN.c ├── f128_le.c ├── f128_le_quiet.c ├── f128_lt.c ├── f128_lt_quiet.c ├── f128_mul.c ├── f128_mulAdd.c ├── f128_rem.c ├── f128_roundToInt.c ├── f128_sqrt.c ├── f128_sub.c ├── f128_to_f16.c ├── f128_to_f32.c ├── f128_to_f64.c ├── f128_to_i32.c ├── f128_to_i32_r_minMag.c ├── f128_to_i64.c ├── f128_to_i64_r_minMag.c ├── f128_to_ui32.c ├── f128_to_ui32_r_minMag.c ├── f128_to_ui64.c ├── f128_to_ui64_r_minMag.c ├── f16_add.c ├── f16_div.c ├── f16_eq.c ├── f16_eq_signaling.c ├── f16_isSignalingNaN.c ├── f16_le.c ├── f16_le_quiet.c ├── f16_lt.c ├── f16_lt_quiet.c ├── f16_mul.c ├── f16_mulAdd.c ├── f16_rem.c ├── f16_roundToInt.c ├── f16_sqrt.c ├── f16_sub.c ├── f16_to_f128.c ├── f16_to_f32.c ├── f16_to_f64.c ├── f16_to_i32.c ├── f16_to_i32_r_minMag.c ├── f16_to_i64.c ├── f16_to_i64_r_minMag.c ├── f16_to_ui32.c ├── f16_to_ui32_r_minMag.c ├── f16_to_ui64.c ├── f16_to_ui64_r_minMag.c ├── f32_add.c ├── f32_classify.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_mul.c ├── f32_mulAdd.c ├── f32_rem.c ├── f32_roundToInt.c ├── f32_sqrt.c ├── f32_sub.c ├── f32_to_f128.c ├── f32_to_f16.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 ├── f64_add.c ├── f64_classify.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_mul.c ├── f64_mulAdd.c ├── f64_rem.c ├── f64_roundToInt.c ├── f64_sqrt.c ├── f64_sub.c ├── f64_to_f128.c ├── f64_to_f16.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 ├── i32_to_f128.c ├── i32_to_f16.c ├── i32_to_f32.c ├── i32_to_f64.c ├── i64_to_f128.c ├── i64_to_f16.c ├── i64_to_f32.c ├── i64_to_f64.c ├── include/ │ └── softfloat/ │ ├── internals.h │ ├── platform.h │ ├── primitiveTypes.h │ ├── primitives.h │ ├── softfloat.h │ ├── softfloat.hpp │ ├── softfloat_types.h │ └── specialize.h ├── s_add128.c ├── s_add256M.c ├── s_addCarryM.c ├── s_addComplCarryM.c ├── s_addM.c ├── s_addMagsF128.c ├── s_addMagsF16.c ├── s_addMagsF32.c ├── s_addMagsF64.c ├── s_approxRecip32_1.c ├── s_approxRecipSqrt32_1.c ├── s_approxRecipSqrt_1Ks.c ├── s_approxRecip_1Ks.c ├── s_commonNaNToF128UI.c ├── s_commonNaNToF16UI.c ├── s_commonNaNToF32UI.c ├── s_commonNaNToF64UI.c ├── s_compare128M.c ├── s_compare96M.c ├── s_countLeadingZeros16.c ├── s_countLeadingZeros32.c ├── s_countLeadingZeros64.c ├── s_countLeadingZeros8.c ├── s_eq128.c ├── s_f128UIToCommonNaN.c ├── s_f16UIToCommonNaN.c ├── s_f32UIToCommonNaN.c ├── s_f64UIToCommonNaN.c ├── s_le128.c ├── s_lt128.c ├── s_mul128By32.c ├── s_mul128MTo256M.c ├── s_mul128To256M.c ├── s_mul64ByShifted32To128.c ├── s_mul64To128.c ├── s_mul64To128M.c ├── s_mulAddF128.c ├── s_mulAddF16.c ├── s_mulAddF32.c ├── s_mulAddF64.c ├── s_negXM.c ├── s_normRoundPackToF128.c ├── s_normRoundPackToF16.c ├── s_normRoundPackToF32.c ├── s_normRoundPackToF64.c ├── s_normSubnormalF128Sig.c ├── s_normSubnormalF16Sig.c ├── s_normSubnormalF32Sig.c ├── s_normSubnormalF64Sig.c ├── s_propagateNaNF128UI.c ├── s_propagateNaNF16UI.c ├── s_propagateNaNF32UI.c ├── s_propagateNaNF64UI.c ├── s_remStepMBy32.c ├── s_roundMToI64.c ├── s_roundMToUI64.c ├── s_roundPackMToI64.c ├── s_roundPackMToUI64.c ├── s_roundPackToF128.c ├── s_roundPackToF16.c ├── s_roundPackToF32.c ├── s_roundPackToF64.c ├── s_roundPackToI32.c ├── s_roundPackToI64.c ├── s_roundPackToUI32.c ├── s_roundPackToUI64.c ├── s_roundToI32.c ├── s_roundToI64.c ├── s_roundToUI32.c ├── s_roundToUI64.c ├── s_shiftRightJam128.c ├── s_shiftRightJam128Extra.c ├── s_shiftRightJam256M.c ├── s_shiftRightJam32.c ├── s_shiftRightJam64.c ├── s_shiftRightJam64Extra.c ├── s_shortShiftLeft128.c ├── s_shortShiftLeft64To96M.c ├── s_shortShiftRight128.c ├── s_shortShiftRightExtendM.c ├── s_shortShiftRightJam128.c ├── s_shortShiftRightJam128Extra.c ├── s_shortShiftRightJam64.c ├── s_shortShiftRightJam64Extra.c ├── s_shortShiftRightM.c ├── s_sub128.c ├── s_sub1XM.c ├── s_sub256M.c ├── s_subM.c ├── s_subMagsF128.c ├── s_subMagsF16.c ├── s_subMagsF32.c ├── s_subMagsF64.c ├── softfloat_raiseFlags.c ├── softfloat_state.c ├── ui32_to_f128.c ├── ui32_to_f16.c ├── ui32_to_f32.c ├── ui32_to_f64.c ├── ui64_to_f128.c ├── ui64_to_f16.c ├── ui64_to_f32.c └── ui64_to_f64.c ================================================ FILE CONTENTS ================================================ ================================================ FILE: .clang-format ================================================ --- BasedOnStyle: Google ColumnLimit: '120' AllowShortCaseLabelsOnASingleLine: 'false' AllowShortFunctionsOnASingleLine: Empty AllowShortIfStatementsOnASingleLine: 'false' IndentWidth: '4' TabWidth: '4' UseTab: ForIndentation ... ================================================ FILE: .gitignore ================================================ .cproject .project .settings/ main build/ vp/dependencies/systemc-dist/ *.bin systemc-* *.asm **/nbproject/private/ **/nbproject/Makefile-*.mk **/nbproject/Package-*.bash build/ nbbuild/ dist/ nbdist/ .nb-gradle/ nbproject/ sw/basic-gcov/main.* sw/**/*.o ================================================ FILE: .gitlab-ci.yml ================================================ image: alpine:3.19 variables: GIT_SUBMODULE_STRATEGY: recursive cache: key: $CI_COMMIT_REF_SLUG paths: - vp/build default: before_script: - apk update && apk add --no-cache build-base git boost-dev cmake git gdb-multiarch g++-riscv-none-elf gcc-riscv-none-elf newlib-riscv-none-elf valgrind socat - export RISCV_PREFIX=riscv-none-elf- build-vp: stage: build script: - sh -c 'env MAKEFLAGS=-j$(nproc) make' artifacts: paths: - vp/build/bin expire_in: 24h only: - master - merge_requests test-vp: stage: test script: - cd vp/build - ctest -V only: - master - merge_requests ================================================ FILE: .gitmodules ================================================ [submodule "vp/src/core/common/gdb-mc/parser/mpc"] path = vp/src/core/common/gdb-mc/libgdb/mpc url = https://github.com/orangeduck/mpc [submodule "tests/integration"] path = vp/tests url = https://github.com/agra-uni-bremen/vp-integration-tests.git [submodule "vp/src/platform/hwitl/virtual-bus"] path = vp/src/platform/hwitl/virtual-bus url = https://github.com/agra-uni-bremen/virtual-bus [submodule "vp/src/platform/hifive/vbb-protocol"] path = vp/src/platform/hifive/vbb-protocol url = https://github.com/agra-uni-bremen/virtual-breadboard-protocol.git [submodule "vp/src/vendor/systemc"] path = vp/src/vendor/systemc url = https://github.com/accellera-official/systemc.git ================================================ FILE: CITATION.cff ================================================ # This CITATION.cff file was generated with cffinit. # Visit https://bit.ly/cffinit to generate yours today! cff-version: 1.2.0 title: RISC-V VP message: >- If you want to cite this software, please use the metadata from this file. type: software authors: - given-names: Vladimir family-names: Herdt email: riscv@informatik.uni-bremen.de affiliation: University of Bremen orcid: 'https://orcid.org/0000-0002-4481-057X' - given-names: Group of Computer Architecture email: riscv@informatik.uni-bremen.de affiliation: University of Bremen - given-names: Rolf family-names: Drechsler email: drechsler@uni-bremen.de affiliation: University of Bremen orcid: 'https://orcid.org/0000-0002-9872-1740' identifiers: - type: doi value: 10.1016/j.sysarc.2020.101756 description: >- RISC-V based virtual prototype: An extensible and configurable platform for the system-level repository-code: 'hhttps://github.com/agra-uni-bremen/riscv-vp' abstract: >- RISC-V based virtual prototype: An extensible and configurable platform for the system-level license: MIT ================================================ FILE: Dockerfile ================================================ # XXX: Need Alpine Linux Edge since the latest release (3.19) # only ships SystemC 2.3.3 and does hence not support aarch64. FROM alpine:edge RUN apk update && apk add --no-cache build-base cmake boost-dev \ systemc-dev systemc-static git gcc-riscv-none-elf \ g++-riscv-none-elf newlib-riscv-none-elf gdb-multiarch RUN adduser -G users -g 'RISC-V VP User' -D riscv-vp ADD --chown=riscv-vp:users . /home/riscv-vp/riscv-vp RUN su - riscv-vp -c 'env USE_SYSTEM_SYSTEMC=ON MAKEFLAGS="-j$(nproc)" make -C /home/riscv-vp/riscv-vp' RUN su - riscv-vp -c 'echo export RISCV_PREFIX=\"riscv-none-elf-\" >> /home/riscv-vp/.profile' RUN su - riscv-vp -c 'echo export PATH=\"$PATH:/home/riscv-vp/riscv-vp/vp/build/bin\" >> /home/riscv-vp/.profile' CMD su - riscv-vp ================================================ FILE: LICENSE ================================================ Copyright (c) 2017-2018 Group of Computer Architecture, University of Bremen 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. ================================================ FILE: Makefile ================================================ MAKEFLAGS += --no-print-directory # Whether to use a system-wide SystemC library instead of the vendored one. USE_SYSTEM_SYSTEMC ?= OFF vps: vp/src/core/common/gdb-mc/libgdb/mpc/mpc.c vp/build/Makefile $(MAKE) install -C vp/build vp/src/core/common/gdb-mc/libgdb/mpc/mpc.c: git submodule update --init vp/src/core/common/gdb-mc/libgdb/mpc all: vps vp-display vp/build/Makefile: mkdir -p vp/build cd vp/build && cmake -DUSE_SYSTEM_SYSTEMC=$(USE_SYSTEM_SYSTEMC) .. vp-eclipse: mkdir -p vp-eclipse cd vp-eclipse && cmake ../vp/ -G "Eclipse CDT4 - Unix Makefiles" env/basic/vp-display/build/Makefile: mkdir -p env/basic/vp-display/build cd env/basic/vp-display/build && cmake .. vp-display: env/basic/vp-display/build/Makefile $(MAKE) -C env/basic/vp-display/build vp-clean: rm -rf vp/build qt-clean: rm -rf env/basic/vp-display/build clean-all: vp-clean qt-clean clean: vp-clean codestyle: find . -type d \( -name .git -o -name dependencies \) -prune -o -name '*.h' -o -name '*.hpp' -o -name '*.cpp' -print | xargs clang-format -i -style=file ================================================ FILE: README.md ================================================ # RISC-V based Virtual Prototype (VP)

RISC-V based Virtual Prototype (VP)

### Key features of our VP: - RV32GC and RV64GC core support (i.e. RV32IMAFDC and RV64IMAFDC) - Implemented in SystemC TLM-2.0 - SW debug capabilities (GDB RSP interface) with Eclipse - Virtual Breadboard GUI (interactive IO) featuring C++ and Lua modeled digital devices (separate repository) - FreeRTOS, RIOT, Zephyr, Linux support - Generic and configurable bus - CLINT and PLIC-based interrupt controller + additional peripherals - Instruction-based timing model + annotated TLM 2.0 transaction delays - Peripherals, e.g. display, flash controller, preliminary ethernet - Example configuration for the SiFive HiFive1 (currently only Rev. A) board available - Support for simulation of multi-core platforms - Machine-, Supervisor- and User-mode (including user traps) privilege levels and CSRs - Virtual memory support (Sv32, Sv39, Sv48) For related information, e.g. verification, please visit https://www.informatik.uni-bremen.de/agra/projects/risc-v/ or contact . We accept pull requests and in general contributions are very welcome. If you are using the RISC-V VP in a scientific paper, please cite https://doi.org/10.1016/j.sysarc.2020.101756. For the Virtual Breadboard GUI, please refer to https://www.mdpi.com/2079-9268/12/4/52. In the following we provide build instructions and how to compile and run software on the VP. #### 1) Build requirements Mainly the usual build tools and boost is required: On Ubuntu 20, install these: ```bash sudo apt-get install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo libgoogle-perftools-dev libtool patchutils bc zlib1g-dev libexpat-dev libboost-iostreams-dev libboost-program-options-dev libboost-log-dev qt5-default ``` On Fedora, following actions are required: ```bash sudo dnf install autoconf automake curl libmpc-devel mpfr-devel gmp-devel gawk bison flex texinfo gperf libtool patchutils bc zlib-devel expat-devel cmake boost-devel qt5-qtbase qt5-qtbase-devel sudo dnf groupinstall "C Development Tools and Libraries" #optional debuginfo sudo dnf debuginfo-install boost-iostreams boost-program-options boost-regex bzip2-libs glibc libgcc libicu libstdc++ zlib ``` #### 2) Build this RISC-V Virtual Prototype: Check out all submodules (`git submodule update --init --recursive`), and type `make all`. This script does the following for you: > >i) in *vp/dependencies* folder (will download and compile SystemC, and build a local version of the softfloat library): > >```bash >./build_systemc_233.sh >./build_softfloat.sh >``` > > >ii) in *vp* folder (requires the *boost* C++ library): > >```bash >mkdir build >cd build >cmake .. >make install >``` #### 3) Building the interactive environment GUI (`vp-breadboard`) The GUI for interacting with the VP has moved to [https://github.com/agra-uni-bremen/virtual-breadboard](https://github.com/agra-uni-bremen/virtual-breadboard). #### 3) Building SW examples using the GNU toolchain ##### Requirements In order to test the software examples, a configured RISC-V GNU toolchain is required in your `$PATH`. Several standard packages are required to build the toolchain. For more information on prerequisites for the RISC-V GNU toolchain visit https://github.com/riscv/riscv-gnu-toolchain. With the packages installed, the toolchain can be build as follows: ```bash # in some source folder git clone https://github.com/riscv/riscv-gnu-toolchain.git cd riscv-gnu-toolchain git submodule update --init --recursive # this may take a while ./configure --prefix=$(pwd)/../riscv-gnu-toolchain-dist-rv32imac-ilp32 --with-arch=rv32imac --with-abi=ilp32 make -j$(nproc) ``` If wanted, move the `riscv-gnu-toolchain-dist-rv32imac-ilp32` folder to your `/opt/` folder and add it to your path in your `~/.bashrc` (e.g. `PATH=$PATH:/opt/riscv-gnu-toolchain-dist-rv32imac-ilp32/bin`) ##### Running the examples In *sw*: ```bash cd simple-sensor # can be replaced with different example make # (requires RISC-V GNU toolchain in PATH) make sim # (requires *riscv-vp*, i.e. *vp/build/bin/riscv-vp*, executable in PATH) ``` Please note, if *make* is called without the *install* argument in step 2, then the *riscv-vp* executable is available in *vp/build/src/platform/basic/riscv-vp*. This will also copy the VP binaries into the *vp/build/bin* folder. #### Alternative Setup: Docker Instead of compiling the riscv-vp manually, a `Dockerfile` is also provided which eases this process. In order to build a Docker image from this file run the following command: $ docker build -t riscv-vp . Afterwards, start a new Docker container using: $ docker run --rm -it riscv-vp Within this Docker container, the riscv-vp source tree is available in `/home/riscv-vp/riscv-vp/`. A RISC-V cross compiler toolchain is also part of the container. As such, it is possible to compile and run any of the examples from the `./sw` subdirectory in this container. For example: $ cd /home/riscv-vp/riscv-vp/sw/basic-c/ $ make $ make sim #### FAQ **Q:** How do I exit the VP? **A:** All VPs use the input TTY in raw mode and forward all control characters to the guest. For this reason, one cannot use Ctrl-c to exit the VP. Instead, press Ctrl-a to enter command mode and press Ctrl-x to exit the VP. **Q:** How do I emit a Ctrl-a control character? **A:** Enter control mode using Ctrl-a and press Ctrl-a again to send a literal Ctrl-a control character to the guest. #### Acknowledgements: This work was supported in part by the German Federal Ministry of Education and Research (BMBF) within the project CONFIRM under contract no. 16ES0565 and within the project SATiSFy under contract no. 16KIS0821K and within the project VerSys under contract no. 01IW19001 and within the project Scale4Edge under contract no. 16ME0127, and by the University of Bremen’s graduate school SyDe, funded by the German Excellence Initiative. ================================================ FILE: env/basic/vp-display/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.1.0) project(vp-display) # Your project name set(CMAKE_CXX_STANDARD 11) # This is equal to QMAKE_CXX_FLAGS += -std=c++0x # Find includes in corresponding build directories set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) find_package(Qt5Widgets CONFIG REQUIRED) set(SOURCES main.cpp mainwindow.cpp vpdisplayserver.cpp ) set(HEADERS mainwindow.h vpdisplayserver.h framebuffer.h ) set(UI mainwindow.ui) add_executable(vp-display ${SOURCES} ${HEADERS} ${UI}) target_link_libraries(vp-display Qt5::Widgets pthread) ================================================ FILE: env/basic/vp-display/VP-Display.pro ================================================ #------------------------------------------------- # # Project created by QtCreator 2018-09-10T15:30:06 # #------------------------------------------------- QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = VP-Display TEMPLATE = app CONFIG += c++11 # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ mainwindow.cpp \ vpdisplayserver.cpp HEADERS += \ mainwindow.h \ vpdisplayserver.h \ framebuffer.h FORMS += \ mainwindow.ui ================================================ FILE: env/basic/vp-display/framebuffer.h ================================================ #pragma once #include #include #include #define SHMKEY 1338 struct Framebuffer { static constexpr uint16_t screenWidth = 800; static constexpr uint16_t screenHeight = 600; typedef uint16_t Color; struct Point { uint32_t x; uint32_t y; inline Point() : x(0), y(0){}; inline Point(uint32_t x, uint32_t y) : x(x), y(y){}; }; struct PointF { float x; float y; inline PointF() : x(0), y(0){}; inline PointF(float x, float y) : x(x), y(y){}; inline PointF(Point p) : x(p.x), y(p.y){}; }; struct Frame { Color raw[screenHeight][screenWidth]; // Notice: Screen is on side }; enum class Type : uint8_t { foreground, background }; uint8_t activeFrame; enum class Command : uint8_t { none = 0, clearAll, fillFrame, applyFrame, drawLine, } volatile command; union Parameter { struct { //fillframe Type frame; Color color; } fill; struct { //drawLine Type frame; PointF from; PointF to; Color color; } line; inline Parameter(){}; } parameter; Frame frames[2]; Frame background; Framebuffer() : activeFrame(0), command(Command::none){}; Frame& getActiveFrame() { return frames[activeFrame % 2]; } Frame& getInactiveFrame() { return frames[(activeFrame + 1) % 2]; } Frame& getBackground() { return background; } Frame& getFrame(Type type) { if (type == Type::foreground) return getInactiveFrame(); else if (type == Type::background) return getBackground(); assert(false && "Get invalid frame type"); return background; } }; inline Framebuffer::PointF operator+(const Framebuffer::PointF l, Framebuffer::PointF const r) { return Framebuffer::PointF(l.x + r.x, l.y + r.y); } ================================================ FILE: env/basic/vp-display/main.cpp ================================================ #include #include "mainwindow.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); VPDisplay w; w.show(); return a.exec(); } ================================================ FILE: env/basic/vp-display/mainwindow.cpp ================================================ #include "mainwindow.h" #include #include #include "framebuffer.h" #include "ui_mainwindow.h" VPDisplay::VPDisplay(QWidget* mparent) : QWidget(mparent) { framebuffer = server.createSM(); frame = new QImage(Framebuffer::screenWidth, Framebuffer::screenHeight, QImage::Format_RGB444); // two bytes per pixel resize(Framebuffer::screenWidth, Framebuffer::screenHeight); setFixedSize(size()); server.startListening(std::bind(&VPDisplay::notifyChange, this, std::placeholders::_1)); } VPDisplay::~VPDisplay() { delete frame; } void VPDisplay::drawMainPage(QImage* mem) { Framebuffer::Frame activeFrame = framebuffer->getActiveFrame(); Framebuffer::Frame background = framebuffer->getBackground(); for (int row = 0; row < mem->height(); row++) { uint16_t* line = reinterpret_cast(mem->scanLine(row)); // Two bytes per pixel for (int x = 0; x < mem->width(); x++) { line[x] = activeFrame.raw[row][x] == 0 ? background.raw[row][x] : activeFrame.raw[row][x]; } } } void VPDisplay::paintEvent(QPaintEvent*) { QPainter painter(this); // painter.scale(size_factor, size_factor); // Draw Header // QPainter mempaint(&memory); drawMainPage(frame); painter.drawImage(QPoint(0, 0), *frame); painter.end(); } void VPDisplay::notifyChange(bool success) { assert(success); update(); } ================================================ FILE: env/basic/vp-display/mainwindow.h ================================================ #pragma once #include #include #include "vpdisplayserver.h" namespace Ui { class VPDisplay; } class VPDisplay : public QWidget { Q_OBJECT Framebuffer* framebuffer; QImage* frame; VPDisplayserver server; public: VPDisplay(QWidget* mparent = 0); ~VPDisplay(); void paintEvent(QPaintEvent*); // void keyPressEvent(QKeyEvent *e); void drawMainPage(QImage* mem); void notifyChange(bool success); }; ================================================ FILE: env/basic/vp-display/mainwindow.ui ================================================ MainWindow 0 0 400 300 MainWindow ================================================ FILE: env/basic/vp-display/vpdisplayserver.cpp ================================================ #include "vpdisplayserver.h" #include #include #include #include #include #include VPDisplayserver::VPDisplayserver(unsigned int sharedMemoryKey) : mSharedMemoryKey(sharedMemoryKey), stop(false) {} VPDisplayserver::~VPDisplayserver() { stop.store(true); active_watch.join(); } Framebuffer* VPDisplayserver::createSM() { int shmid; // TODO: Dont create, but check if exists if ((shmid = shmget(mSharedMemoryKey, sizeof(Framebuffer), 0666)) < 0) { perror("shmget"); exit(1); } std::cout << "SHMID: " << shmid << std::endl; framebuffer = reinterpret_cast(shmat(shmid, nullptr, 0)); if (framebuffer == (Framebuffer*)-1) { perror("shmat"); exit(1); } return framebuffer; } void VPDisplayserver::startListening(std::function notifyChange) { // TODO: While loop around buffer changer active_watch = std::thread([=]() { uint8_t lastFrame = -1; while (!stop.load()) { if (framebuffer->activeFrame != lastFrame) { notifyChange(true); lastFrame = framebuffer->activeFrame; } // std::this_thread::sleep_for(std::chrono::milliseconds(100)); } }); notifyChange(true); } ================================================ FILE: env/basic/vp-display/vpdisplayserver.h ================================================ #pragma once #include #include #include #include "framebuffer.h" class VPDisplayserver { unsigned int mSharedMemoryKey; Framebuffer* framebuffer; std::atomic stop; std::thread active_watch; public: VPDisplayserver(unsigned int sharedMemoryKey = 1338); ~VPDisplayserver(); Framebuffer* createSM(); void startListening(std::function notifyChange); }; ================================================ FILE: sw/.gitignore ================================================ main ================================================ FILE: sw/Makefile ================================================ all: find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c "cd '{}' && make" \; clean: find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c "cd '{}' && make clean" \; ================================================ FILE: sw/Makefile.common ================================================ RISCV_PREFIX ?= riscv32-unknown-elf- override CC = $(RISCV_PREFIX)gcc override CXX = $(RISCV_PREFIX)g++ override LD = $(RISCV_PREFIX)gcc ASFLAGS ?= $(CFLAGS) SIM_TARGET ?= sim-default # ISA Version 2.2 is the last version where zicsr is still # supported as part of the base ISA. Use that for now until # _zicsr is widely supported by existing cross-compilers. SUPPORTS_MISA ?= $(shell echo "typedef int dont_be_pedantic;" | $(RISCV_PREFIX)gcc -march=rv32imac -mabi=ilp32 -misa-spec=2.2 -E - > /dev/null 2>&1 && echo 1 || echo 0) ifeq (1,$(SUPPORTS_MISA)) CFLAGS += -misa-spec=2.2 CXXFLAGS += -misa-spec=2.2 endif VP ?= riscv-vp VP_FLAGS ?= --intercept-syscalls --error-on-zero-traphandler=true EXECUTABLE ?= main OBJECTS ?= main.o ######################################################################## $(EXECUTABLE): $(OBJECTS) $(LD) $(CXXFLAGS) $(CFLAGS) -o $@ $(LDFLAGS) $^ $(LDLIBS) %.o: %.S $(CC) $(CPPFLAGS) $(ASFLAGS) -c $< %.o: %.c $(CC) $(CPPFLAGS) $(CFLAGS) -c $< %.o: %.cpp $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< ######################################################################## sim: $(SIM_TARGET) sim-default: $(EXECUTABLE) $(VP) $(VP_FLAGS) $< dump-elf: $(EXECUTABLE) $(RISCV_PREFIX)readelf -a main dump-code: $(EXECUTABLE) $(RISCV_PREFIX)objdump -D main clean: rm -f $(OBJECTS) $(EXECUTABLE) $(CLEAN_EXTRA) .PHONY: sim sim-default dump-elf dump-code clean .DEFAULT_GOAL := $(EXECUTABLE) ================================================ FILE: sw/README.md ================================================ These SW examples demonstrate basic bare-metal applications and applications that use the C-library. In particular, the applications using the C-library require support for system calls (syscalls). Syscalls are handled in one of two ways in the VP: 1) By default the VP will trigger a trap and thus jump to the trap/interrupt handler. The handler will detect that the reason is a syscall and re-direct the syscall to the syscall handler (or some other peripheral) through memory mapped I/O. This requires to provide and setup a trap handler. This can be done by providing a custom entry-point that performs the required setup and then jumps to the crt0.S entry code of the C-library (which in turn will call the main function). The *printf* SW example demonstrates this case. 2) With the "--intercept-syscalls" command line argument, the VP will directly intercept and handle syscalls, hence it is not necessary to setup a trap handler. Thus, no designated startup code (i.e. bootstrap.S) is required to run applications that use the C-library. For example see the *c++-lib* SW example. The provided SW examples demonstrate both approaches for dealing with syscalls. The VP also supports the FreeRTOS (see https://github.com/agra-uni-bremen/riscv-freertos) and Zephyr (see https://www.zephyrproject.org/ - use the Zephyr *hifive* board option when building Zephyr applications and use the *hifive-vp* configuration for executing them) operating systems. ================================================ FILE: sw/basic-asm/Makefile ================================================ OBJECTS = sum.o CFLAGS = -march=rv32i -mabi=ilp32 LDFLAGS = -nostartfiles -Wl,--no-relax VP_FLAGS = --error-on-zero-traphandler=true include ../Makefile.common ================================================ FILE: sw/basic-asm/sum.S ================================================ .globl _start .equ SYSCALL_ADDR, 0x02010000 .macro SYS_EXIT, exit_code li a7, 93 li a0, \exit_code li t0, SYSCALL_ADDR csrr a6, mhartid sw a6, 0(t0) .endm # program entry-point _start: li a0,50 li a1,100 li a2,0 loop: bgt a0,a1,end add a2,a2,a0 addi a0,a0,1 j loop end: # call exit (SYS_EXIT=93) with exit code 0 (argument in a0) SYS_EXIT 0 ================================================ FILE: sw/basic-c/Makefile ================================================ OBJECTS = main.o sum.o bootstrap.o CFLAGS = -march=rv32i -mabi=ilp32 LDFLAGS = -nostartfiles -Wl,--no-relax include ../Makefile.common ================================================ FILE: sw/basic-c/bootstrap.S ================================================ .globl _start .globl main _start: jal main # call exit (SYS_EXIT=93) with exit code 0 (argument in a0) li a7,93 li a0,0 ecall ================================================ FILE: sw/basic-c/main.c ================================================ int sum(int end); int x = 5; int y; int main() { int a = 6; int b = 7; a = a + b + x + y; a = sum(a); return a; } ================================================ FILE: sw/basic-c/sum.c ================================================ int sum(int end) { int ans = end; for (int i=1; i New -> Makefile Project with Existing Code Select the software folder containing the Makefile Run -> Debug Configurations ... C/C++ Remote Application (List Entry on the left side): Click "New" Button Main Tab - C/C++ Application Name: Enter name, typically "main" - Using GDB (DSF) Automatic Remote Launcher: Click "Select other" -> Use configuration specific settings -> GDB (DSF) Manual Remote Debug Launcher Debugger Tab - GDB debugger: riscv32-unknown-elf-gdb [Sub-tab Main] - Connection: Port Number 5005 [Sub-tab Connection] Click "Debug" Button (lower right corner) to start debugging -> Launch the VP in debug mode first: riscv-vp --debug-mode main -> Perhaps it is necessary to refresh the Eclipse project view in case the executable (typically main) cannot be found (the "Debug" button is greyed out in this case) ================================================ FILE: sw/basic-debug/main.c ================================================ int x = 5; int y; int f(int a, int b) { if (a > 0) { int ans = a + b; return ans; } a = -a; return b + a; } int main() { int a = 5; int b = 3; b--; a = a / b; a = a * 2; a = f(x, y); return a; } ================================================ FILE: sw/basic-debug/remote-debug-readme.txt ================================================ In the first terminal run our VP in debug mode (wraps the core iss in a debug stub): riscv-vp --debug-mode --intercept-syscalls main In the other terminal run: riscv32-unknown-elf-gdb Inside of gdb then (for example): file main target remote :5005 b main.c:14 continue p x p y step continue This will load the symbols from the *main* elf file (note: this one should match the one loaded in our VP). The *target remote* command is passed host and port number. In this case localhost is used. Note: you can use 'set debug remote 1' in gdb to observe the packets send and received by gdb (might be useful for debugging). ================================================ FILE: sw/basic-debug/test-ignore ================================================ ================================================ FILE: sw/basic-dma/Makefile ================================================ OBJECTS = main.o irq.o bootstrap.o CFLAGS = -march=rv32imac -mabi=ilp32 LDFLAGS = -nostartfiles -Wl,--no-relax include ../Makefile.common ================================================ FILE: sw/basic-dma/bootstrap.S ================================================ .globl _start .globl init .globl main .globl level_1_interrupt_handler .equ PLIC_ENABLED_IRQ_ADDR, 0x40002000 _start: jal init la t0, level_0_interrupt_handler csrw mtvec, t0 li t1, 0x888 csrw mie, t1 csrwi mstatus, 8 li t0, PLIC_ENABLED_IRQ_ADDR li t1, -1 sw t1, 0(t0) sw t1, 4(t0) jal main # call exit (SYS_EXIT=93) with exit code 0 (argument in a0) li a7,93 li a0,0 ecall /* * Interrupt handler for non-nested interrupts. Only selected registers are stored/re-stored, i.e. those not preserved on function calls. */ #define STORE sw #define LOAD lw #define REGBYTES 4 .align 4 level_0_interrupt_handler: // store execution context on the stack (register content) addi sp, sp, -REGBYTES * 32 STORE x1, 0x0(sp) STORE x4, 3 * REGBYTES(sp) STORE x5, 4 * REGBYTES(sp) STORE x6, 5 * REGBYTES(sp) STORE x7, 6 * REGBYTES(sp) STORE x10, 9 * REGBYTES(sp) STORE x11, 10 * REGBYTES(sp) STORE x12, 11 * REGBYTES(sp) STORE x13, 12 * REGBYTES(sp) STORE x14, 13 * REGBYTES(sp) STORE x15, 14 * REGBYTES(sp) STORE x16, 15 * REGBYTES(sp) STORE x17, 16 * REGBYTES(sp) STORE x28, 27 * REGBYTES(sp) STORE x29, 28 * REGBYTES(sp) STORE x30, 29 * REGBYTES(sp) STORE x31, 30 * REGBYTES(sp) // load interrupt/trap reason and call external C function to handle it csrr a0, mcause jal level_1_interrupt_handler // re-store the saved context LOAD x1, 0x0(sp) LOAD x4, 3 * REGBYTES(sp) LOAD x5, 4 * REGBYTES(sp) LOAD x6, 5 * REGBYTES(sp) LOAD x7, 6 * REGBYTES(sp) LOAD x10, 9 * REGBYTES(sp) LOAD x11, 10 * REGBYTES(sp) LOAD x12, 11 * REGBYTES(sp) LOAD x13, 12 * REGBYTES(sp) LOAD x14, 13 * REGBYTES(sp) LOAD x15, 14 * REGBYTES(sp) LOAD x16, 15 * REGBYTES(sp) LOAD x17, 16 * REGBYTES(sp) LOAD x28, 27 * REGBYTES(sp) LOAD x29, 28 * REGBYTES(sp) LOAD x30, 29 * REGBYTES(sp) LOAD x31, 30 * REGBYTES(sp) addi sp, sp, REGBYTES * 32 mret ================================================ FILE: sw/basic-dma/irq.c ================================================ #include "irq.h" #include "assert.h" #define RISCV_MACHINE_SOFTWARE_INTERRUPT 3 #define RISCV_MACHINE_TIMER_INTERRUPT 7 #define RISCV_MACHINE_EXTERNAL_INTERRUPT 11 #define PLIC_BASE 0x40000000 #define IRQ_TABLE_NUM_ENTRIES 64 static volatile uint32_t * const PLIC_INTERRUPT_ENABLE_START = (uint32_t * const)(PLIC_BASE + 0x2000); static volatile uint32_t * const PLIC_CLAIM_AND_RESPONSE_REGISTER = (uint32_t * const)(PLIC_BASE + 0x200004); static void irq_empty_handler() {} static irq_handler_t irq_handler_table[IRQ_TABLE_NUM_ENTRIES] = { [ 0 ... IRQ_TABLE_NUM_ENTRIES-1 ] = irq_empty_handler }; #define CLINT_BASE 0x2000000 volatile uint64_t* mtime = (uint64_t*)(CLINT_BASE + 0xbff8); volatile uint64_t* mtimecmp = (uint64_t*)(CLINT_BASE + 0x4000); static irq_handler_t timer_irq_handler = 0; void level_1_interrupt_handler(uint32_t cause) { switch (cause & 0xf) { case RISCV_MACHINE_EXTERNAL_INTERRUPT: { asm volatile ("csrc mip, %0" : : "r" (0x800)); uint32_t irq_id = *PLIC_CLAIM_AND_RESPONSE_REGISTER; irq_handler_table[irq_id](); *PLIC_CLAIM_AND_RESPONSE_REGISTER = 1; return; } case RISCV_MACHINE_TIMER_INTERRUPT: { // Note: the pending timer interrupt bit will be automatically cleared when writing to the *mtimecmp* register of this hart if (timer_irq_handler) { // let the user registered handler clear the timer interrupt bit timer_irq_handler(); } else { // reset the *mtimecmp* register to zero to clear the pending bit *mtimecmp = 0; } return; } } assert (0 && "unsupported cause"); } void register_interrupt_handler(uint32_t irq_id, irq_handler_t fn) { assert (irq_id < IRQ_TABLE_NUM_ENTRIES); // enable interrupt volatile uint32_t* const reg = (PLIC_INTERRUPT_ENABLE_START + irq_id/32); *reg |= 1 << (irq_id%32); // set a prio different to zero (which means do-not-interrupt) *((uint32_t*) (PLIC_BASE + irq_id*sizeof(uint32_t))) = 1; irq_handler_table[irq_id] = fn; } void register_timer_interrupt_handler(irq_handler_t fn) { timer_irq_handler = fn; } ================================================ FILE: sw/basic-dma/irq.h ================================================ #ifndef __RISCV_IRQ_H__ #define __RISCV_IRQ_H__ #include "stdint.h" typedef void (*irq_handler_t)(void); void register_interrupt_handler(uint32_t irq_id, irq_handler_t fn); void register_timer_interrupt_handler(irq_handler_t fn); extern volatile uint64_t* mtime; extern volatile uint64_t* mtimecmp; #endif ================================================ FILE: sw/basic-dma/main.c ================================================ #include "stdint.h" #include "irq.h" static volatile char * const TERMINAL_ADDR = (char * const)0x20000000; static volatile uint32_t * const DMA_SRC_ADDR = (uint32_t * const)0x70000000; static volatile uint32_t * const DMA_DST_ADDR = (uint32_t * const)0x70000004; static volatile uint32_t * const DMA_LEN_ADDR = (uint32_t * const)0x70000008; static volatile uint32_t * const DMA_OP_ADDR = (uint32_t * const)0x7000000C; static volatile uint32_t * const DMA_STAT_ADDR = (uint32_t * const)0x70000010; static const uint32_t DMA_OP_NOP = 0; static const uint32_t DMA_OP_MEMCPY = 1; volatile _Bool dma_completed = 0; void dma_irq_handler() { dma_completed = 1; } void init() { register_interrupt_handler(4, dma_irq_handler); } int main() { uint8_t src[32] = { [ 0 ... 31 ] = 70 }; uint8_t dst[32] = { 0 }; dma_completed = 0; *DMA_SRC_ADDR = (uint32_t)(&src[0]); *DMA_DST_ADDR = (uint32_t)(&dst[0]); *DMA_LEN_ADDR = sizeof(src); *DMA_OP_ADDR = DMA_OP_MEMCPY; while (!dma_completed) { asm volatile ("wfi"); } for (int i=0; i<32; ++i) { *TERMINAL_ADDR = dst[i]; } *TERMINAL_ADDR = '\n'; return 0; } ================================================ FILE: sw/basic-e/Makefile ================================================ OBJECTS = sum.o CFLAGS = -march=rv32e -mabi=ilp32e LDFLAGS = -nostartfiles -Wl,--no-relax VP_FLAGS = --use-E-base-isa --error-on-zero-traphandler=true include ../Makefile.common ================================================ FILE: sw/basic-e/sum.S ================================================ .globl _start .equ SYSCALL_ADDR, 0x02010000 .macro SYS_EXIT, exit_code li a5, 93 li a0, \exit_code li t0, SYSCALL_ADDR csrr t1, mhartid sw t1, 0(t0) .endm # program entry-point _start: li a0,50 li a1,100 li a2,0 loop: bgt a0,a1,end add a2,a2,a0 addi a0,a0,1 j loop end: # call exit (SYS_EXIT=93) with exit code 0 (argument in a0) SYS_EXIT 0 ================================================ FILE: sw/basic-gcov/Makefile ================================================ OBJECTS = main.o CFLAGS = --coverage -march=rv32ima -mabi=ilp32 LDFLAGS = --coverage VP_FLAGS = --error-on-zero-traphandler=true CLEAN_EXTRA = main.c.gcov main.gcda main.gcno cov*.html main.gcda: main riscv-vp --intercept-syscalls --error-on-zero-traphandler=true main # use -b option to display branch coverage too dump-coverage: main.gcda $(RISCV_PREFIX)gcov main.c dump-html-coverage: main.gcda gcovr --gcov-executable $(RISCV_PREFIX)gcov -b -r . --html-details -o cov.html include ../Makefile.common .DEFAULT_GOAL := main.gcda ================================================ FILE: sw/basic-gcov/test-ignore ================================================ ================================================ FILE: sw/basic-gpio/Makefile ================================================ OBJECTS = bootstrap.o main.o uart.o CFLAGS = -g3 -march=rv32i -mabi=ilp32 LDLIBS = -Tlink.ld -nostartfiles -Wl,--no-relax VP = microrv32-vp VP_FLAGS = hex: $(EXECUTABLE) ../elf2bin.py ./main gpio.hex 0x4020 include ../Makefile.common ================================================ FILE: sw/basic-gpio/bootstrap.S ================================================ .globl _start .globl main .equ SYSCALL_ADDR, 0x02010000 .macro INIT_HW_PLATFORM and x1,x0,x0 and x2,x0,x0 and x3,x0,x0 and x4,x0,x0 and x5,x0,x0 and x6,x0,x0 and x7,x0,x0 and x8,x0,x0 and x9,x0,x0 and x10,x0,x0 and x11,x0,x0 and x12,x0,x0 and x13,x0,x0 and x14,x0,x0 and x15,x0,x0 and x16,x0,x0 and x17,x0,x0 and x18,x0,x0 and x19,x0,x0 and x20,x0,x0 and x21,x0,x0 and x22,x0,x0 and x23,x0,x0 and x24,x0,x0 and x25,x0,x0 and x26,x0,x0 and x27,x0,x0 and x28,x0,x0 and x29,x0,x0 and x30,x0,x0 and x31,x0,x0 .endm .macro SYS_EXIT, exit_code li a7, 93 li a0, \exit_code li t0, SYSCALL_ADDR csrr a6, mhartid sw a6, 0(t0) .endm # .macro SYS_EXIT, exit_code # li a7, 93 # li a0, \exit_code # li t0, SYSCALL_ADDR # sw a7, 0(t0) # .endm _start: # initialize hw-platform INIT_HW_PLATFORM la sp, stack_end jal main # call exit (SYS_EXIT=93) with exit code 0 (argument in a0) SYS_EXIT 0 .align 4 stack_begin: .zero 1024 stack_end: ================================================ FILE: sw/basic-gpio/gpio.h ================================================ #ifndef GPIO_H #define GPIO_H #endif /* GPIO_H */ ================================================ FILE: sw/basic-gpio/link.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; .text.init : { *(.text.init) } . = ALIGN(0x1000); .tohost : { *(.tohost) } . = ALIGN(0x1000); .text : { *(.text) } . = ALIGN(0x1000); .data : { *(.data) } .bss : { *(.bss) } _end = .; } ================================================ FILE: sw/basic-gpio/main.c ================================================ #include #include #include "platform.h" #include "uart.h" #include "util.h" //#include "gpio.h" void wait(uint32_t nOps) { /* * TODO correlate nOps to clocks/time waited */ for(uint32_t i = 0; i < nOps; i++) { asm("nop"); } } int main(int argc, char **argv) { uint8_t val = 1; *GPIO_BANK_A_DIRECTION_ADDR = 0x000000ff; // set all pins to output *GPIO_BANK_A_OUTPUT_ADDR = 0x01; // output 0x01 to all 8 pins of gpio bank A wait(10); *LED_ADDR = 0x05; wait(10); *LED_ADDR = 0x0A; wait(10); // bit shift pattern until only 0x55 and 0xAA are present for(uint8_t i=0; i<10; i++) { *GPIO_BANK_A_OUTPUT_ADDR = val; wait(10); val = (val << 1) | (i & 1); } *LED_ADDR = 0x0A; return 0; } ================================================ FILE: sw/basic-gpio/platform.h ================================================ #ifndef PLATFORM_H #define PLATFORM_H //#define MICRORV #ifdef MICRORV // LED static volatile uint32_t *LED_ADDR = (uint32_t *)0x81000000; // UART static volatile uint32_t *UART_TX_DATA_ADDR = (uint32_t *)0x82000000; static volatile uint32_t *UART_TX_CTRL_ADDR = (uint32_t *)0x82000004; static volatile uint32_t *UART_RX_DATA_ADDR = (uint32_t *)0x82000008; // CLIC static volatile uint64_t *MTIMECMP_REG = (uint64_t *)0x02004000; static volatile uint64_t *MTIME_REG = (uint64_t *)0x0200bff8; // GPIO static volatile uint32_t *GPIO_BANK_A_DIRECTION_ADDR = (uint32_t *)0x83000000; static volatile uint32_t *GPIO_BANK_A_OUTPUT_ADDR = (uint32_t *)0x83000004; static volatile uint32_t *GPIO_BANK_A_INPUT_ADDR = (uint32_t *)0x83000008; #else // LED static volatile uint32_t *LED_ADDR = (uint32_t *)0x81000000; // UART static volatile uint32_t *UART_TX_DATA_ADDR = (uint32_t *)0x82000000; static volatile uint32_t *UART_TX_CTRL_ADDR = (uint32_t *)0x82000004; static volatile uint32_t *UART_RX_DATA_ADDR = (uint32_t *)0x82000008; // CLIC static volatile uint64_t *MTIMECMP_REG = (uint64_t *)0x02004000; static volatile uint64_t *MTIME_REG = (uint64_t *)0x0200bff8; // GPIO static volatile uint32_t *GPIO_BANK_A_DIRECTION_ADDR = (uint32_t *)0x83000000; static volatile uint32_t *GPIO_BANK_A_OUTPUT_ADDR = (uint32_t *)0x83000004; static volatile uint32_t *GPIO_BANK_A_INPUT_ADDR = (uint32_t *)0x83000008; #endif #endif /* PLATFORM_H */ ================================================ FILE: sw/basic-gpio/uart.c ================================================ #include "uart.h" #include "platform.h" #include int sendString(char* str, long len) { long cnt = len; const char *s = (const char *)str; while (cnt > 0) { --cnt; putChr(*s); s++; } return len; } void putChr(char chr) { #ifdef MICRORV uint32_t tx_rdy = 0; *UART_TX_DATA_ADDR = chr; // send character stored in uart_tx_addr *UART_TX_CTRL_ADDR = 1; // wait until tx is ready again for sening another character do { // read uart tx status tx_rdy = *UART_TX_CTRL_ADDR; asm volatile ("nop"); } while(!tx_rdy); #else uint32_t tx_rdy = 0; *UART_TX_DATA_ADDR = chr; // send character stored in uart_tx_addr *UART_TX_CTRL_ADDR = 1; // wait until tx is ready again for sening another character do { // read uart tx status tx_rdy = *UART_TX_CTRL_ADDR; asm volatile ("nop"); } while(!tx_rdy); #endif return; } ================================================ FILE: sw/basic-gpio/uart.h ================================================ #ifndef UART_H #include int sendString(char* str, long len); void putChr(char chr); #endif /* UART_H */ ================================================ FILE: sw/basic-gpio/util.c ================================================ /* * utility functions for embedded usage where c-libs are too big */ //---------------------------- // integer to ascii (itoa) with util functions //---------------------------- // function to swap two numbers void swap(char *x, char *y) { char t = *x; *x = *y; *y = t; } // function to reverse buffer[i..j] char* reverse(char *buffer, int i, int j) { while (i < j) swap(&buffer[i++], &buffer[j--]); return buffer; } // Iterative function to implement itoa() function in C char* itoa(int value, char* buffer, int base) { // invalid input if (base < 2 || base > 32) return buffer; // consider absolute value of number int n = (value < 0) ? -value : value; int i = 0; while (n) { int r = n % base; if (r >= 10) buffer[i++] = 65 + (r - 10); else buffer[i++] = 48 + r; n = n / base; } // if number is 0 if (i == 0) buffer[i++] = '0'; // If base is 10 and value is negative, the resulting string // is preceded with a minus sign (-) // With any other base, value is always considered unsigned if (value < 0 && base == 10) buffer[i++] = '-'; buffer[i] = '\0'; // null terminate string // reverse the string and return it return reverse(buffer, 0, i - 1); } ================================================ FILE: sw/basic-gpio/util.h ================================================ #ifndef UTIL_H void swap(char *x, char *y); char* reverse(char *buffer, int i, int j); char* itoa(int value, char* buffer, int base); #endif /* UTIL_H */ ================================================ FILE: sw/basic-multicore/Makefile ================================================ OBJECTS = main.o bootstrap.o CFLAGS = -march=rv32ima -mabi=ilp32 LDFLAGS = -nostartfiles -Wl,--no-relax VP = tiny32-mc VP_FLAGS = --error-on-zero-traphandler=true include ../Makefile.common ================================================ FILE: sw/basic-multicore/bootstrap.S ================================================ .globl _start .globl main .equ SYSCALL_ADDR, 0x02010000 # NOTE: this will exit the whole simulation, i.e. stop all harts .macro SYS_EXIT, exit_code li a7, 93 li a0, \exit_code li t0, SYSCALL_ADDR csrr a6, mhartid sw a6, 0(t0) .endm # NOTE: each core will start here with execution _start: # initialize global pointer (see crt0.S of the RISC-V newlib C-library port) .option push .option norelax 1:auipc gp, %pcrel_hi(__global_pointer$) addi gp, gp, %pcrel_lo(1b) .option pop csrr a0, mhartid # return a core specific number 0 or 1 li t0, 0 beq a0, t0, core0 li t0, 1 beq a0, t0, core1 core0: la sp, stack0_end # code executed only by core0 j end core1: la sp, stack1_end # code executed only by core1 j end end: jal main # wait until all two cores have finished la t0, exit_counter li t1, 1 li t2, 1 amoadd.w a0, t1, 0(t0) 1: blt a0, t2, 1b # call exit (SYS_EXIT=93) with exit code 0 (argument in a0) SYS_EXIT 0 .align 8 stack0_begin: .zero 32768 stack0_end: .align 8 stack1_begin: .zero 32768 stack1_end: exit_counter: .word 0 ================================================ FILE: sw/basic-multicore/main.c ================================================ int main(unsigned hart_id) { // behave differently based on the core (i.e. hart) id for (unsigned i=0; i<100*hart_id; ++i) ; return 0; } ================================================ FILE: sw/blocking-sleep/Makefile ================================================ OBJECTS = main.o irq.o bootstrap.o CFLAGS = -march=rv32imac -mabi=ilp32 LDFLAGS = -nostartfiles -Wl,--no-relax VP = tiny32-vp include ../Makefile.common ================================================ FILE: sw/blocking-sleep/bootstrap.S ================================================ .globl _start .globl register_handler .globl main _start: call register_handler jal main # call exit (SYS_EXIT=93) with exit code 0 (argument in a0) li a7,93 li a0,0 ecall ================================================ FILE: sw/blocking-sleep/irq.S ================================================ .globl register_handler .globl lvl0_handler .align 4 lvl0_handler: # Store all register values on the stack addi sp, sp, -4 * 32 sw x1, 0x0(sp) sw x4, 3 * 4(sp) sw x5, 4 * 4(sp) sw x6, 5 * 4(sp) sw x7, 6 * 4(sp) sw x10, 9 * 4(sp) sw x11, 10 * 4(sp) sw x12, 11 * 4(sp) sw x13, 12 * 4(sp) sw x14, 13 * 4(sp) sw x15, 14 * 4(sp) sw x16, 15 * 4(sp) sw x17, 16 * 4(sp) sw x28, 27 * 4(sp) sw x29, 28 * 4(sp) sw x30, 29 * 4(sp) sw x31, 30 * 4(sp) jal irq_handler # Load all register values from the stack and return lw x1, 0x0(sp) lw x4, 3 * 4(sp) lw x5, 4 * 4(sp) lw x6, 5 * 4(sp) lw x7, 6 * 4(sp) lw x10, 9 * 4(sp) lw x11, 10 * 4(sp) lw x12, 11 * 4(sp) lw x13, 12 * 4(sp) lw x14, 13 * 4(sp) lw x15, 14 * 4(sp) lw x16, 15 * 4(sp) lw x17, 16 * 4(sp) lw x28, 27 * 4(sp) lw x29, 28 * 4(sp) lw x30, 29 * 4(sp) lw x31, 30 * 4(sp) addi sp, sp, 4 * 32 mret register_handler: # Use lvl0_handler as the trap handler la t0, lvl0_handler csrw mtvec, t0 # Enable machine external interrupts (MIE bit) li t1, 0x888 csrw mie, t1 # Globally enable machine mode interrupts (MIE bit) li t1, 8 csrw mstatus, t1 # Return ret ================================================ FILE: sw/blocking-sleep/main.c ================================================ #include #include enum { SLEEP_TIME = 5, // In seconds US_PER_SEC = 1000000, }; /* This is used to quantize a 1MHz value to the closest 32768Hz value */ #define DIVIDEND ((uint64_t)15625/(uint64_t)512) /* Bitmask to extract exception code from mcause register */ #define MCAUSE_CAUSE 0x7FFFFFFF /* Exception code for timer interrupts */ #define MACHINE_TIMER 7 /* Set after timer interrupt was received */ static volatile bool terminate = false; static volatile uint64_t *MTIMECMP_REG = (uint64_t *)0x2004000; static volatile uint64_t *MTIME_REG = (uint64_t *)0x200bff8; void irq_handler(void) { uint32_t mcause; uint32_t code; mcause = 0; __asm__ volatile ("csrr %[ret], mcause" : [ret] "=r" (mcause)); code = mcause & MCAUSE_CAUSE; if (code != MACHINE_TIMER || terminate) __asm__ volatile ("ebreak"); // Attempt to clear timer interrupt *MTIMECMP_REG = UINT64_MAX; terminate = true; return; } int main() { uint64_t usec = SLEEP_TIME * US_PER_SEC; uint64_t ticks = usec / DIVIDEND; uint64_t target = *MTIME_REG + ticks; *MTIMECMP_REG = target; while (!terminate) __asm__ volatile ("wfi"); return 0; } ================================================ FILE: sw/busy-wait-sleep/Makefile ================================================ OBJECTS = main.o bootstrap.o CFLAGS = -march=rv32i -mabi=ilp32 LDFLAGS = -nostartfiles -Wl,--no-relax VP = tiny32-vp include ../Makefile.common ================================================ FILE: sw/busy-wait-sleep/bootstrap.S ================================================ .globl _start .globl main _start: jal main # call exit (SYS_EXIT=93) with exit code 0 (argument in a0) li a7,93 li a0,0 ecall ================================================ FILE: sw/busy-wait-sleep/main.c ================================================ #include static volatile uint64_t *MTIMECMP_REG = (uint64_t *)0x2004000; static volatile uint64_t *MTIME_REG = (uint64_t *)0x200bff8; enum { SLEEP_TIME = 5, // In seconds US_PER_SEC = 1000000, }; /* This is used to quantize a 1MHz value to the closest 32768Hz value */ #define DIVIDEND ((uint64_t)15625/(uint64_t)512) int main() { uint64_t usec = SLEEP_TIME * US_PER_SEC; uint64_t ticks = usec / DIVIDEND; uint64_t target = *MTIME_REG + ticks; while (*MTIME_REG < target) ; return 0; } ================================================ FILE: sw/c++-lib/Makefile ================================================ LD = $(CXX) OBJECTS = main.o CXXFLAGS = -std=c++14 -march=rv32imac -mabi=ilp32 include ../Makefile.common override LD = $(CXX) ================================================ FILE: sw/c++-lib/main.cpp ================================================ #include #include #include #include struct A { int a; int b; A(int a, int b) : a(a), b(b) {} virtual int foo() = 0; virtual int bar() { return a + b; } }; struct B : public A { using A::A; virtual int foo() override { return a - b; } }; int main() { std::cout << "Hello World\n"; B x(5, 2); auto a = x.foo(); auto b = x.bar(); std::cout << a << "\n"; std::cout << b << "\n"; std::vector v; v.push_back(1); v.push_back(2); for (auto e : v) std::cout << e << std::endl; return 0; } ================================================ FILE: sw/clock-ticks/Makefile ================================================ OBJECTS = main.o irq.o bootstrap.o CFLAGS = -march=rv32imac -mabi=ilp32 LDFLAGS = -nostartfiles -Wl,--no-relax include ../Makefile.common ================================================ FILE: sw/clock-ticks/bootstrap.S ================================================ .globl _start .globl main .globl level_1_interrupt_handler _start: la t0, level_0_interrupt_handler csrw mtvec, t0 li t1, 0x888 csrw mie, t1 csrwi mstatus, 8 jal main # call exit (SYS_EXIT=93) with exit code 0 (argument in a0) li a7,93 li a0,0 ecall /* * Interrupt handler for non-nested interrupts. Only selected registers are stored/re-stored, i.e. those not preserved on function calls. */ #define STORE sw #define LOAD lw #define REGBYTES 4 .align 4 level_0_interrupt_handler: // store execution context on the stack (register content) addi sp, sp, -REGBYTES * 32 STORE x1, 0x0(sp) STORE x4, 3 * REGBYTES(sp) STORE x5, 4 * REGBYTES(sp) STORE x6, 5 * REGBYTES(sp) STORE x7, 6 * REGBYTES(sp) STORE x10, 9 * REGBYTES(sp) STORE x11, 10 * REGBYTES(sp) STORE x12, 11 * REGBYTES(sp) STORE x13, 12 * REGBYTES(sp) STORE x14, 13 * REGBYTES(sp) STORE x15, 14 * REGBYTES(sp) STORE x16, 15 * REGBYTES(sp) STORE x17, 16 * REGBYTES(sp) STORE x28, 27 * REGBYTES(sp) STORE x29, 28 * REGBYTES(sp) STORE x30, 29 * REGBYTES(sp) STORE x31, 30 * REGBYTES(sp) // load interrupt/trap reason and call external C function to handle it csrr a0, mcause jal level_1_interrupt_handler // re-store the saved context LOAD x1, 0x0(sp) LOAD x4, 3 * REGBYTES(sp) LOAD x5, 4 * REGBYTES(sp) LOAD x6, 5 * REGBYTES(sp) LOAD x7, 6 * REGBYTES(sp) LOAD x10, 9 * REGBYTES(sp) LOAD x11, 10 * REGBYTES(sp) LOAD x12, 11 * REGBYTES(sp) LOAD x13, 12 * REGBYTES(sp) LOAD x14, 13 * REGBYTES(sp) LOAD x15, 14 * REGBYTES(sp) LOAD x16, 15 * REGBYTES(sp) LOAD x17, 16 * REGBYTES(sp) LOAD x28, 27 * REGBYTES(sp) LOAD x29, 28 * REGBYTES(sp) LOAD x30, 29 * REGBYTES(sp) LOAD x31, 30 * REGBYTES(sp) addi sp, sp, REGBYTES * 32 mret ================================================ FILE: sw/clock-ticks/irq.c ================================================ #include "irq.h" #include "assert.h" #define RISCV_MACHINE_SOFTWARE_INTERRUPT 3 #define RISCV_MACHINE_TIMER_INTERRUPT 7 #define RISCV_MACHINE_EXTERNAL_INTERRUPT 11 #define PLIC_BASE 0x40000000 #define IRQ_TABLE_NUM_ENTRIES 64 static volatile uint32_t * const PLIC_INTERRUPT_ENABLE_START = (uint32_t * const)(PLIC_BASE + 0x2000); static volatile uint32_t * const PLIC_CLAIM_AND_RESPONSE_REGISTER = (uint32_t * const)(PLIC_BASE + 0x200004); static void irq_empty_handler() {} static irq_handler_t irq_handler_table[IRQ_TABLE_NUM_ENTRIES] = { [ 0 ... IRQ_TABLE_NUM_ENTRIES-1 ] = irq_empty_handler }; #define CLINT_BASE 0x2000000 volatile uint64_t* mtime = (uint64_t*)(CLINT_BASE + 0xbff8); volatile uint64_t* mtimecmp = (uint64_t*)(CLINT_BASE + 0x4000); static irq_handler_t timer_irq_handler = 0; void level_1_interrupt_handler(uint32_t cause) { switch (cause & 0xf) { case RISCV_MACHINE_EXTERNAL_INTERRUPT: { asm volatile ("csrc mip, %0" : : "r" (0x800)); uint32_t irq_id = *PLIC_CLAIM_AND_RESPONSE_REGISTER; irq_handler_table[irq_id](); *PLIC_CLAIM_AND_RESPONSE_REGISTER = 1; return; } case RISCV_MACHINE_TIMER_INTERRUPT: { // Note: the pending timer interrupt bit will be automatically cleared when writing to the *mtimecmp* register of this hart if (timer_irq_handler) { // let the user registered handler clear the timer interrupt bit timer_irq_handler(); } else { // reset the *mtimecmp* register to zero to clear the pending bit *mtimecmp = 0; } return; } } assert (0 && "unsupported cause"); } void register_interrupt_handler(uint32_t irq_id, irq_handler_t fn) { assert (irq_id < IRQ_TABLE_NUM_ENTRIES); // enable interrupt volatile uint32_t* const reg = (PLIC_INTERRUPT_ENABLE_START + irq_id/32); *reg |= 1 << (irq_id%32); // set a prio different to zero (which means do-not-interrupt) *((uint32_t*) (PLIC_BASE + irq_id*sizeof(uint32_t))) = 1; irq_handler_table[irq_id] = fn; } void register_timer_interrupt_handler(irq_handler_t fn) { timer_irq_handler = fn; } ================================================ FILE: sw/clock-ticks/irq.h ================================================ #ifndef __RISCV_IRQ_H__ #define __RISCV_IRQ_H__ #include "stdint.h" typedef void (*irq_handler_t)(void); void register_interrupt_handler(uint32_t irq_id, irq_handler_t fn); void register_timer_interrupt_handler(irq_handler_t fn); extern volatile uint64_t* mtime; extern volatile uint64_t* mtimecmp; #endif ================================================ FILE: sw/clock-ticks/main.c ================================================ #include "stdint.h" #include "irq.h" #include "stdio.h" #include "assert.h" static void set_next_timer_interrupt() { assert (mtime && mtimecmp); *mtimecmp = *mtime + 1000; // 1000 timer ticks, corresponds to 1 MS delay with current CLINT configuration } unsigned int num_ticks = 0; void timer_irq_handler() { set_next_timer_interrupt(); ++num_ticks; } int main() { printf("num_ticks %d\n", num_ticks); register_timer_interrupt_handler(timer_irq_handler); set_next_timer_interrupt(); while (num_ticks < 10) { printf("num_ticks %d\n", num_ticks); } printf("num_ticks %d\n", num_ticks); return 0; } ================================================ FILE: sw/crc8/Makefile ================================================ OBJECTS = main.o uart.o bootstrap.o CFLAGS = -march=rv32i -mabi=ilp32 LDFLAGS = -nostartfiles -Wl,--no-relax -T link.ld VP = microrv32-vp VP_FLAGS = hex: all ../elf2bin.py ./main crc.hex 0x4020 include ../Makefile.common ================================================ FILE: sw/crc8/bootstrap.S ================================================ .globl _start .globl main .equ SYSCALL_ADDR, 0x02010000 .macro INIT_HW_PLATFORM and x1,x0,x0 and x2,x0,x0 and x3,x0,x0 and x4,x0,x0 and x5,x0,x0 and x6,x0,x0 and x7,x0,x0 and x8,x0,x0 and x9,x0,x0 and x10,x0,x0 and x11,x0,x0 and x12,x0,x0 and x13,x0,x0 and x14,x0,x0 and x15,x0,x0 and x16,x0,x0 and x17,x0,x0 and x18,x0,x0 and x19,x0,x0 and x20,x0,x0 and x21,x0,x0 and x22,x0,x0 and x23,x0,x0 and x24,x0,x0 and x25,x0,x0 and x26,x0,x0 and x27,x0,x0 and x28,x0,x0 and x29,x0,x0 and x30,x0,x0 and x31,x0,x0 .endm .macro SYS_EXIT li a7, 93 li t0, SYSCALL_ADDR csrr a6, mhartid sw a6, 0(t0) .endm _start: # initialize hw-platform INIT_HW_PLATFORM la sp, stack_end jal main # call exit (SYS_EXIT=93) with exit code in a0 SYS_EXIT stack_begin: .zero 1024 stack_end: ================================================ FILE: sw/crc8/link.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; .text.init : { *(.text.init) } . = ALIGN(0x1000); .tohost : { *(.tohost) } . = ALIGN(0x1000); .text : { *(.text) } . = ALIGN(0x1000); .data : { *(.data) } .bss : { *(.bss) } _end = .; } ================================================ FILE: sw/crc8/main.c ================================================ #include #include #include "platform.h" #include "uart.h" #include "util.h" // 8-bit SAE J1850 CRC unsigned char crc8(unsigned char *data, int length) { /* * 8-bit CRC calculation * polynomial : 0x1D * initial value : 0xFF * reflect input : no * reflect result : no * XOR value : 0xFF * check : 0x4B * magic check : 0xC4 */ unsigned long crc; int i,bit; crc = 0xFF; for(i=0; i int sendString(char* str, long len) { long cnt = len; const char *s = (const char *)str; while (cnt > 0) { --cnt; putChr(*s); s++; } return len; } void putChr(char chr) { #ifdef MICRORV uint32_t tx_rdy = 0; *UART_TX_ADDR = chr; // send character stored in uart_tx_addr *UART_TX_CTRL = 1; // wait until tx is ready again for sening another character do { // read uart tx status tx_rdy = *UART_TX_CTRL; asm volatile ("nop"); } while(!tx_rdy); #else uint32_t tx_rdy = 0; *UART_TX_DATA_ADDR = chr; // send character stored in uart_tx_addr *UART_TX_CTRL_ADDR = 1; // wait until tx is ready again for sening another character do { // read uart tx status tx_rdy = *UART_TX_CTRL_ADDR; asm volatile ("nop"); } while(!tx_rdy); #endif return; } ================================================ FILE: sw/crc8/uart.h ================================================ #ifndef UART_H #include int sendString(char* str, long len); void putChr(char chr); #endif /* UART_H */ ================================================ FILE: sw/crc8/util.c ================================================ /* * utility functions for embedded usage where c-libs are too big */ //---------------------------- // integer to ascii (itoa) with util functions //---------------------------- // function to swap two numbers void swap(char *x, char *y) { char t = *x; *x = *y; *y = t; } // function to reverse buffer[i..j] char* reverse(char *buffer, int i, int j) { while (i < j) swap(&buffer[i++], &buffer[j--]); return buffer; } // Iterative function to implement itoa() function in C char* itoa(int value, char* buffer, int base) { // invalid input if (base < 2 || base > 32) return buffer; // consider absolute value of number int n = (value < 0) ? -value : value; int i = 0; while (n) { int r = n % base; if (r >= 10) buffer[i++] = 65 + (r - 10); else buffer[i++] = 48 + r; n = n / base; } // if number is 0 if (i == 0) buffer[i++] = '0'; // If base is 10 and value is negative, the resulting string // is preceded with a minus sign (-) // With any other base, value is always considered unsigned if (value < 0 && base == 10) buffer[i++] = '-'; buffer[i] = '\0'; // null terminate string // reverse the string and return it return reverse(buffer, 0, i - 1); } ================================================ FILE: sw/crc8/util.h ================================================ #ifndef UTIL_H void swap(char *x, char *y); char* reverse(char *buffer, int i, int j); char* itoa(int value, char* buffer, int base); #endif /* UTIL_H */ ================================================ FILE: sw/flashTest/Makefile ================================================ OBJECTS = main.o CXXFLAGS = -ggdb -std=c++14 -march=rv32ima -mabi=ilp32 include ../Makefile.common override LD = $(CXX) ================================================ FILE: sw/flashTest/main.cpp ================================================ #include #include #include // From flash.h static constexpr unsigned int BLOCKSIZE = 512; static constexpr unsigned int FLASH_ADDR_REG = 0; static constexpr unsigned int FLASH_SIZE_REG = sizeof(uint64_t); static constexpr unsigned int DATA_ADDR = FLASH_SIZE_REG + sizeof(uint64_t); // static constexpr unsigned int ADDR_SPACE = DATA_ADDR + BLOCKSIZE; static uint8_t* volatile const FLASH_CONTROLLER = (uint8_t * volatile const)(0x71000000); using namespace std; void setTargetBlock(uint64_t addr); void readFlash(char* dst, uint64_t addr, size_t len); void writeFlash(const char* src, uint64_t addr, size_t len); int main() { unsigned long counter = 0; uint64_t flashNumOfBlocks = 0; memcpy(&flashNumOfBlocks, FLASH_CONTROLLER + FLASH_SIZE_REG, sizeof(uint64_t)); cout << "Flash size: " << flashNumOfBlocks * BLOCKSIZE << " (" << flashNumOfBlocks << " Blocks)" << endl; readFlash(reinterpret_cast(&counter), 0, sizeof(unsigned long)); cout << " Counter before: " << counter << endl; writeFlash(reinterpret_cast(&++counter), 0, sizeof(unsigned long)); cout << " Counter after: " << counter << endl; } void setTargetBlock(uint64_t addr) { uint64_t targetBlock = addr % BLOCKSIZE; memcpy(FLASH_CONTROLLER + FLASH_ADDR_REG, &targetBlock, sizeof(uint64_t)); } void readFlash(char* dst, uint64_t addr, size_t len) { if (addr / BLOCKSIZE != (addr + len) / BLOCKSIZE) { cerr << "Unaligned read, currently not supported" << endl; return; } setTargetBlock(addr); memcpy(dst, FLASH_CONTROLLER + DATA_ADDR, len); } void writeFlash(const char* src, uint64_t addr, size_t len) { if (addr / BLOCKSIZE != (addr + len) / BLOCKSIZE) { cerr << "Unaligned read, currently not supported" << endl; return; } setTargetBlock(addr); memcpy(FLASH_CONTROLLER + DATA_ADDR, src, len); } ================================================ FILE: sw/flashTest/test-ignore ================================================ ================================================ FILE: sw/mramTest/Makefile ================================================ OBJECTS = main.o CXXFLAGS = -ggdb -std=c++14 -march=rv32ima -mabi=ilp32 include ../Makefile.common override LD = $(CXX) ================================================ FILE: sw/mramTest/main.cpp ================================================ #include #include "stdio.h" static char* const MRAM_START_ADDR = reinterpret_cast(0x60000000); static const unsigned int MRAM_SIZE = 0x0FFFFFFF; int main() { unsigned long counter = 0; char buffer[10] = {0}; memcpy(&counter, MRAM_START_ADDR, sizeof(unsigned long)); memcpy(buffer, MRAM_START_ADDR + 10, 10); printf("Before:\n"); printf("%lu, %0.*s\n", counter, 10, buffer); memcpy(MRAM_START_ADDR, &(++counter), sizeof(unsigned long)); memcpy(MRAM_START_ADDR + 10, "Kokosnuss", 10); memcpy(&counter, MRAM_START_ADDR, sizeof(unsigned long)); memcpy(buffer, MRAM_START_ADDR + 10, 10); printf("After:\n"); printf("%lu, %0.*s\n", counter, 10, buffer); } ================================================ FILE: sw/mrv32-uart/Makefile ================================================ rvArch?=rv32i OBJECTS = bootstrap.o main.o uart.o util.o CFLAGS = -march=$(rvArch) -mabi=ilp32 -mno-strict-align LDFLAGS = -nostartfiles -Wl,--no-relax,--print-memory-usage -T link.ld VP = microrv32-vp VP_FLAGS = include ../Makefile.common ================================================ FILE: sw/mrv32-uart/bootstrap.S ================================================ .globl _start .globl main .equ SYSCALL_ADDR, 0x02010000 .macro INIT_HW_PLATFORM and x1,x0,x0 and x2,x0,x0 and x3,x0,x0 and x4,x0,x0 and x5,x0,x0 and x6,x0,x0 and x7,x0,x0 and x8,x0,x0 and x9,x0,x0 and x10,x0,x0 and x11,x0,x0 and x12,x0,x0 and x13,x0,x0 and x14,x0,x0 and x15,x0,x0 and x16,x0,x0 and x17,x0,x0 and x18,x0,x0 and x19,x0,x0 and x20,x0,x0 and x21,x0,x0 and x22,x0,x0 and x23,x0,x0 and x24,x0,x0 and x25,x0,x0 and x26,x0,x0 and x27,x0,x0 and x28,x0,x0 and x29,x0,x0 and x30,x0,x0 and x31,x0,x0 .endm .macro SYS_EXIT, exit_code li a7, 93 li a0, \exit_code li t0, SYSCALL_ADDR csrr a6, mhartid sw a6, 0(t0) sw a7, 0(t0) .endm .align 4 _start: # initialize hw-platform INIT_HW_PLATFORM la sp, stack_end jal main # call exit (SYS_EXIT=93) with exit code 0 (argument in a0) 1: SYS_EXIT 0 j 1b .align 4 stack_begin: .zero 2048 stack_end: ================================================ FILE: sw/mrv32-uart/link.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(_start) MEMORY { RAM (rwx): ORIGIN = 0x80000000, LENGTH = 8k } SECTIONS { . = 0x80000000; .text.init : { *(.text.init) } > RAM . = ALIGN(0x1000); .tohost : { *(.tohost) } > RAM . = ALIGN(0x1000); .text : { *(.text) } > RAM . = ALIGN(0x1000); .data : { *(.data) } > RAM .bss : { *(.bss) } > RAM _end = .; } ================================================ FILE: sw/mrv32-uart/main.c ================================================ #include #include // #include #include "platform.h" #include "uart.h" #include "util.h" void delay(uint32_t loops) { for(uint32_t i = 0; i < loops; i++) { asm volatile("nop"); } } int main() { delay(10000); char buf[3]; char *txt1 = "uart rx failed?!\n"; delay(5000); // delay(7000); // delay(2000); // delay(10000); char rxBuf[5]; int rxEmpty = 1; int maxCnt = 30; int cnt = 0; rxEmpty = UART->RXEMPT; int occ; if(!rxEmpty) { // read rx data register from uart peripheral do { rxBuf[0] = UART->RXDATA; putChr(rxBuf[0]); cnt++; occ = UART->RXOCCU; // sendString() } while(UART->RXEMPT || cnt <= maxCnt); putChr('\n'); putChr('\n'); } else { sendString(txt1,1600); putChr('\n'); } return 0; } ================================================ FILE: sw/mrv32-uart/platform.h ================================================ #ifndef PLATFORM_H #define PLATFORM_H /* #define MICRORV // #ifdef MICRORV */ // LED static volatile uint32_t *LED_ADDR = (uint32_t *)0x81000000; // UART static volatile uint32_t *UART_TX_DATA_ADDR = (uint32_t *)0x82000000; static volatile uint32_t *UART_TX_CTRL_ADDR = (uint32_t *)0x82000004; static volatile uint32_t *UART_RX_DATA_ADDR = (uint32_t *)0x82000008; // CLIC static volatile uint64_t *MTIMECMP_REG = (uint64_t *)0x02004000; static volatile uint64_t *MTIME_REG = (uint64_t *)0x0200bff8; typedef struct { volatile uint32_t TXDATA; volatile uint32_t TXCTRL; volatile uint32_t RXDATA; volatile uint32_t RXOCCU; volatile uint32_t RXALEM; volatile uint32_t RXEMPT; } UART_REGS; #define UART ((UART_REGS *)0x82000000) /* #else // // UART // static volatile uint32_t *UART_TX_DATA_ADDR = (uint32_t *)0x82000000; // static volatile uint32_t *UART_TX_CTRL_ADDR = (uint32_t *)0x82000004; // static volatile uint32_t *UART_RX_DATA_ADDR = (uint32_t *)0x82000008; // static volatile uint32_t *UART_RX_FIFO_OCC_ADDR = (uint32_t *)0x8200000c; // static volatile uint32_t *UART_RX_FIFO_ALMOST_EMPTY_ADDR = (uint32_t *)0x82000010; // static volatile uint32_t *UART_RX_FIFO_EMPTY_ADDR = (uint32_t *)0x82000014; // // CLIC // static volatile uint64_t *MTIMECMP_REG = (uint64_t *)0x02004000; // static volatile uint64_t *MTIME_REG = (uint64_t *)0x0200bff8; // #endif */ #endif /* PLATFORM_H */ ================================================ FILE: sw/mrv32-uart/uart.c ================================================ #include "uart.h" #include "platform.h" #include int sendString(char* str, long len) { long cnt = len; const char *s = (const char *)str; while (cnt > 0) { --cnt; putChr(*s); s++; } return len; } void putChr(char chr) { uint32_t tx_rdy = 0; UART->TXDATA = chr; // send character stored in uart_tx_addr UART->TXCTRL = 1; // wait until tx is ready again for sening another character do { // read uart tx status tx_rdy = UART->TXCTRL; asm volatile ("nop"); } while(!tx_rdy); return; } ================================================ FILE: sw/mrv32-uart/uart.h ================================================ #ifndef UART_H #include int sendString(char* str, long len); void putChr(char chr); #endif /* UART_H */ ================================================ FILE: sw/mrv32-uart/util.c ================================================ /* * utility functions for embedded usage where c-libs are too big */ //---------------------------- // integer to ascii (itoa) with util functions //---------------------------- // function to swap two numbers void swap(char *x, char *y) { char t = *x; *x = *y; *y = t; } // function to reverse buffer[i..j] char* reverse(char *buffer, int i, int j) { while (i < j) swap(&buffer[i++], &buffer[j--]); return buffer; } // Iterative function to implement itoa() function in C char* itoa(int value, char* buffer, int base) { // invalid input if (base < 2 || base > 32) return buffer; // consider absolute value of number int n = (value < 0) ? -value : value; int i = 0; while (n) { int r = n % base; if (r >= 10) buffer[i++] = 65 + (r - 10); else buffer[i++] = 48 + r; n = n / base; } // if number is 0 if (i == 0) buffer[i++] = '0'; // If base is 10 and value is negative, the resulting string // is preceded with a minus sign (-) // With any other base, value is always considered unsigned if (value < 0 && base == 10) buffer[i++] = '-'; buffer[i] = '\0'; // null terminate string // reverse the string and return it return reverse(buffer, 0, i - 1); } ================================================ FILE: sw/mrv32-uart/util.h ================================================ #ifndef UTIL_H void swap(char *x, char *y); char* reverse(char *buffer, int i, int j); char* itoa(int value, char* buffer, int base); #endif /* UTIL_H */ ================================================ FILE: sw/peripheral-in-the-loop/Makefile ================================================ OBJECTS = main.o irq.o bootstrap.o CFLAGS = -march=rv32i -mabi=ilp32 LDFLAGS = -nostartfiles -Wl,--no-relax virtual-bus-path=../../vp/src/platform/hwitl/virtual-bus simple-sensor-path=../simple-sensor tty=/dev/ttyUSB2 $(virtual-bus-path)/responder-cli: make -C $(virtual-bus-path) responder-cli sim-bus: $(EXECUTABLE) $(virtual-bus-path)/responder-cli make -C $(virtual-bus-path) pipe_left sleep 1 #needed sometimes as pipe is not immediately there $(virtual-bus-path)/responder-cli $(virtual-bus-path)/pipe_right & hwitl-vp $(EXECUTABLE) --error-on-zero-traphandler=true --virtual-bus-device $(virtual-bus-path)/pipe_left killall responder-cli killall socat real: $(EXECUTABLE) hwitl-vp $(EXECUTABLE) --error-on-zero-traphandler=true --virtual-bus-device $(tty) clearpipes: killall responder-cli || true killall socat || true SIM_TARGET = sim-bus include ../Makefile.common ================================================ FILE: sw/peripheral-in-the-loop/main.c ================================================ #include #include "../simple-sensor/irq.h" typedef uint32_t BUS_BRIDGE_TYPE; static volatile BUS_BRIDGE_TYPE * const BUS_BRIDGE_START = (BUS_BRIDGE_TYPE * const) 0x50000000; static volatile BUS_BRIDGE_TYPE * const BUS_BRIDGE_END = (BUS_BRIDGE_TYPE * const) 0x5000000F; // INCLUSIVE static const unsigned BUS_BRIDGE_ITR = 2; static volatile char * const TERMINAL_ADDR = (char * const)0x20000000; static const unsigned num_words = (BUS_BRIDGE_END - BUS_BRIDGE_START) + 1; // INCLUSIVE void read_stuff() { for (int i = 0; i < num_words; i++) { const BUS_BRIDGE_TYPE datum = BUS_BRIDGE_START[i]; for(int c = 0; c < sizeof(BUS_BRIDGE_TYPE); c++) { *TERMINAL_ADDR = ((uint8_t*)&datum)[c]; } *TERMINAL_ADDR = '\n'; } } void write_stuff() { for (int i = 0; i < num_words; i++) { BUS_BRIDGE_TYPE datum; for(int c = 0; c < sizeof(BUS_BRIDGE_TYPE); c++) { ((uint8_t*)&datum)[c] = 'a' + (i+c); *TERMINAL_ADDR = ((uint8_t*)&datum)[c]; } BUS_BRIDGE_START[i] = datum; *TERMINAL_ADDR = '\n'; } } volatile int was_itr_triggered = 0; void virtual_bus_irq_handler() { static const char* hi = "Interrupt was triggered\n"; was_itr_triggered = 1; for(int i = 0; hi[i]; i++) *TERMINAL_ADDR = hi[i]; } int main() { register_interrupt_handler(BUS_BRIDGE_ITR, virtual_bus_irq_handler); read_stuff(); /* while(!was_itr_triggered) asm volatile ("wfi"); */ write_stuff(); return 0; } ================================================ FILE: sw/printf/Makefile ================================================ OBJECTS = main.o entry.o CFLAGS = -march=rv32i -mabi=ilp32 LDFLAGS = -Wl,-e_reset_vector VP_FLAGS = --error-on-zero-traphandler=true include ../Makefile.common ================================================ FILE: sw/printf/entry.S ================================================ .globl _start .globl _reset_vector .equ SYSCALL_ADDR, 0x02010000 trap_handler: li t0, SYSCALL_ADDR csrr t1, mhartid sw t1, 0(t0) csrr t0, mepc addi t0, t0, 4 csrw mepc, t0 mret _reset_vector: la t0, trap_handler csrw mtvec, t0 j _start ================================================ FILE: sw/printf/main.c ================================================ #include "stdio.h" #include "errno.h" #include "string.h" #include "unistd.h" int main(int argc, char **argv) { int n = printf("ABCDEFX %s\n", "Done"); int e = errno; puts(strerror(e)); puts ("Hello World!"); puts (" Hello World!"); puts (" X A "); putchar('a'); putchar('b'); putchar('c'); putchar('\n'); printf(" X Test\n"); printf("%d\n", 12); printf("Should print 1.2: %f\n", 1.2f); return 0; } ================================================ FILE: sw/simple-display/Makefile ================================================ OBJECTS = main.o libDisplay.o CXXFLAGS = -std=c++14 -march=rv32ima -mabi=ilp32 removeSHMEM: ipcrm --shmem-key 0x0000053a || true include ../Makefile.common override LD = $(CXX) ================================================ FILE: sw/simple-display/libDisplay.cpp ================================================ /* * libDisplay.cpp * * Created on: Oct 5, 2018 * Author: dwd */ #include "libDisplay.hpp" #include #include typedef Framebuffer::Point Point; typedef Framebuffer::PointF PointF; typedef Framebuffer::Color Color; namespace display { void setPixel(Framebuffer::Type frame, Point pixel, Color color) { framebuffer->getFrame(frame).raw[pixel.y][pixel.x] = color; } void drawLine(Framebuffer::Type frame, PointF from, PointF to, Color color) { framebuffer->parameter.line.frame = frame; framebuffer->parameter.line.from = from; framebuffer->parameter.line.to = to; framebuffer->parameter.line.color = color; framebuffer->command = Framebuffer::Command::drawLine; } void drawRect(Framebuffer::Type frame, PointF ol, PointF ur, Color color) { if (ol.x > ur.x) { std::swap(ol.x, ur.x); } if (ol.y > ur.y) { std::swap(ol.y, ur.y); } drawLine(frame, ol, PointF(ur.x, ol.y), color); drawLine(frame, PointF(ur.x, ol.y), ur, color); drawLine(frame, ur, PointF(ol.x, ur.y), color); drawLine(frame, PointF(ol.x, ur.y), ol, color); } void fillRect(Framebuffer::Type frame, PointF ol, PointF ur, Color color) { if (ol.x == ur.x || ol.y == ur.y) { // No dimension return; } if (ol.x > ur.x) { std::swap(ol.x, ur.x); } if (ol.y > ur.y) { std::swap(ol.y, ur.y); } if (ur.x - ol.x > ur.y - ol.y) { // Horizontal for (uint16_t y = ol.y; y <= ur.y; y++) { drawLine(frame, PointF(ol.x, y), PointF(ur.x, y), color); } } else { // Vertical for (uint16_t x = ol.x; x <= ur.x; x++) { drawLine(frame, PointF(x, ol.y), PointF(x, ur.y), color); } } } void applyFrame() { framebuffer->command = Framebuffer::Command::applyFrame; } void fillFrame(Framebuffer::Type frame, Color color) { framebuffer->parameter.fill.frame = frame; framebuffer->parameter.fill.color = color; framebuffer->command = Framebuffer::Command::fillFrame; } } // namespace display ================================================ FILE: sw/simple-display/libDisplay.hpp ================================================ /* * libDisplay.hpp * * Created on: Oct 5, 2018 * Author: dwd */ #pragma once #include "../../env/basic/vp-display/framebuffer.h" extern Framebuffer* volatile const framebuffer; inline Framebuffer::Color fromRGB(uint8_t r, uint8_t g, uint8_t b) { Framebuffer::Color ret = 0; ret |= (b & 0x0F); ret |= (g & 0x0F) << 4; ret |= (r & 0x0F) << 8; return ret; } namespace display { void setPixel(Framebuffer::Type frame, Framebuffer::Point pixel, Framebuffer::Color color); void drawLine(Framebuffer::Type frame, Framebuffer::PointF from, Framebuffer::PointF to, Framebuffer::Color color); void drawRect(Framebuffer::Type frame, Framebuffer::PointF ol, Framebuffer::PointF ur, Framebuffer::Color color); void fillRect(Framebuffer::Type frame, Framebuffer::PointF ol, Framebuffer::PointF ur, Framebuffer::Color color); void applyFrame(); void fillFrame(Framebuffer::Type frame = Framebuffer::Type::foreground, Framebuffer::Color color = 0); }; // namespace display ================================================ FILE: sw/simple-display/main.cpp ================================================ #include "libDisplay.hpp" #include #include #include #include Framebuffer* volatile const framebuffer = (Framebuffer * volatile const)(0x72000000); typedef Framebuffer::Point Point; typedef Framebuffer::PointF PointF; typedef Framebuffer::Color Color; static constexpr auto screenWidth = Framebuffer::screenWidth; static constexpr auto screenHeight = Framebuffer::screenHeight; void activeWait(float factor = 0.5) { for (uint16_t i = 0; i < UINT16_MAX * factor; i++) { }; } Point getRandomPoint() { return Point(rand() % screenWidth, rand() % screenHeight); } Color getRandomColor() { return rand() % SHRT_MAX; } void drawBackground() { for (uint32_t i = 0; i < screenHeight - 1; i++) { display::drawLine(Framebuffer::Type::background, Point(0, i), Point(screenWidth, i), fromRGB(i & 0x7, 0, i >> 3)); if (i % 5 == 0) display::applyFrame(); } } void drawFunnyRects() { static uint32_t m = 0; for (uint16_t i = 0; i < 400; i++) { // drawLine(framebuffer->getInactiveFrame(), getRandomPoint(), // getRandomPoint(), getRandomColor()); display::drawRect(Framebuffer::Type::foreground, Point(m % screenWidth, m % screenHeight), Point( (screenWidth - (m + 1) % screenWidth), (screenHeight - (m + 1) % screenHeight) ), fromRGB(255 - (m % 255), (m % 255), i % 255)); display::applyFrame(); activeWait(.005); m += 17; } } /** * @param completion Values between 0..1 */ void progressBar(bool horizontal, Framebuffer::PointF base, Framebuffer::PointF extent, Color fg, Color bg, float completion) { PointF progress = horizontal ? PointF(extent.x * completion, extent.y) : PointF(extent.x, extent.y * completion); display::fillRect(Framebuffer::Type::foreground, base, base + progress, fg); display::fillRect(Framebuffer::Type::foreground, base + progress, base + extent, bg); } void drawFunnyBar(bool horizontal = false) { Color bgColor = fromRGB(0, 0, 1); Color progressColor = fromRGB(126, 255, 10); Point baseOL; Point baseUR; uint16_t stepsize = 1; if (horizontal) { baseOL = Point(100, 250); baseUR = Point(700, 350); } else { baseOL = Point(350, 50); baseUR = Point(450, 550); } display::fillRect(Framebuffer::Type::foreground, baseOL, baseUR, bgColor); display::applyFrame(); Point barBase(baseOL.x + 10, baseOL.y + 10); Point barExtent((baseUR.x - baseOL.x) - 20, (baseUR.y - baseOL.y) - 20); for (float progress = 0; progress <= 1; progress += 0.01) { display::fillRect(Framebuffer::Type::foreground, baseOL, baseUR, bgColor); progressBar(horizontal, barBase, barExtent, progressColor, bgColor, progress); display::applyFrame(); activeWait(.005); } for (float progress = 1; progress >= 0; progress -= 0.01) { display::fillRect(Framebuffer::Type::foreground, baseOL, baseUR, bgColor); progressBar(horizontal, barBase, barExtent, progressColor, bgColor, progress); display::applyFrame(); activeWait(.005); } } using namespace std; int main() { cout << "draw background" << endl; drawBackground(); while (true) { cout << "Draw H-bar" << endl; drawFunnyBar(true); display::fillFrame(Framebuffer::Type::foreground); display::applyFrame(); cout << "Draw V-bar" << endl; drawFunnyBar(false); display::fillFrame(Framebuffer::Type::foreground); display::applyFrame(); cout << "Draw Rects" << endl; drawFunnyRects(); display::fillFrame(Framebuffer::Type::foreground); display::applyFrame(); } return 0; } ================================================ FILE: sw/simple-display/test-ignore ================================================ ================================================ FILE: sw/simple-scheduler/Makefile ================================================ OBJECTS = main.o cor.o CFLAGS = -march=rv32imac -mabi=ilp32 include ../Makefile.common ================================================ FILE: sw/simple-scheduler/cor.S ================================================ .globl contextswitch .globl coroutine_entry .globl launch_coroutine coroutine_entry: // move the launch argument to the a0 register (i.e. first argument of the following function) mv a0,s0 call launch_coroutine // the above call should not return (i.e the scheduler should not call a finished coroutine) ebreak /* * registers a0 and a1 point to the current and next context, respectively * * 1) store all current registers and pc in the current context * 2) load register values from next context * 3) jump to pc in the next context */ contextswitch: // store registers sw x1,4(a0) // ra sw x2,8(a0) // sp sw x8,32(a0) // s0 sw x9,36(a0) // s1 sw x18,72(a0) // s2 sw x19,76(a0) // s3 sw x20,80(a0) // s4 sw x21,84(a0) // s5 sw x22,88(a0) // s6 sw x23,92(a0) // s7 sw x24,96(a0) // s8 sw x25,100(a0) // s9 sw x26,104(a0) // s10 sw x27,108(a0) // s11 // store pc la t0,_resume sw t0,0(a0) // restore other registers (NOTE: callee saved only + ra) lw x1,4(a1) // ra lw x2,8(a1) // sp lw x8,32(a1) // s0 lw x9,36(a1) // s1 lw x18,72(a1) // s2 lw x19,76(a1) // s3 lw x20,80(a1) // s4 lw x21,84(a1) // s5 lw x22,88(a1) // s6 lw x23,92(a1) // s7 lw x24,96(a1) // s8 lw x25,100(a1) // s9 lw x26,104(a1) // s10 lw x27,108(a1) // s11 // load new program counter and perform context switch lw t0,0(a1) jr t0 _resume: ret ================================================ FILE: sw/simple-scheduler/main.c ================================================ #include #include #include #include #define REG_SP 1 #define REG_S0 7 typedef void (*entrypoint_t)(void *); enum state_t { UNKNOWN, START, ACTIVE, FINISHED }; typedef struct { uint32_t pc; uint32_t regs[31]; } context_t; typedef struct { uint8_t stack[16384]; context_t ctx; entrypoint_t entry; void *arg; enum state_t stat; } coroutine_t; context_t main_context; context_t *active_context; extern void contextswitch(context_t *current, context_t *next); extern void coroutine_entry(); void switch_to_scheduler() { contextswitch(active_context, &main_context); } void switch_to_coroutine(coroutine_t *cor) { active_context = &cor->ctx; contextswitch(&main_context, &cor->ctx); } void launch_coroutine(coroutine_t *cor) { cor->stat = ACTIVE; cor->entry(cor->arg); cor->stat = FINISHED; assert (active_context == &cor->ctx); switch_to_scheduler(); } void function_A(void *arg) { printf("A fn: 1\n"); switch_to_scheduler(); printf("A fn: 2\n"); } void function_B(void *arg) { printf("B fn: 1\n"); switch_to_scheduler(); printf("B fn: 2\n"); switch_to_scheduler(); printf("B fn: 3\n"); } coroutine_t *create_coroutine(entrypoint_t fn, void *arg) { coroutine_t *cor = (coroutine_t *)malloc(sizeof(coroutine_t)); for (int i=0; i<31; ++i) cor->ctx.regs[i] = 0; cor->ctx.regs[REG_SP] = (uint32_t)(&cor->stack[16384]); cor->ctx.regs[REG_S0] = (uint32_t)cor; cor->entry = fn; cor->arg = arg; cor->stat = START; cor->ctx.pc = (uint32_t)coroutine_entry; return cor; } void free_coroutine(coroutine_t *cor) { free(cor); } int main() { coroutine_t *A_cor = create_coroutine(function_A, 0); coroutine_t *B_cor = create_coroutine(function_B, 0); _Bool done = 0; while (!done) { done = 1; if (A_cor->stat != FINISHED) { switch_to_coroutine(A_cor); done = 0; } if (B_cor->stat != FINISHED) { switch_to_coroutine(B_cor); done = 0; } } free_coroutine(A_cor); free_coroutine(B_cor); return 0; } ================================================ FILE: sw/simple-scheduler/no-clib/Makefile ================================================ all : main.c riscv32-unknown-elf-gcc main.c cor.S bootstrap.S -o main -march=rv32ima -mabi=ilp32 -nostartfiles sim: all riscv-vp --intercept-syscalls main dump-elf: all riscv32-unknown-elf-readelf -a main dump-code: all riscv32-unknown-elf-objdump -D main clean: rm -f main ================================================ FILE: sw/simple-scheduler/no-clib/bootstrap.S ================================================ .globl _start .globl main _start: # Initialize global pointer .option push .option norelax 1:auipc gp, %pcrel_hi(__global_pointer$) addi gp, gp, %pcrel_lo(1b) .option pop li sp, 8000000 jal main # call exit (SYS_EXIT=93) with exit code 0 (argument in a0) li a7,93 li a0,0 ecall ================================================ FILE: sw/simple-scheduler/no-clib/cor.S ================================================ .globl contextswitch .globl coroutine_entry .globl launch_coroutine coroutine_entry: // move the launch argument to the a0 register (i.e. first argument of the following function) mv a0,s0 call launch_coroutine // the above call should not return (i.e the scheduler should not call a finished coroutine) ebreak /* * registers a0 and a1 point to the current and next context, respectively * * 1) store all current registers and pc in the current context * 2) load register values from next context * 3) jump to pc in the next context */ contextswitch: // store registers sw x1,4(a0) // ra sw x2,8(a0) // sp //sw x3,12(a0) // gp //sw x4,16(a0) // tp //sw x5,20(a0) // t0 //sw x6,24(a0) // t1 //sw x7,28(a0) // t2 sw x8,32(a0) // s0 sw x9,36(a0) // s1 //sw x10,40(a0) // a0 //sw x11,44(a0) // a1 //sw x12,48(a0) // a2 //sw x13,52(a0) // a3 //sw x14,56(a0) // a4 //sw x15,60(a0) // a5 //sw x16,64(a0) // a6 //sw x17,68(a0) // a7 sw x18,72(a0) // s2 sw x19,76(a0) // s3 sw x20,80(a0) // s4 sw x21,84(a0) // s5 sw x22,88(a0) // s6 sw x23,92(a0) // s7 sw x24,96(a0) // s8 sw x25,100(a0) // s9 sw x26,104(a0) // s10 sw x27,108(a0) // s11 //sw x28,112(a0) // t3 //sw x29,116(a0) // t4 //sw x30,120(a0) // t5 //sw x31,124(a0) // t6 // store pc la t0,_resume sw t0,0(a0) // restore other registers (NOTE: callee saved only + ra) lw x1,4(a1) // ra lw x2,8(a1) // sp lw x8,32(a1) // s0 lw x9,36(a1) // s1 lw x18,72(a1) // s2 lw x19,76(a1) // s3 lw x20,80(a1) // s4 lw x21,84(a1) // s5 lw x22,88(a1) // s6 lw x23,92(a1) // s7 lw x24,96(a1) // s8 lw x25,100(a1) // s9 lw x26,104(a1) // s10 lw x27,108(a1) // s11 // load new program counter and perform context switch lw t0,0(a1) jr t0 _resume: ret ================================================ FILE: sw/simple-scheduler/no-clib/main.c ================================================ #include "stdlib.h" #include "stdio.h" #include "assert.h" #define REG_SP 1 #define REG_S0 7 typedef void (*entrypoint_t)(void *); enum state_t { UNKNOWN, START, ACTIVE, FINISHED }; typedef struct { uint32_t pc; uint32_t regs[31]; } context_t; typedef struct { uint8_t stack[16384]; context_t ctx; entrypoint_t entry; void *arg; enum state_t stat; } coroutine_t; context_t main_context; context_t *active_context; extern void contextswitch(context_t *current, context_t *next); extern void coroutine_entry(); void switch_to_scheduler() { contextswitch(active_context, &main_context); } void switch_to_coroutine(coroutine_t *cor) { active_context = &cor->ctx; contextswitch(&main_context, &cor->ctx); } void launch_coroutine(coroutine_t *cor) { cor->stat = ACTIVE; cor->entry(cor->arg); cor->stat = FINISHED; assert (active_context == &cor->ctx); switch_to_scheduler(); } void function_A(void *arg) { printf("A fn: 1\n"); switch_to_scheduler(); printf("A fn: 2\n"); } void function_B(void *arg) { printf("B fn: 1\n"); switch_to_scheduler(); printf("B fn: 2\n"); switch_to_scheduler(); printf("B fn: 3\n"); } coroutine_t *create_coroutine(entrypoint_t fn, void *arg) { coroutine_t *cor = (coroutine_t *)malloc(sizeof(coroutine_t)); for (int i=0; i<31; ++i) cor->ctx.regs[i] = 0; cor->ctx.regs[REG_SP] = (uint32_t)(&cor->stack[16384]); cor->ctx.regs[REG_S0] = (uint32_t)cor; cor->entry = fn; cor->arg = arg; cor->stat = START; cor->ctx.pc = (uint32_t)coroutine_entry; return cor; } void free_coroutine(coroutine_t *cor) { free(cor); } int main() { coroutine_t *A_cor = create_coroutine(function_A, 0); coroutine_t *B_cor = create_coroutine(function_B, 0); _Bool done = 0; while (!done) { done = 1; if (A_cor->stat != FINISHED) { switch_to_coroutine(A_cor); done = 0; } if (B_cor->stat != FINISHED) { switch_to_coroutine(B_cor); done = 0; } } free_coroutine(A_cor); free_coroutine(B_cor); return 0; } ================================================ FILE: sw/simple-sensor/Makefile ================================================ OBJECTS = main.o irq.o bootstrap.o CFLAGS = -march=rv32i -mabi=ilp32 LDFLAGS = -nostartfiles -Wl,--no-relax include ../Makefile.common ================================================ FILE: sw/simple-sensor/bootstrap.S ================================================ .globl _start .globl main .globl level_1_interrupt_handler .equ SYSCALL_ADDR, 0x02010000 .equ PLIC_ENABLED_IRQ_ADDR, 0x40002000 .macro SYS_EXIT, exit_code li a7, 93 li a0, \exit_code li t0, SYSCALL_ADDR csrr a6, mhartid sw a6, 0(t0) .endm _start: la t0, level_0_interrupt_handler csrw mtvec, t0 li t1, 0x888 csrw mie, t1 csrsi mstatus, 8 li t0, PLIC_ENABLED_IRQ_ADDR li t1, -1 sw t1, 0(t0) sw t1, 4(t0) jal main # call exit (SYS_EXIT=93) with exit code 0 (argument in a0) SYS_EXIT 0 /* * Interrupt handler for non-nested interrupts. Only selected registers are stored/re-stored, i.e. those not preserved on function calls. */ #define STORE sw #define LOAD lw #define REGBYTES 4 level_0_interrupt_handler: // store execution context on the stack (register content) addi sp, sp, -REGBYTES * 32 STORE x1, 0x0(sp) STORE x4, 3 * REGBYTES(sp) STORE x5, 4 * REGBYTES(sp) STORE x6, 5 * REGBYTES(sp) STORE x7, 6 * REGBYTES(sp) STORE x10, 9 * REGBYTES(sp) STORE x11, 10 * REGBYTES(sp) STORE x12, 11 * REGBYTES(sp) STORE x13, 12 * REGBYTES(sp) STORE x14, 13 * REGBYTES(sp) STORE x15, 14 * REGBYTES(sp) STORE x16, 15 * REGBYTES(sp) STORE x17, 16 * REGBYTES(sp) STORE x28, 27 * REGBYTES(sp) STORE x29, 28 * REGBYTES(sp) STORE x30, 29 * REGBYTES(sp) STORE x31, 30 * REGBYTES(sp) // load interrupt/trap reason and call external C function to handle it csrr t2, mcause srli t3, t2, 31 bnez t3, handle_irq li t0, SYSCALL_ADDR csrr t1, mhartid csrr a7, mcause sw t1, 0(t0) csrr t0, mepc addi t0, t0, 4 csrw mepc, t0 sw a0, 9 * REGBYTES(sp) j done_trap handle_irq: mv a0, t2 jal level_1_interrupt_handler done_trap: // re-store the saved context LOAD x1, 0x0(sp) LOAD x4, 3 * REGBYTES(sp) LOAD x5, 4 * REGBYTES(sp) LOAD x6, 5 * REGBYTES(sp) LOAD x7, 6 * REGBYTES(sp) LOAD x10, 9 * REGBYTES(sp) LOAD x11, 10 * REGBYTES(sp) LOAD x12, 11 * REGBYTES(sp) LOAD x13, 12 * REGBYTES(sp) LOAD x14, 13 * REGBYTES(sp) LOAD x15, 14 * REGBYTES(sp) LOAD x16, 15 * REGBYTES(sp) LOAD x17, 16 * REGBYTES(sp) LOAD x28, 27 * REGBYTES(sp) LOAD x29, 28 * REGBYTES(sp) LOAD x30, 29 * REGBYTES(sp) LOAD x31, 30 * REGBYTES(sp) addi sp, sp, REGBYTES * 32 mret ================================================ FILE: sw/simple-sensor/irq.c ================================================ #include "irq.h" #include "assert.h" #define RISCV_MACHINE_SOFTWARE_INTERRUPT 3 #define RISCV_MACHINE_TIMER_INTERRUPT 7 #define RISCV_MACHINE_EXTERNAL_INTERRUPT 11 #define PLIC_BASE 0x40000000 #define IRQ_TABLE_NUM_ENTRIES 64 static volatile uint32_t * const PLIC_INTERRUPT_ENABLE_START = (uint32_t * const)(PLIC_BASE + 0x2000); static volatile uint32_t * const PLIC_CLAIM_AND_RESPONSE_REGISTER = (uint32_t * const)(PLIC_BASE + 0x200004); static void irq_empty_handler() {} static irq_handler_t irq_handler_table[IRQ_TABLE_NUM_ENTRIES] = { [ 0 ... IRQ_TABLE_NUM_ENTRIES-1 ] = irq_empty_handler }; #define CLINT_BASE 0x2000000 volatile uint64_t* mtime = (uint64_t*)(CLINT_BASE + 0xbff8); volatile uint64_t* mtimecmp = (uint64_t*)(CLINT_BASE + 0x4000); static irq_handler_t timer_irq_handler = 0; void level_1_interrupt_handler(uint32_t cause) { switch (cause & 0xf) { case RISCV_MACHINE_EXTERNAL_INTERRUPT: { asm volatile ("csrc mip, %0" : : "r" (0x800)); uint32_t irq_id = *PLIC_CLAIM_AND_RESPONSE_REGISTER; irq_handler_table[irq_id](); *PLIC_CLAIM_AND_RESPONSE_REGISTER = 1; return; } case RISCV_MACHINE_TIMER_INTERRUPT: { // Note: the pending timer interrupt bit will be automatically cleared when writing to the *mtimecmp* register of this hart if (timer_irq_handler) { // let the user registered handler clear the timer interrupt bit timer_irq_handler(); } else { // reset the *mtimecmp* register to zero to clear the pending bit *mtimecmp = 0; } return; } } assert (0 && "unsupported cause"); } void register_interrupt_handler(uint32_t irq_id, irq_handler_t fn) { assert (irq_id < IRQ_TABLE_NUM_ENTRIES); // enable interrupt volatile uint32_t* const reg = (PLIC_INTERRUPT_ENABLE_START + irq_id/32); *reg |= 1 << (irq_id%32); // set a prio different to zero (which means do-not-interrupt) *((uint32_t*) (PLIC_BASE + irq_id*sizeof(uint32_t))) = 1; irq_handler_table[irq_id] = fn; } void register_timer_interrupt_handler(irq_handler_t fn) { timer_irq_handler = fn; } ================================================ FILE: sw/simple-sensor/irq.h ================================================ #ifndef __RISCV_IRQ_H__ #define __RISCV_IRQ_H__ #include "stdint.h" typedef void (*irq_handler_t)(void); void register_interrupt_handler(uint32_t irq_id, irq_handler_t fn); void register_timer_interrupt_handler(irq_handler_t fn); extern volatile uint64_t* mtime; extern volatile uint64_t* mtimecmp; #endif ================================================ FILE: sw/simple-sensor/main.c ================================================ #include #include "irq.h" static volatile char * const TERMINAL_ADDR = (char * const)0x20000000; static volatile char * const SENSOR_INPUT_ADDR = (char * const)0x50000000; static volatile uint32_t * const SENSOR_SCALER_REG_ADDR = (uint32_t * const)0x50000080; static volatile uint32_t * const SENSOR_FILTER_REG_ADDR = (uint32_t * const)0x50000084; volatile _Bool has_sensor_data = 0; void sensor_irq_handler() { has_sensor_data = 1; } void dump_sensor_data() { while (!has_sensor_data) { asm volatile ("wfi"); } has_sensor_data = 0; for (int i=0; i<64; ++i) { *TERMINAL_ADDR = *(SENSOR_INPUT_ADDR + i) % 92 + 32; } *TERMINAL_ADDR = '\n'; } int main() { register_interrupt_handler(2, sensor_irq_handler); *SENSOR_SCALER_REG_ADDR = 5; *SENSOR_FILTER_REG_ADDR = 2; for (int i=0; i<3; ++i) dump_sensor_data(); return 0; } ================================================ FILE: sw/sys-read/Makefile ================================================ OBJECTS = main.o CFLAGS = -march=rv32ima -mabi=ilp32 include ../Makefile.common ================================================ FILE: sw/sys-read/main.c ================================================ #include "stdio.h" int main(int argc, char **argv) { printf("Enter a number: "); int c,n = 0; while (!scanf("%d", &n)) { printf("Error: unable to parse number\n"); while((c = getchar()) != '\n' && c != EOF); printf("Enter a number: "); } printf("Success, you entered %i\n", n); return 0; } ================================================ FILE: sw/sys-read/test-ignore ================================================ ================================================ FILE: sw/test.sh ================================================ #!/bin/sh export SYSTEMC_DISABLE_COPYRIGHT_MESSAGE=1 handle_exit() { [ $# -eq 1 ] || exit 1 if [ "${1}" -eq 0 ]; then printf "OK.\n" else printf "FAIL.\n" exit 1 fi } for test in *; do [ -e "${test}/test-ignore" -o -f "${test}" ] && continue name=${test##*/} printf "Building sw '%s': " "${name}" make -C "${test}" >/dev/null handle_exit $? printf "Running sw '%s': " "${name}" make -C "${test}" sim >/dev/null handle_exit $? done ================================================ FILE: vp/.gitignore ================================================ build ================================================ FILE: vp/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.18) project(riscv-vp VERSION 1.2.2 ) option(USE_SYSTEM_SYSTEMC "use systemc version provided by the system" OFF) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Debug) endif() set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wpedantic") set(CMAKE_CXX_FLAGS_DEBUG "-g3") #"-fsanitize=address -fno-omit-frame-pointer" set(CMAKE_CXX_FLAGS_RELEASE "-O3") # Allows running tests without invoking `make install` first. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}) include(cmake/AddGitSubmodule.cmake) find_package( Boost REQUIRED COMPONENTS iostreams program_options log) if(USE_SYSTEM_SYSTEMC) find_library(SystemC libsystemc.a) endif() subdirs(src) enable_testing() list(APPEND CMAKE_CTEST_ARGUMENTS "--verbose") add_test(NAME libgdb COMMAND ./test.sh WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/tests/libgdb") add_test(NAME gdb COMMAND ./test.sh WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/tests/gdb") add_test(NAME integration COMMAND ./test.sh WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/tests/integration") add_test(NAME sw COMMAND ./test.sh WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/../sw") set_tests_properties(gdb integration sw PROPERTIES ENVIRONMENT PATH=$ENV{PATH}:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) set_tests_properties(libgdb PROPERTIES ENVIRONMENT RISCV_VP_BASE=${CMAKE_CURRENT_SOURCE_DIR}/..) ================================================ FILE: vp/cmake/AddGitSubmodule.cmake ================================================ #thanks @ https://gist.github.com/scivision/bb1d47a9529e153617414e91ff5390af cmake_minimum_required(VERSION 3.16) function(add_git_submodule dir) # add a Git submodule directory to CMake, assuming the # Git submodule directory is a CMake project. # # Usage: in CMakeLists.txt # # include(AddGitSubmodule.cmake) # add_git_submodule(mysubmod_dir) find_package(Git REQUIRED) if(NOT EXISTS ${dir}) set(dir ${CMAKE_CURRENT_SOURCE_DIR}/${dir}) endif() if(NOT EXISTS "${dir}/CMakeLists.txt") message("checking out submodule ${dir}") execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive -- ${abs_dir} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} #COMMAND_ERROR_IS_FATAL # cmake 3.19+ #ANY # cmake 3.19+ ) endif() add_subdirectory(${dir}) endfunction(add_git_submodule) ================================================ FILE: vp/src/CMakeLists.txt ================================================ include_directories(.) subdirs(vendor) subdirs(core) subdirs(platform) ================================================ FILE: vp/src/core/CMakeLists.txt ================================================ subdirs(common) subdirs(rv32) subdirs(rv64) ================================================ FILE: vp/src/core/common/CMakeLists.txt ================================================ file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) add_library(core-common timer.cpp real_clint.cpp instr.cpp debug_memory.cpp rawmode.cpp ${HEADERS}) target_include_directories(core-common PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(core-common PRIVATE pthread systemc) add_subdirectory(gdb-mc) ================================================ FILE: vp/src/core/common/bus_lock_if.h ================================================ #pragma once struct bus_lock_if { virtual ~bus_lock_if() {} virtual void lock(unsigned hart_id) = 0; virtual void unlock(unsigned hart_id) = 0; virtual bool is_locked() = 0; // by any hart virtual bool is_locked(unsigned hart_id) = 0; virtual void wait_until_unlocked() = 0; inline void wait_for_access_rights(unsigned hart_id) { if (is_locked() && !is_locked(hart_id)) wait_until_unlocked(); } }; ================================================ FILE: vp/src/core/common/clint.h ================================================ #ifndef RISCV_ISA_CLINT_H #define RISCV_ISA_CLINT_H #include "clint_if.h" #include "irq_if.h" #include #include #include "util/memory_map.h" template struct CLINT : public clint_if, public sc_core::sc_module { // // core local interrupt controller (provides local timer interrupts with // memory mapped configuration) // // send out interrupt if: *mtime >= mtimecmp* and *mtimecmp != 0* // // *mtime* is a read-only 64 bit timer register shared by all CPUs (accessed // by MMIO and also mapped into the CSR address space of each CPU) // // for every CPU a *mtimecmp* register (read/write 64 bit) is available // // // Note: the software is responsible to ensure that no overflow occurs when // writing *mtimecmp* (see RISC-V privileged ISA spec.): // // # New comparand is in a1:a0. // li t0, -1 // sw t0, mtimecmp # No smaller than old value. // sw a1, mtimecmp+4 # No smaller than new value. // sw a0, mtimecmp # New value. // static_assert(NumberOfCores < 4096, "out of bound"); // stay within the allocated address range static constexpr uint64_t scaler = 1000000; // scale from PS resolution (default in SystemC) to US // resolution (apparently required by FreeRTOS) tlm_utils::simple_target_socket tsock; sc_core::sc_time clock_cycle = sc_core::sc_time(10, sc_core::SC_NS); sc_core::sc_event irq_event; RegisterRange regs_mtime{0xBFF8, 8}; IntegerView mtime{regs_mtime}; RegisterRange regs_mtimecmp{0x4000, 8 * NumberOfCores}; ArrayView mtimecmp{regs_mtimecmp}; RegisterRange regs_msip{0x0, 4 * NumberOfCores}; ArrayView msip{regs_msip}; std::vector register_ranges{®s_mtime, ®s_mtimecmp, ®s_msip}; std::array target_harts{}; SC_HAS_PROCESS(CLINT); CLINT(sc_core::sc_module_name) { tsock.register_b_transport(this, &CLINT::transport); regs_mtimecmp.alignment = 4; regs_msip.alignment = 4; regs_mtime.alignment = 4; regs_mtime.pre_read_callback = std::bind(&CLINT::pre_read_mtime, this, std::placeholders::_1); regs_mtimecmp.post_write_callback = std::bind(&CLINT::post_write_mtimecmp, this, std::placeholders::_1); regs_msip.post_write_callback = std::bind(&CLINT::post_write_msip, this, std::placeholders::_1); SC_THREAD(run); } uint64_t update_and_get_mtime() override { auto now = sc_core::sc_time_stamp().value() / scaler; if (now > mtime) mtime = now; // do not update backward in time (e.g. due to local quantums in tlm transaction processing) return mtime; } void run() { while (true) { sc_core::wait(irq_event); update_and_get_mtime(); for (unsigned i = 0; i < NumberOfCores; ++i) { auto cmp = mtimecmp[i]; // std::cout << "[vp::clint] process mtimecmp[" << i << "]=" << cmp << ", mtime=" << mtime << std::endl; if (cmp > 0 && mtime >= cmp) { // std::cout << "[vp::clint] set timer interrupt for core " << i << std::endl; target_harts[i]->trigger_timer_interrupt(true); } else { // std::cout << "[vp::clint] unset timer interrupt for core " << i << std::endl; target_harts[i]->trigger_timer_interrupt(false); if (cmp > 0 && cmp < UINT64_MAX) { auto time = sc_core::sc_time::from_value(mtime * scaler); auto goal = sc_core::sc_time::from_value(cmp * scaler); // std::cout << "[vp::clint] time=" << time << std::endl; // std::cout << "[vp::clint] goal=" << goal << std::endl; // std::cout << "[vp::clint] goal-time=delay=" << goal-time << std::endl; irq_event.notify(goal - time); } } } } } bool pre_read_mtime(RegisterRange::ReadInfo t) { sc_core::sc_time now = sc_core::sc_time_stamp() + t.delay; mtime.write(now.value() / scaler); return true; } void post_write_mtimecmp(RegisterRange::WriteInfo t) { // std::cout << "[vp::clint] write mtimecmp[addr=" << t.addr << "]=" << mtimecmp[t.addr / 8] << ", mtime=" << // mtime << std::endl; irq_event.notify(t.delay); } void post_write_msip(RegisterRange::WriteInfo t) { assert(t.addr % 4 == 0); unsigned idx = t.addr / 4; msip[idx] &= 0x1; target_harts[idx]->trigger_software_interrupt(msip[idx] != 0); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { delay += 2 * clock_cycle; vp::mm::route("CLINT", register_ranges, trans, delay); } }; #endif // RISCV_ISA_CLINT_H ================================================ FILE: vp/src/core/common/clint_if.h ================================================ #pragma once #include struct clint_if { virtual ~clint_if() {} virtual uint64_t update_and_get_mtime() = 0; }; ================================================ FILE: vp/src/core/common/core_defs.h ================================================ #pragma once enum Architecture { RV32 = 1, RV64 = 2, RV128 = 3, }; enum class CoreExecStatus { Runnable, HitBreakpoint, Terminated, }; constexpr unsigned SATP_MODE_BARE = 0; constexpr unsigned SATP_MODE_SV32 = 1; constexpr unsigned SATP_MODE_SV39 = 8; constexpr unsigned SATP_MODE_SV48 = 9; constexpr unsigned SATP_MODE_SV57 = 10; constexpr unsigned SATP_MODE_SV64 = 11; ================================================ FILE: vp/src/core/common/debug.h ================================================ #ifndef RISCV_DEBUG #define RISCV_DEBUG #include #include #include #include "core_defs.h" struct debug_target_if { virtual ~debug_target_if() {} virtual void enable_debug(void) = 0; virtual CoreExecStatus get_status(void) = 0; virtual void set_status(CoreExecStatus) = 0; virtual void block_on_wfi(bool) = 0; virtual void insert_breakpoint(uint64_t) = 0; virtual void remove_breakpoint(uint64_t) = 0; virtual Architecture get_architecture(void) = 0; virtual uint64_t get_hart_id(void) = 0; virtual uint64_t get_progam_counter(void) = 0; virtual std::vector get_registers(void) = 0; virtual uint64_t read_register(unsigned) = 0; virtual void run(void) = 0; virtual void run_step(void) = 0; }; #endif ================================================ FILE: vp/src/core/common/debug_memory.cpp ================================================ #include "debug_memory.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include unsigned DebugMemoryInterface::_do_dbg_transaction(tlm::tlm_command cmd, uint64_t addr, uint8_t *data, unsigned num_bytes) { tlm::tlm_generic_payload trans; trans.set_command(cmd); trans.set_address(addr); trans.set_data_ptr(data); trans.set_data_length(num_bytes); trans.set_response_status(tlm::TLM_OK_RESPONSE); unsigned nbytes = isock->transport_dbg(trans); if (trans.is_response_error()) throw std::runtime_error("debug transaction failed"); return nbytes; } std::string DebugMemoryInterface::read_memory(uint64_t start, unsigned nbytes) { std::vector buf(nbytes); // NOTE: every element is zero-initialized by default unsigned nbytes_read = _do_dbg_transaction(tlm::TLM_READ_COMMAND, start, buf.data(), buf.size()); assert(nbytes_read == nbytes && "not all bytes read"); std::stringstream stream; stream << std::setfill('0') << std::hex; for (uint8_t byte : buf) { stream << std::setw(2) << (unsigned)byte; } return stream.str(); } void DebugMemoryInterface::write_memory(uint64_t start, unsigned nbytes, const std::string &data) { unsigned i, j; std::vector buf(data.length() / 2); assert(data.length() % 2 == 0); assert(buf.size() == nbytes); for (j = 0, i = 0; i + 1 < nbytes; j++, i += 2) { long num; char hex[3]; hex[0] = data.at(i); hex[1] = data.at(i+1); hex[2] = '\0'; errno = 0; num = strtol(hex, NULL, 16); if (num == 0 && errno != 0) throw std::system_error(errno, std::generic_category()); assert(num >= 0 && num <= UINT8_MAX); buf.at(j) = (uint8_t)num; } unsigned nbytes_write = _do_dbg_transaction(tlm::TLM_WRITE_COMMAND, start, buf.data(), buf.size()); assert(nbytes_write == nbytes && "not all data written"); } ================================================ FILE: vp/src/core/common/debug_memory.h ================================================ #ifndef RISCV_ISA_DEBUG_MEMORY_H #define RISCV_ISA_DEBUG_MEMORY_H #include #include #include #include #include "core_defs.h" #include "trap.h" struct DebugMemoryInterface : public sc_core::sc_module { tlm_utils::simple_initiator_socket isock; DebugMemoryInterface(sc_core::sc_module_name) {} unsigned _do_dbg_transaction(tlm::tlm_command cmd, uint64_t addr, uint8_t *data, unsigned num_bytes); std::string read_memory(uint64_t start, unsigned nbytes); void write_memory(uint64_t start, unsigned nbytes, const std::string &data); }; #endif // RISCV_ISA_GDB_STUB_H ================================================ FILE: vp/src/core/common/dmi.h ================================================ #pragma once #include class MemoryDMI { uint8_t *mem; uint64_t start; uint64_t size; uint64_t end; MemoryDMI(uint8_t *mem, uint64_t start, uint64_t size) : mem(mem), start(start), size(size), end(start + size) {} public: static MemoryDMI create_start_end_mapping(uint8_t *mem, uint64_t start, uint64_t end) { assert(end > start); return create_start_size_mapping(mem, start, end - start); } static MemoryDMI create_start_size_mapping(uint8_t *mem, uint64_t start, uint64_t size) { assert(start + size > start); return MemoryDMI(mem, start, size); } uint8_t *get_raw_mem_ptr() { return mem; } template T *get_mem_ptr_to_global_addr(uint64_t addr) { assert(contains(addr)); assert((addr + sizeof(T)) <= end); // assert ((addr % sizeof(T)) == 0 && "unaligned access"); //NOTE: due to compressed instructions, fetching // can be unaligned return reinterpret_cast(mem + (addr - start)); } template T load(uint64_t addr) { static_assert(std::is_integral::value, "integer type required"); T ans; T *src = get_mem_ptr_to_global_addr(addr); // use memcpy to avoid problems with unaligned loads into standard C++ data types // see: https://blog.quarkslab.com/unaligned-accesses-in-cc-what-why-and-solutions-to-do-it-properly.html memcpy(&ans, src, sizeof(T)); return ans; } template void store(uint64_t addr, T value) { static_assert(std::is_integral::value, "integer type required"); T *dst = get_mem_ptr_to_global_addr(addr); memcpy(dst, &value, sizeof(value)); } uint64_t get_start() { return start; } uint64_t get_end() { return start + size; } uint64_t get_size() { return size; } bool contains(uint64_t addr) { return addr >= start && addr < end; } }; ================================================ FILE: vp/src/core/common/elf_loader.h ================================================ #pragma once #include #include #include #include #include "load_if.h" template struct GenericElfLoader { typedef typename T::addr_t addr_t; typedef typename T::Elf_Ehdr Elf_Ehdr; typedef typename T::Elf_Phdr Elf_Phdr; typedef typename T::Elf_Shdr Elf_Shdr; typedef typename T::Elf_Sym Elf_Sym; static_assert(sizeof(addr_t) == sizeof(Elf_Ehdr::e_entry), "architecture mismatch"); const char *filename; boost::iostreams::mapped_file_source elf; const Elf_Ehdr *hdr; struct load_executable_exception : public std::exception { const char * what () const throw () { return "Tried loading invalid elf layout"; } }; GenericElfLoader(const char *filename) : filename(filename), elf(filename) { assert(elf.is_open() && "file not open"); hdr = reinterpret_cast(elf.data()); } std::vector get_load_sections() { std::vector sections; for (int i = 0; i < hdr->e_phnum; ++i) { const Elf_Phdr *p = reinterpret_cast(elf.data() + hdr->e_phoff + hdr->e_phentsize * i); if (p->p_type != T::PT_LOAD) continue; if ((p->p_filesz == 0) && (p->p_memsz == 0)) continue; //If p_memsz is greater than p_filesz, the extra bytes are NOBITS. // -> still, the memory needs to be zero initialized in this case! // if (p->p_memsz > p->p_filesz) // continue; sections.push_back(p); } return sections; } std::ostream& print_phdr(std::ostream& os, const Elf_Phdr& h, unsigned tabs = 0) { std::string tab(tabs, '\t'); os << tab << "p_type " << h.p_type << std::endl; os << tab << "p_offset "<< h.p_offset << std::endl; os << tab << "p_vaddr " << h.p_vaddr << std::endl; os << tab << "p_paddr " << h.p_paddr << std::endl; os << tab << "p_filesz "<< h.p_filesz << std::endl; os << tab << "p_memsz " << h.p_memsz << std::endl; os << tab << "p_flags " << h.p_flags << std::endl; os << tab << "p_align " << h.p_align << std::endl; return os; } void load_executable_image(load_if &load_if, addr_t size, addr_t offset, bool use_vaddr = true) { for (auto p : get_load_sections()) { auto addr = p->p_paddr; if (use_vaddr) addr = p->p_vaddr; // If the modeled virtual platform separates Flash and DRAM // (like the hifive-vp does) we call load_executable_image // once for each memory segment (i.e. once for the Flash and // once for the DRAM). As such, we must skip all ELF regions // which are not covered by the passed memory segment. if (!(addr >= offset && addr < (offset + size))) continue; if (addr < offset) { std::cerr << "[elf_loader] "; std::cerr << "Offset overlaps into section:" << std::endl; std::cerr << "\t0x" << std::hex << +addr << " < " << +offset << std::endl; print_phdr(std::cerr, *p, 2); throw load_executable_exception(); } if (addr + p->p_memsz >= offset + size) { std::cerr << "[elf_loader] "; std::cerr << "Section does not fit in target memory" << std::endl; std::cerr << "\t0x" << std::hex << +addr << " + size 0x" << +p->p_memsz; std::cerr << " would overflow offset 0x" << +offset << " + size 0x" << +size << std::endl; print_phdr(std::cerr, *p, 2); throw load_executable_exception(); } auto idx = addr - offset; const char *src = elf.data() + p->p_offset; auto to_copy = p->p_filesz; load_if.load_data(src, idx, to_copy); assert (p->p_memsz >= p->p_filesz); idx = idx + p->p_filesz; to_copy = p->p_memsz - p->p_filesz; load_if.load_zero(idx, to_copy); } } addr_t get_memory_end() { const Elf_Phdr *last = reinterpret_cast(elf.data() + hdr->e_phoff + hdr->e_phentsize * (hdr->e_phnum - 1)); return last->p_vaddr + last->p_memsz; } addr_t get_heap_addr() { // return first 8 byte aligned address after the memory image auto s = get_memory_end(); return s + s % 8; } addr_t get_entrypoint() { return hdr->e_entry; } const char *get_section_string_table() { assert(hdr->e_shoff != 0 && "string table section not available"); const Elf_Shdr *s = reinterpret_cast(elf.data() + hdr->e_shoff + hdr->e_shentsize * hdr->e_shstrndx); const char *start = elf.data() + s->sh_offset; return start; } const char *get_symbol_string_table() { auto s = get_section(".strtab"); return elf.data() + s->sh_offset; } const Elf_Sym *get_symbol(const char *symbol_name) { const Elf_Shdr *s = get_section(".symtab"); const char *strings = get_symbol_string_table(); assert(s->sh_size % sizeof(Elf_Sym) == 0); auto num_entries = s->sh_size / sizeof(typename T::Elf_Sym); for (unsigned i = 0; i < num_entries; ++i) { const Elf_Sym *p = reinterpret_cast(elf.data() + s->sh_offset + i * sizeof(Elf_Sym)); // std::cout << "check symbol: " << strings + p->st_name << std::endl; if (!strcmp(strings + p->st_name, symbol_name)) { return p; } } throw std::runtime_error("unable to find symbol in the symbol table " + std::string(symbol_name)); } addr_t get_begin_signature_address() { auto p = get_symbol("begin_signature"); return p->st_value; } addr_t get_end_signature_address() { auto p = get_symbol("end_signature"); return p->st_value; } addr_t get_to_host_address() { auto p = get_symbol("tohost"); return p->st_value; } std::vector get_sections(void) { if (hdr->e_shoff == 0) { throw std::runtime_error("unable to find section address, section table not available"); } std::vector sections; for (unsigned i = 0; i < hdr->e_shnum; ++i) { const Elf_Shdr *s = reinterpret_cast(elf.data() + hdr->e_shoff + hdr->e_shentsize * i); sections.push_back(s); } return sections; } const Elf_Shdr *get_section(const char *section_name) { const char *strings = get_section_string_table(); for (auto s : get_sections()) { if (!strcmp(strings + s->sh_name, section_name)) { return s; } } throw std::runtime_error("unable to find section address, section seems not available: " + std::string(section_name)); } }; ================================================ FILE: vp/src/core/common/fp.h ================================================ #pragma once #include // floating-point rounding modes constexpr unsigned FRM_RNE = 0b000; // Round to Nearest, ties to Even constexpr unsigned FRM_RTZ = 0b001; // Round towards Zero constexpr unsigned FRM_RDN = 0b010; // Round Down (towards -inf) constexpr unsigned FRM_RUP = 0b011; // Round Down (towards +inf) constexpr unsigned FRM_RMM = 0b100; // Round to Nearest, ties to Max Magnitude constexpr unsigned FRM_DYN = 0b111; // In instruction’s rm field, selects dynamic rounding mode; In Rounding Mode register, Invalid // NaN values constexpr uint32_t defaultNaNF32UI = 0x7fc00000; constexpr uint64_t defaultNaNF64UI = 0x7FF8000000000000; constexpr float32_t f32_defaultNaN = {defaultNaNF32UI}; constexpr float64_t f64_defaultNaN = {defaultNaNF64UI}; constexpr uint32_t F32_SIGN_BIT = 1 << 31; constexpr uint64_t F64_SIGN_BIT = 1ul << 63; inline bool f32_isNegative(float32_t x) { return x.v & F32_SIGN_BIT; } inline bool f64_isNegative(float64_t x) { return x.v & F64_SIGN_BIT; } inline float32_t f32_neg(float32_t x) { return float32_t{x.v ^ F32_SIGN_BIT}; } inline float64_t f64_neg(float64_t x) { return float64_t{x.v ^ F64_SIGN_BIT}; } inline bool f32_isNaN(float32_t x) { // f32 NaN: // - sign bit can be 0 or 1 // - all exponent bits set // - at least one fraction bit set return ((~x.v & 0x7F800000) == 0) && (x.v & 0x007FFFFF); } inline bool f64_isNaN(float64_t x) { // similar to f32 NaN return ((~x.v & 0x7FF0000000000000) == 0) && (x.v & 0x000FFFFFFFFFFFFF); } struct FpRegs { private: std::array regs; bool is_boxed_f32(float64_t x) { return (x.v >> 32) == (uint32_t)-1; } float32_t unbox_f32(float64_t x) { return float32_t{(uint32_t)x.v}; } float64_t box_f32(float32_t x) { return float64_t{(uint64_t)x.v | 0xFFFFFFFF00000000}; } public: void write(unsigned idx, float32_t x) { write(idx, box_f32(x)); } void write(unsigned idx, float64_t x) { regs[idx] = x; } uint32_t u32(unsigned idx) { // access raw data, e.g. to store to memory return regs[idx].v; } float32_t f32(unsigned idx) { if (is_boxed_f32(regs[idx])) return unbox_f32(regs[idx]); else return f32_defaultNaN; } float64_t f64(unsigned idx) { return regs[idx]; } }; ================================================ FILE: vp/src/core/common/gdb-mc/CMakeLists.txt ================================================ add_subdirectory(libgdb) add_library(gdb-mc gdb_server.cpp gdb_runner.cpp register_format.cpp handler.cpp) target_link_libraries(gdb-mc gdb core-common systemc) ================================================ FILE: vp/src/core/common/gdb-mc/gdb_runner.cpp ================================================ #include "gdb_runner.h" GDBServerRunner::GDBServerRunner(sc_core::sc_module_name name, GDBServer *server, debug_target_if *hart) { (void)name; this->hart = hart; this->server = server; this->stop_event = server->get_stop_event(hart); server->set_run_event(hart, &this->run_event); hart->enable_debug(); SC_THREAD(run); } void GDBServerRunner::run(void) { for (;;) { sc_core::wait(run_event); if (server->single_run) { hart->run_step(); if (hart->get_status() == CoreExecStatus::Runnable) hart->set_status(CoreExecStatus::HitBreakpoint); } else { hart->run(); } stop_event->notify(); if (hart->get_status() == CoreExecStatus::Terminated) break; } } ================================================ FILE: vp/src/core/common/gdb-mc/gdb_runner.h ================================================ #ifndef RISCV_GDB_RUNNER #define RISCV_GDB_RUNNER #include #include "debug.h" #include "gdb_server.h" SC_MODULE(GDBServerRunner) { public: SC_HAS_PROCESS(GDBServerRunner); GDBServerRunner(sc_core::sc_module_name, GDBServer *, debug_target_if *); private: GDBServer *server; debug_target_if *hart; sc_core::sc_event run_event; sc_core::sc_event *stop_event; void run(void); }; #endif ================================================ FILE: vp/src/core/common/gdb-mc/gdb_server.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gdb_server.h" #include "platform/common/async_event.h" extern std::map handlers; GDBServer::GDBServer(sc_core::sc_module_name name, std::vector targets, DebugMemoryInterface *mm, uint16_t port, std::vector mmus) { (void)name; if (targets.size() <= 0) throw std::invalid_argument("no harts specified"); if (mmus.size() > 0 && mmus.size() != targets.size()) throw std::invalid_argument("invalid amount of MMUs specified"); for (size_t i = 0; i < targets.size(); i++) { debug_target_if *target = targets.at(i); harts.push_back(target); events[target] = std::make_tuple(new sc_core::sc_event, (sc_core::sc_event *)NULL); if (mmus.size() > 0) mmu[target] = mmus.at(i); /* Don't block on WFI, otherwise the run_threads method * does not work correctly. Allowing blocking WFI would * likely increase the performance */ target->block_on_wfi(false); } memory = mm; arch = harts.at(0)->get_architecture(); // assuming all harts use the same prevpkt = NULL; create_sock(port); SC_THREAD(run); thr = std::thread(&GDBServer::serve, this); thr.detach(); } sc_core::sc_event *GDBServer::get_stop_event(debug_target_if *hart) { return std::get<0>(events.at(hart)); } void GDBServer::set_run_event(debug_target_if *hart, sc_core::sc_event *event) { std::get<1>(events.at(hart)) = event; } void GDBServer::create_sock(uint16_t port) { struct sockaddr_in addr; int reuse; sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) throw std::system_error(errno, std::generic_category()); reuse = 1; if (setsockopt(sockfd, SOL_TCP, TCP_NODELAY, &reuse, sizeof(reuse)) == -1) goto err; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) == -1) goto err; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); addr.sin_port = htons(port); if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) goto err; if (listen(sockfd, 0) == -1) goto err; return; err: close(sockfd); throw std::system_error(errno, std::generic_category()); } std::vector GDBServer::get_threads(int id) { if (id == GDB_THREAD_ANY) id = 1; /* pick the first thread */ if (id == GDB_THREAD_ALL) return harts; if (id < 1) /* thread ids should start at index 1 */ throw std::out_of_range("Thread id is too small"); else id--; std::vector v; v.push_back(harts.at(id)); return v; } uint64_t GDBServer::translate_addr(debug_target_if *hart, uint64_t addr, MemoryAccessType type) { mmu_memory_if *mmu_if; try { mmu_if = mmu.at(hart); } catch (const std::out_of_range&) { mmu_if = NULL; } if (!mmu_if) { return addr; } else { return mmu_if->v2p(addr, type); } } void GDBServer::exec_thread(thread_func fn, char op) { int thread; std::vector threads; try { thread = thread_ops.at(op); } catch (const std::out_of_range&) { thread = GDB_THREAD_ANY; } threads = get_threads(thread); for (debug_target_if *thread : threads) fn(thread); } std::vector GDBServer::run_threads(std::vector hartsrun, bool single) { if (hartsrun.empty()) { return hartsrun; } this->single_run = single; /* invoke all selected harts */ sc_core::sc_event_or_list allharts; for (debug_target_if *hart : hartsrun) { sc_core::sc_event *stop_event, *run_event; std::tie (stop_event, run_event) = this->events.at(hart); run_event->notify(); allharts |= *stop_event; } /* wait until the first hart finishes execution */ sc_core::wait(allharts); /* ensure that all running harts are stopped */ std::vector orig_status; for (debug_target_if *hart : hartsrun) { CoreExecStatus status = hart->get_status(); orig_status.push_back(status); if (status != CoreExecStatus::Runnable) continue; hart->set_status(CoreExecStatus::HitBreakpoint); sc_core::sc_event &stopev = *get_stop_event(hart); sc_core::wait(stopev); } /* restore original hart status */ assert(orig_status.size() == hartsrun.size()); for (size_t i = 0; i < hartsrun.size(); i++) hartsrun[i]->set_status(orig_status[i]); return hartsrun; } void GDBServer::writeall(int fd, char *data, size_t len) { ssize_t ret, w; w = 0; do { assert(len >= (size_t)w); ret = write(fd, &data[w], len - (size_t)w); if (ret < 0) throw std::system_error(errno, std::generic_category()); w += ret; } while ((size_t)w < len); } void GDBServer::send_packet(int conn, const char *data, gdb_kind_t kind) { char *serialized; serialized = gdb_serialize(kind, data); try { writeall(conn, serialized, strlen(serialized)); } catch (const std::system_error& e) { warnx("writeall failed: %s", e.what()); goto ret; } /* acknowledgment are only used for GDB packets */ if (kind != GDB_KIND_PACKET) goto ret; free(prevpkt); if (!(prevpkt = strdup(serialized))) { prevpkt = NULL; free(serialized); throw std::system_error(errno, std::generic_category()); } ret: free(serialized); } void GDBServer::retransmit(int conn) { if (!prevpkt) return; try { writeall(conn, prevpkt, strlen(prevpkt)); } catch (const std::system_error& e) { warnx("writeall failed: %s", e.what()); } /* memory for prevpkt is freed on next successfull * packet transmit in the send_packet function */ } void GDBServer::dispatch(int conn) { FILE *stream; gdb_packet_t *pkt; if (!(stream = fdopen(conn, "r"))) throw std::system_error(errno, std::generic_category()); for (;;) { mtx.lock(); if (!(pkt = gdb_parse_pkt(stream))) { mtx.unlock(); break; } pktq.push(std::make_tuple(conn, pkt)); asyncEvent.notify(); /* further processing is performed in the SystemC run() * thread which interacts with the ISS objects and * unlocks the mutex after finishing all operations. */ } fclose(stream); } void GDBServer::serve(void) { int conn; for (;;) { if ((conn = accept(sockfd, NULL, NULL)) == -1) { warn("accept failed"); continue; } dispatch(conn); close(conn); free(prevpkt); prevpkt = NULL; } } void GDBServer::run(void) { int conn; gdb_command_t *cmd; gdb_packet_t *pkt; packet_handler handler; for (;;) { sc_core::wait(asyncEvent); auto ctx = pktq.front(); std::tie (conn, pkt) = ctx; switch (pkt->kind) { case GDB_KIND_NACK: retransmit(conn); /* fall through */ case GDB_KIND_ACK: goto next1; default: break; } if (!(cmd = gdb_parse_cmd(pkt))) { send_packet(conn, NULL, GDB_KIND_NACK); goto next1; } send_packet(conn, NULL, GDB_KIND_ACK); try { handler = handlers.at(cmd->name); } catch (const std::out_of_range&) { // For any command not supported by the stub, an // empty response (‘$#00’) should be returned. send_packet(conn, ""); goto next2; } (this->*handler)(conn, cmd); next2: gdb_free_cmd(cmd); next1: gdb_free_packet(pkt); pktq.pop(); mtx.unlock(); } } ================================================ FILE: vp/src/core/common/gdb-mc/gdb_server.h ================================================ #ifndef RISCV_GDB_NG #define RISCV_GDB_NG #include #include #include #include #include #include #include #include #include #include #include #include #include "debug.h" #include "core_defs.h" #include "platform/common/async_event.h" #include "debug_memory.h" // DebugMemoryInterface SC_MODULE(GDBServer) { public: typedef void (GDBServer::*packet_handler)(int, gdb_command_t *); void haltReason(int, gdb_command_t *); void getRegisters(int, gdb_command_t *); void setThread(int, gdb_command_t *); void killServer(int, gdb_command_t *); void readMemory(int, gdb_command_t *); void writeMemory(int, gdb_command_t *); void readRegister(int, gdb_command_t *); void qAttached(int, gdb_command_t *); void qSupported(int, gdb_command_t *); void threadInfo(int, gdb_command_t *); void threadInfoEnd(int, gdb_command_t *); void vCont(int, gdb_command_t *); void vContSupported(int, gdb_command_t *); void removeBreakpoint(int, gdb_command_t *); void setBreakpoint(int, gdb_command_t *); void isAlive(int, gdb_command_t *); SC_HAS_PROCESS(GDBServer); GDBServer(sc_core::sc_module_name, std::vector, DebugMemoryInterface*, uint16_t, std::vector mmus = {}); /* Used by GDBRunner to determine whether run() or run_step() * should be used when receiving a run event for a debug_target_if. * * TODO: Pass this on a per-event basis instead. */ bool single_run = false; sc_core::sc_event *get_stop_event(debug_target_if *); void set_run_event(debug_target_if *, sc_core::sc_event *); private: typedef std::function thread_func; typedef std::tuple ctx; typedef std::tuple hart_event; DebugMemoryInterface *memory; AsyncEvent asyncEvent; Architecture arch; std::vector harts; std::thread thr; char *prevpkt; std::queue pktq; std::mutex mtx; int sockfd; /* operation → thread id */ std::map thread_ops; /* hart → events */ std::map events; /* hart → mmu */ std::map mmu; void create_sock(uint16_t); std::vector get_threads(int); uint64_t translate_addr(debug_target_if *, uint64_t, MemoryAccessType type); void exec_thread(thread_func, char = 'g'); std::vector run_threads(std::vector, bool = false); void writeall(int, char *, size_t); void send_packet(int, const char *, gdb_kind_t = GDB_KIND_PACKET); void retransmit(int); void dispatch(int conn); void serve(void); void run(void); }; #endif ================================================ FILE: vp/src/core/common/gdb-mc/handler.cpp ================================================ #include #include #include #include #include "debug.h" #include "gdb_server.h" #include "register_format.h" enum { GDB_PKTSIZ = 4096, GDB_PC_REG = 32, }; std::map handlers { { "?", &GDBServer::haltReason }, { "g", &GDBServer::getRegisters }, { "H", &GDBServer::setThread }, { "k", &GDBServer::killServer }, { "m", &GDBServer::readMemory }, { "M", &GDBServer::writeMemory }, { "p", &GDBServer::readRegister }, { "qAttached", &GDBServer::qAttached }, { "qSupported", &GDBServer::qSupported }, { "qfThreadInfo", &GDBServer::threadInfo }, { "qsThreadInfo", &GDBServer::threadInfoEnd }, { "T", &GDBServer::isAlive }, { "vCont", &GDBServer::vCont }, { "vCont?", &GDBServer::vContSupported }, { "z", &GDBServer::removeBreakpoint }, { "Z", &GDBServer::setBreakpoint }, }; void GDBServer::haltReason(int conn, gdb_command_t *cmd) { (void)cmd; // If n is a recognized stop reason […]. The aa should be // ‘05’, the trap signal. At most one stop reason should be // present. // TODO: Only send create conditionally. send_packet(conn, "S05"); } void GDBServer::getRegisters(int conn, gdb_command_t *cmd) { (void)cmd; auto formatter = new RegisterFormater(arch); auto fn = [formatter] (debug_target_if *hart) { for (uint64_t v : hart->get_registers()) formatter->formatRegister(v); }; exec_thread(fn); send_packet(conn, formatter->str().c_str()); delete formatter; } void GDBServer::setThread(int conn, gdb_command_t *cmd) { gdb_cmd_h_t *hcmd; hcmd = &cmd->v.hcmd; thread_ops[hcmd->op] = hcmd->id.tid; send_packet(conn, "OK"); } void GDBServer::killServer(int conn, gdb_command_t *cmd) { (void)conn; (void)cmd; // TODO: Stop the System C simulation instead of // terminating the program. This would require interacting // with the GDBServerRunner directly to make it exit. // // This could be implemented by adding sys_exit to // debug_target_if, however, some SystemC modules, e.g. FU540_PLIC // also spawn threads which are not stopped at all. These // modules need to be fixed first. exit(EXIT_SUCCESS); } void GDBServer::readMemory(int conn, gdb_command_t *cmd) { gdb_memory_t *mem; mem = &cmd->v.mem; assert(mem->addr <= UINT64_MAX); assert(mem->length <= UINT_MAX); std::string retval; auto fn = [this, &retval, mem] (debug_target_if *hart) { uint64_t addr = translate_addr(hart, mem->addr, LOAD); retval += memory->read_memory(addr, (unsigned)mem->length); }; try { exec_thread(fn); } catch (const std::runtime_error&) { /* exception raised in fn */ send_packet(conn, "E01"); return; } send_packet(conn, retval.c_str()); } void GDBServer::writeMemory(int conn, gdb_command_t *cmd) { gdb_memory_t *loc; gdb_memory_write_t *mem; mem = &cmd->v.memw; loc = &mem->location; assert(loc->addr <= UINT64_MAX); assert(loc->length <= UINT_MAX); auto fn = [this, loc, mem] (debug_target_if *hart) { uint64_t addr = translate_addr(hart, loc->addr, STORE); memory->write_memory(addr, (unsigned)loc->length, mem->data); }; try { exec_thread(fn); } catch (const std::runtime_error&) { send_packet(conn, "E01"); return; } send_packet(conn, "OK"); } void GDBServer::readRegister(int conn, gdb_command_t *cmd) { int reg; auto formatter = new RegisterFormater(arch); reg = cmd->v.ival; auto fn = [formatter, reg] (debug_target_if *hart) { uint64_t regval; if (reg == GDB_PC_REG) { regval = hart->get_progam_counter(); } else { regval = hart->read_register(reg); } /* TODO: handle CSRs? */ formatter->formatRegister(regval); }; try { exec_thread(fn); } catch (const std::out_of_range&) { /* exception raised in fn */ send_packet(conn, "E01"); goto ret; } send_packet(conn, formatter->str().c_str()); ret: delete formatter; } void GDBServer::threadInfo(int conn, gdb_command_t *cmd) { (void)cmd; std::string thrlist = "m"; /* TODO: refactor this to make it always output hex digits, * preferablly move it to the protocol code/ */ for (size_t i = 0; i < harts.size(); i++) { debug_target_if *hart = harts.at(i); if (hart->get_status() == CoreExecStatus::Terminated) continue; thrlist += std::to_string(hart->get_hart_id() + 1); if (i + 1 < harts.size()) thrlist += ","; } send_packet(conn, thrlist.c_str()); } void GDBServer::threadInfoEnd(int conn, gdb_command_t *cmd) { (void)cmd; // GDB will respond to each reply with a request for more thread // ids (using the ‘qs’ form of the query), until the target // responds with ‘l’ (lower-case ell, for last). // // Since the GDBServer::threadInfo sends all threads in one // response we always terminate the list here. send_packet(conn, "l"); } void GDBServer::qAttached(int conn, gdb_command_t *cmd) { (void)cmd; // 0 process started, 1 attached to process send_packet(conn, "0"); } void GDBServer::qSupported(int conn, gdb_command_t *cmd) { (void)cmd; send_packet(conn, ("vContSupported+;PacketSize=" + std::to_string(GDB_PKTSIZ)).c_str()); } void GDBServer::isAlive(int conn, gdb_command_t *cmd) { gdb_thread_t *thr; thr = &cmd->v.tval; try { get_threads(thr->tid); } catch (const std::out_of_range&) { send_packet(conn, "E01"); return; } send_packet(conn, "OK"); } void GDBServer::vCont(int conn, gdb_command_t *cmd) { gdb_vcont_t *vcont; int stopped_thread = -1; const char *stop_reason = NULL; std::map matched; /* This handler attempts to implement the all-stop mode. * See: https://sourceware.org/gdb/onlinedocs/gdb/All_002dStop-Mode.html */ vcont = cmd->v.vval; for (vcont = cmd->v.vval; vcont; vcont = vcont->next) { bool single = false; if (vcont->action == 's') single = true; else if (vcont->action != 'c') throw std::invalid_argument("Unimplemented vCont action"); /* TODO */ std::vector selected_harts; try { auto run = get_threads(vcont->thread.tid); for (auto i = run.begin(); i != run.end();) { debug_target_if *hart = *i; if (matched.count(hart)) i = run.erase(i); /* already matched */ else i++; } selected_harts = run_threads(run, single); } catch (const std::out_of_range&) { send_packet(conn, "E01"); return; } for (debug_target_if *hart : selected_harts) { switch (hart->get_status()) { case CoreExecStatus::HitBreakpoint: stop_reason = "05"; stopped_thread = hart->get_hart_id() + 1; /* mark runnable again */ hart->set_status(CoreExecStatus::Runnable); break; case CoreExecStatus::Terminated: stop_reason = "03"; stopped_thread = hart->get_hart_id() + 1; break; case CoreExecStatus::Runnable: continue; } } /* The vCont specification mandates that only the leftmost action with * a matching thread-id is applied. Unfortunately, the specification * is a bit unclear in regards to handling two actions with no thread * id (i.e. GDB_THREAD_ALL). */ if (vcont->thread.tid > 0) { auto threads = get_threads(vcont->thread.tid); assert(threads.size() == 1); matched[threads.front()] = true; } } assert(stop_reason && stopped_thread >= 1); /* This sets the current thread for various follow-up * operations, most importantly readRegister. Without this * change gdb reads the registers of the previously selected * thread and doesn't switch threads properly if a thread other * than the currently selected hits a breakpoint. * * XXX: No idea if the stub is really required to do this. */ thread_ops['g'] = stopped_thread; const std::string msg = std::string("T") + stop_reason + "thread:" + std::to_string(stopped_thread) + ";"; send_packet(conn, msg.c_str()); } void GDBServer::vContSupported(int conn, gdb_command_t *cmd) { (void)cmd; // We need to support both c and C otherwise GDB doesn't use vCont // This is documented in the remote_vcont_probe function in the GDB source. send_packet(conn, "vCont;c;C"); } void GDBServer::removeBreakpoint(int conn, gdb_command_t *cmd) { gdb_breakpoint_t *bpoint; bpoint = &cmd->v.bval; if (bpoint->type != GDB_ZKIND_SOFT) { send_packet(conn, ""); /* not supported */ return; } for (debug_target_if *hart : harts) hart->remove_breakpoint(bpoint->address); send_packet(conn, "OK"); } void GDBServer::setBreakpoint(int conn, gdb_command_t *cmd) { gdb_breakpoint_t *bpoint; bpoint = &cmd->v.bval; if (bpoint->type != GDB_ZKIND_SOFT) { send_packet(conn, ""); /* not supported */ return; } for (debug_target_if *hart : harts) hart->insert_breakpoint(bpoint->address); send_packet(conn, "OK"); } ================================================ FILE: vp/src/core/common/gdb-mc/libgdb/CMakeLists.txt ================================================ add_library(gdb mpc/mpc.c parser1.c parser2.c response.c util.c) target_compile_options(gdb PRIVATE -Wpedantic -Wall -Wextra -Wconversion -Wmissing-prototypes -Wpointer-arith -Wstrict-prototypes -Wshadow -Wcast-align) set_source_files_properties(mpc/mpc.c PROPERTIES COMPILE_FLAGS "-w -ansi") target_include_directories(gdb PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/mpc) target_include_directories(gdb PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) ================================================ FILE: vp/src/core/common/gdb-mc/libgdb/README.md ================================================ # libgdb Utility library for implementing the [GDB protocol][gdb protocol]. ## Design Unfortunately, the GDB protocol doesn't use delimiters for protocol messages. For this reason, a state machine is required to read packets from a stream. This library implements such a state machine using a parser combinator library. This state machine only returns a generic package structure and doesn't perform any further canonicalization. Since proper canonicalization of GDB packets is desirable this utility library provides two parser stages. The first stage is the aforementioned state machine, the second parser stages performs packet specific validations and uses the most restrictive input definition on a per packet basis. This library attempts to follow some of the [langsec][langsec website] principles outlined in [\[1\]][curing the vulnerable parsers]. Unfortunately, the second stage parser is unfinished at the moment and has a fallback for accepting arbitrary inputs currently, thereby circumventing the "most restrictive input definition". Additionally, some utility functions for creating responses to received GDB packets are provided by `libgdb/response.h`. However, this part of the library is in very early stages of development. [gdb protocol]: https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html [langsec website]: http://langsec.org/ [curing the vulnerable parsers]: https://www.usenix.org/publications/login/spring2017/bratus ================================================ FILE: vp/src/core/common/gdb-mc/libgdb/include/libgdb/parser1.h ================================================ #ifndef LIBGDB_PARSER1_H #define LIBGDB_PARSER1_H #ifdef __cplusplus extern "C" { #endif #include #include #include #define GDB_CSUM_LEN 2 typedef enum { GDB_KIND_NOTIFY, GDB_KIND_PACKET, GDB_KIND_NACK, GDB_KIND_ACK, } gdb_kind_t; typedef struct { gdb_kind_t kind; char *data; char csum[GDB_CSUM_LEN]; } gdb_packet_t; void gdb_free_packet(gdb_packet_t *); gdb_packet_t *gdb_parse_pkt(FILE *); #ifdef __cplusplus } #endif #endif ================================================ FILE: vp/src/core/common/gdb-mc/libgdb/include/libgdb/parser2.h ================================================ #ifndef LIBGDB_PARSER2_H #define LIBGDB_PARSER2_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #ifndef LIBGDB_ADDR_TYPE #define LIBGDB_ADDR_TYPE uint64_t #endif #ifndef LIBGDB_ADDR_FORMAT #define LIBGDB_ADDR_FORMAT SCNx64 #endif typedef LIBGDB_ADDR_TYPE gdb_addr_t; #undef LIBGDB_ADDR_TYPE enum { GDB_THREAD_UNSET = -2, GDB_THREAD_ANY = 0, GDB_THREAD_ALL = -1, }; typedef struct { int pid; /* requires multiprocess feature */ int tid; } gdb_thread_t; typedef enum { GDB_ZKIND_SOFT = 0, GDB_ZKIND_HARD, GDB_ZKIND_WATCHW, GDB_ZKIND_WATCHR, GDB_ZKIND_WATCHA, } gdb_ztype_t; typedef struct { gdb_ztype_t type; gdb_addr_t address; size_t kind; } gdb_breakpoint_t; typedef struct { gdb_addr_t addr; size_t length; } gdb_memory_t; typedef struct { gdb_memory_t location; char *data; /* null-terminated hexstring */ } gdb_memory_write_t; typedef struct { char op; gdb_thread_t id; } gdb_cmd_h_t; typedef struct _gdb_vcont_t gdb_vcont_t; struct _gdb_vcont_t { char action; int sig; /* -1 if unset */ gdb_thread_t thread; gdb_vcont_t *next; /* NULL on end */ }; typedef enum { GDB_ARG_NONE, GDB_ARG_VCONT, GDB_ARG_H, GDB_ARG_INT, GDB_ARG_MEMORY, GDB_ARG_MEMORYW, GDB_ARG_BREAK, GDB_ARG_THREAD, } gdb_argument_t; typedef struct { char *name; gdb_argument_t type; union { gdb_vcont_t *vval; gdb_cmd_h_t hcmd; int ival; gdb_memory_t mem; gdb_memory_write_t memw; gdb_breakpoint_t bval; gdb_thread_t tval; } v; } gdb_command_t; void gdb_free_cmd(gdb_command_t *); gdb_command_t *gdb_parse_cmd(gdb_packet_t *); #ifdef __cplusplus } #endif #endif ================================================ FILE: vp/src/core/common/gdb-mc/libgdb/include/libgdb/response.h ================================================ #ifndef LIBGDB_RESPONSE_H #define LIBGDB_RESPONSE_H #ifdef __cplusplus extern "C" { #endif /* Copied from QEMU * See: https://github.com/qemu/qemu/blob/d37147997/gdbstub.c#L103-L113 */ typedef enum { GDB_SIGNAL_0 = 0, GDB_SIGNAL_INT = 2, GDB_SIGNAL_QUIT = 3, GDB_SIGNAL_TRAP = 5, GDB_SIGNAL_ABRT = 6, GDB_SIGNAL_ALRM = 14, GDB_SIGNAL_IO = 23, GDB_SIGNAL_XCPU = 24, GDB_SIGNAL_UNKNOWN = 143 } gdb_signal_t; char *gdb_serialize(gdb_kind_t, const char *); #ifdef __cplusplus } #endif #endif ================================================ FILE: vp/src/core/common/gdb-mc/libgdb/internal.h ================================================ #ifndef GDB_PROTOCOL_FNS #define GDB_PROTOCOL_FNS #include #include #include #ifdef NDEBUG #define xassert(X) ((void)(X)) /* prevent -Wunused-parameter warning */ #else #define xassert(X) (assert(X)) #endif void *xrealloc(void *, size_t); void *xmalloc(size_t); char *xstrdup(char *); gdb_command_t *gdb_new_cmd(char *, gdb_argument_t); int calc_csum(const char *); bool gdb_is_valid(gdb_packet_t *); char *gdb_unescape(char *); char *gdb_decode_runlen(char *); #endif ================================================ FILE: vp/src/core/common/gdb-mc/libgdb/parser1.c ================================================ #include #include #include #include #include "mpc.h" #include "internal.h" static mpc_val_t * gdbf_packet(int n, mpc_val_t** xs) { gdb_packet_t *pkt; char *start, *csum; xassert(n == 3); pkt = xmalloc(sizeof(*pkt)); pkt->data = (char*)xs[1]; start = (char*)xs[0]; switch (*start) { case '%': pkt->kind = GDB_KIND_NOTIFY; break; case '$': pkt->kind = GDB_KIND_PACKET; break; default: xassert(0); } csum = (char*)xs[2]; csum++; /* skip leading '#' */ memcpy(pkt->csum, csum, GDB_CSUM_LEN); /* data (xs[1]) is still used in struct, don't free it */ free(xs[0]); free(xs[2]); return pkt; } static mpc_val_t * gdbf_acknowledge(mpc_val_t* xs) { gdb_packet_t *pkt; char *str; pkt = xmalloc(sizeof(*pkt)); pkt->data = NULL; memset(pkt->csum, 0, GDB_CSUM_LEN); str = (char*)xs; switch (*str) { case '+': pkt->kind = GDB_KIND_ACK; break; case '-': pkt->kind = GDB_KIND_NACK; break; default: xassert(0); } free(xs); return pkt; } static mpc_parser_t * gdb_csum(void) { mpc_parser_t *csum; csum = mpc_and(2, mpcf_strfold, mpc_any(), mpc_any(), free); return mpc_and(2, mpcf_strfold, mpc_char('#'), csum, free); } static mpc_parser_t * gdb_packet(void) { mpc_parser_t *data; data = mpc_many(mpcf_strfold, mpc_noneof("#$")); return mpc_and(3, gdbf_packet, mpc_char('$'), data, gdb_csum(), free, free); } static mpc_parser_t * gdb_notification(void) { mpc_parser_t *data; data = mpc_many(mpcf_strfold, mpc_noneof("#$%")); return mpc_and(3, gdbf_packet, mpc_char('%'), data, gdb_csum(), free, free); } static mpc_parser_t * gdb_acknowledge(void) { return mpc_apply(mpc_oneof("+-"), gdbf_acknowledge); } static mpc_parser_t * gdb_parse_stage1(void) { return mpc_or(3, gdb_acknowledge(), gdb_packet(), gdb_notification()); } gdb_packet_t * gdb_parse_pkt(FILE *stream) { gdb_packet_t *pkt; mpc_parser_t *par; mpc_result_t r; pkt = NULL; par = mpc_predictive(gdb_parse_stage1()); if (mpc_parse_pipe("", stream, par, &r)) { pkt = (gdb_packet_t *)r.output; } else { #ifdef GDB_PARSER_DEBUG mpc_err_print(r.error); #endif mpc_err_delete(r.error); } mpc_cleanup(1, par); return pkt; } ================================================ FILE: vp/src/core/common/gdb-mc/libgdb/parser2.c ================================================ #include #include #include #include #include #include "mpc.h" #include "parser2.h" #include "internal.h" static mpc_val_t * gdbf_ignarg(mpc_val_t* xs) { char *str, *sep; gdb_command_t *cmd; str = (char *)xs; if ((sep = strchr(str, ':'))) *sep = '\0'; cmd = gdb_new_cmd(xstrdup(str), GDB_ARG_NONE); free(xs); return cmd; } static mpc_val_t * gdbf_address(mpc_val_t *x) { int r; gdb_addr_t *v; v = xmalloc(sizeof(*v)); r = sscanf((char *)x, "%"LIBGDB_ADDR_FORMAT, v); xassert(r == 1); free(x); return v; } static mpc_parser_t * gdb_address(void) { return mpc_expect(mpc_apply(mpc_hexdigits(), gdbf_address), "hexadecimal address"); } static mpc_val_t * gdbf_uhex(mpc_val_t *x) { int r; size_t *v; v = xmalloc(sizeof(*v)); r = sscanf((char *)x, "%zx", v); xassert(r == 1); free(x); return v; } static mpc_parser_t * gdb_uhex(void) { return mpc_apply(mpc_hexdigits(), gdbf_uhex); } static mpc_val_t * gdbf_negative(mpc_val_t *val) { int *neg; xassert(!strcmp((char*)val, "-1")); neg = xmalloc(sizeof(*neg)); *neg = -1; free(val); return neg; } static mpc_val_t * gdbf_memory(int n, mpc_val_t **xs) { gdb_memory_t *mem; xassert(n == 3); xassert(*(char *)xs[1] == ','); mem = xmalloc(sizeof(*mem)); mem->addr = *((gdb_addr_t *)xs[0]); mem->length = *((size_t *)xs[2]); free(xs[0]); free(xs[1]); free(xs[2]); return mem; } static mpc_parser_t * gdb_memory(void) { return mpc_and(3, gdbf_memory, gdb_address(), mpc_char(','), gdb_uhex(), free, free); } static mpc_val_t * gdbf_thread_id(int n, mpc_val_t** xs) { int *arg1, *arg2; gdb_thread_t *id; xassert(n == 2); id = xmalloc(sizeof(*id)); arg1 = (int*)xs[0]; arg2 = (int*)xs[1]; if (arg1 != NULL) id->pid = *arg1; else id->pid = GDB_THREAD_UNSET; id->tid = *arg2; free(xs[0]); free(xs[1]); return id; } static mpc_parser_t * gdb_hexid(void) { /* Positive numbers with a target-specific interpretation, * formatted as big-endian hex strings. Can also be a literal * '-1' to indicate all threads, or '0' to pick any thread. */ return mpc_or(2, mpc_hex(), mpc_apply(mpc_string("-1"), gdbf_negative)); } static mpc_parser_t * gdb_thread_id(void) { mpc_parser_t *pid, *tid; tid = gdb_hexid(); pid = mpc_and(3, mpcf_snd_free, mpc_char('p'), gdb_hexid(), mpc_char('.'), free, free); return mpc_and(2, gdbf_thread_id, mpc_maybe(pid), tid, free); } gdbf_fold(h, GDB_ARG_H, GDBF_ARG_HCMD) static mpc_parser_t * gdb_packet_h(void) { mpc_parser_t *op, *id; op = mpc_any(); /* (‘m’, ‘M’, ‘g’, ‘G’, et.al.). */ id = gdb_thread_id(); return mpc_and(3, gdbf_packet_h, mpc_char('H'), op, id, free, free); } gdbf_fold(p, GDB_ARG_INT, GDBF_ARG_INT) static mpc_parser_t * gdb_packet_p(void) { return mpc_and(2, gdbf_packet_p, mpc_char('p'), mpc_hex(), free); } static mpc_val_t * gdbf_vcont_action(int n, mpc_val_t **xs) { char *actstr; size_t actlen; gdb_vcont_t *vcont; xassert(n == 2); actstr = (char *)xs[0]; actlen = strlen(actstr); vcont = xmalloc(sizeof(*vcont)); vcont->action = *actstr; vcont->next = NULL; if (actlen == 1) vcont->sig = -1; else if (actlen == 3) vcont->sig = (int)strtol(actstr + 1, NULL, 16); else xassert(0); /* An action with no thread-id matches all threads. */ if (!xs[1]) { vcont->thread.pid = GDB_THREAD_UNSET; vcont->thread.tid = GDB_THREAD_ALL; } else { vcont->thread = *((gdb_thread_t *)xs[1]); } free(xs[0]); free(xs[1]); return vcont; } static mpc_val_t * gdbf_vcont(int n, mpc_val_t **xs) { size_t i; gdb_vcont_t *vcont; xassert(n >= 1); for (vcont = (gdb_vcont_t *)xs[0], i = 1; i < (size_t)n; i++, vcont = vcont->next) vcont->next = (gdb_vcont_t *)xs[i]; vcont->next = NULL; return (gdb_vcont_t *)xs[0]; } gdbf_fold(vcont, GDB_ARG_VCONT, GDBF_ARG_VCONT) static mpc_parser_t * gdb_packet_vcont(void) { mpc_parser_t *action0, *action1, *action, *args, *thread; /* TODO: add support for r command */ action0 = mpc_oneof("cst"); action1 = mpc_and(2, mpcf_strfold, mpc_oneof("CS"), mpc_hexdigits()); thread = mpc_and(2, mpcf_snd_free, mpc_char(':'), gdb_thread_id(), free); action = mpc_and(2, gdbf_vcont_action, mpc_or(2, action0, action1), mpc_maybe(thread), free); /* destructor incorrect but unused */ args = mpc_many1(gdbf_vcont, mpc_and(2, mpcf_snd_free, mpc_char(';'), action, free)); return mpc_and(2, gdbf_packet_vcont, mpc_string("vCont"), args, free); } gdbf_fold(m, GDB_ARG_MEMORY, GDBF_ARG_MEMORY) static mpc_parser_t * gdb_packet_m(void) { return mpc_and(2, gdbf_packet_m, mpc_char('m'), gdb_memory(), free); } gdbf_fold(M, GDB_ARG_MEMORYW, GDBF_ARG_MEMORYW) static mpc_parser_t * gdb_packet_M(void) { return mpc_and(4, gdbf_packet_M, mpc_char('M'), gdb_memory(), mpc_char(':'), mpc_hexdigits(), free, free, free); } static mpc_parser_t * gdb_arg(mpc_parser_t *par) { return mpc_and(2, mpcf_fst_free, par, mpc_char(','), free); } gdbf_fold(z, GDB_ARG_BREAK, GDBF_ARG_BREAK) static mpc_parser_t * gdb_packet_z(void) { mpc_parser_t *name, *type; /* TODO: parse cond_list */ name = mpc_or(2, mpc_char('z'), mpc_char('Z')); type = mpc_apply(mpc_re("[0-4]"), mpcf_int); return mpc_and(4, gdbf_packet_z, name, gdb_arg(type), gdb_arg(gdb_address()), gdb_uhex(), free, free, free); } gdbf_fold(T, GDB_ARG_THREAD, GDBF_ARG_THREAD) static mpc_parser_t * gdb_packet_T(void) { return mpc_and(2, gdbf_packet_T, mpc_char('T'), gdb_thread_id(), free); } static mpc_parser_t * gdb_any(void) { return mpc_apply(mpc_many1(mpcf_strfold, mpc_any()), gdbf_ignarg); } static mpc_parser_t * gdb_cmd(mpc_parser_t *cmd) { return mpc_and(2, mpcf_fst_free, cmd, mpc_eoi(), gdb_free_cmd); } static mpc_parser_t * gdb_parse_stage2(void) { return mpc_or(8, gdb_cmd(gdb_packet_h()), gdb_cmd(gdb_packet_p()), gdb_cmd(gdb_packet_vcont()), gdb_cmd(gdb_packet_m()), gdb_cmd(gdb_packet_M()), gdb_cmd(gdb_packet_z()), gdb_cmd(gdb_packet_T()), gdb_any()); } gdb_command_t * gdb_parse_cmd(gdb_packet_t *pkt) { mpc_result_t r; mpc_parser_t *par; char *data, *unesc; gdb_command_t *cmd; cmd = NULL; par = gdb_parse_stage2(); if (pkt->kind != GDB_KIND_PACKET) { errno = EINVAL; return NULL; } if (!gdb_is_valid(pkt)) { errno = EILSEQ; return NULL; } if (!(data = gdb_decode_runlen(pkt->data))) { errno = EBADMSG; return NULL; } unesc = gdb_unescape(data); free(data); if (mpc_parse("", unesc, par, &r)) { cmd = (gdb_command_t *)r.output; } else { #ifdef GDB_PARSER_DEBUG mpc_err_print(r.error); #endif mpc_err_delete(r.error); } free(unesc); mpc_cleanup(1, par); if (!cmd) errno = EBADMSG; /* mpc_parse failed */ return cmd; } ================================================ FILE: vp/src/core/common/gdb-mc/libgdb/parser2.h ================================================ #define gdbf_fold(I, TYPE, FUNC) \ static mpc_val_t *gdbf_packet_##I(int n, mpc_val_t **xs) \ { \ int j; \ gdb_command_t *cmd; \ \ /* Remove optional mpc_maybe() arguments */ \ for (j = n - 1; j >= 0; j--) \ if (!xs[j]) \ --n; \ \ xassert(n > 0); \ cmd = gdb_new_cmd(xs[0], TYPE); \ FUNC; \ \ return cmd; \ } #define GDBF_ARG_HCMD \ do { \ xassert(n == 3); \ \ cmd->v.hcmd.op = *((char*)xs[1]); \ cmd->v.hcmd.id = *((gdb_thread_t*)xs[2]); \ \ free(xs[1]); \ free(xs[2]); \ } while (0) #define GDBF_ARG_INT \ do { \ xassert(n == 2); \ \ cmd->v.ival = *((int*)xs[1]); \ free(xs[1]); \ } while (0) #define GDBF_ARG_VCONT \ do { \ xassert(n == 2); \ cmd->v.vval = (gdb_vcont_t *)xs[1]; \ } while (0) #define GDBF_ARG_MEMORY \ do { \ xassert(n == 2); \ cmd->v.mem = *((gdb_memory_t *)xs[1]); \ free(xs[1]); \ } while (0) #define GDBF_ARG_MEMORYW \ do { \ xassert(n == 4); \ cmd->v.memw.location = *((gdb_memory_t *)xs[1]); \ cmd->v.memw.data = (char *)xs[3]; \ free(xs[1]); \ free(xs[2]); \ } while (0) #define GDBF_ARG_BREAK \ do { \ int type; \ \ xassert(n == 4); \ type = *(int *)(xs[1]); \ xassert(type >= GDB_ZKIND_SOFT && type <= GDB_ZKIND_WATCHA); \ \ cmd->v.bval.type = (gdb_ztype_t)type; \ cmd->v.bval.address = *((gdb_addr_t *)xs[2]); \ cmd->v.bval.kind = *(size_t *)(xs[3]); \ free(xs[1]); \ free(xs[2]); \ free(xs[3]); \ } while (0) #define GDBF_ARG_THREAD \ do { \ xassert(n == 2); \ cmd->v.tval = *((gdb_thread_t *)xs[1]); \ free(xs[1]); \ } while (0) ================================================ FILE: vp/src/core/common/gdb-mc/libgdb/response.c ================================================ #include #include #include #include #include #include #include #include "internal.h" static char kind_to_char(gdb_kind_t kind) { switch (kind) { case GDB_KIND_NOTIFY: return '#'; case GDB_KIND_PACKET: return '$'; case GDB_KIND_NACK: return '-'; case GDB_KIND_ACK: return '+'; default: xassert(0); return -1; } } char * gdb_serialize(gdb_kind_t kind, const char *data) { size_t pktlen; char *serialized; char pktkind; int csum, ret; pktkind = kind_to_char(kind); if (kind == GDB_KIND_NACK || kind == GDB_KIND_ACK) { xassert(data == NULL); serialized = xmalloc(2); /* kind + nullbyte */ serialized[0] = pktkind; serialized[1] = '\0'; return serialized; } csum = calc_csum(data); /* + 3 → nullbyte, checksum delimiter, kind */ pktlen = strlen(data) + GDB_CSUM_LEN + 3; serialized = xmalloc(pktlen); ret = snprintf(serialized, pktlen, "%c%s#%.2x", pktkind, data, csum); if (ret < 0) err(EXIT_FAILURE, "snprintf failed"); else if ((size_t)ret >= pktlen) errx(EXIT_FAILURE, "insufficient snprintf buffer size"); return serialized; } ================================================ FILE: vp/src/core/common/gdb-mc/libgdb/util.c ================================================ #include #include #include #include #include #include #include #include #include #include #include "internal.h" #define GDB_RUNLEN_CHAR '*' #define GDB_RUNLEN_OFF 29 #define GDB_RUNLEN_STEP 32 #define GDB_ESCAPE_CHAR '}' #define GDB_ESCAPE_BYTE 0x20 int calc_csum(const char *data) { size_t i; int csum = 0; for (i = 0; i < strlen(data); i++) csum += (int)data[i]; return csum % 256; } char * gdb_decode_runlen(char *data) { int rcount, j; size_t i, nlen, nrem; int runlen; char *ndat; nlen = 0; nrem = strlen(data); ndat = xmalloc(nrem); for (runlen = -1, i = 0; i < strlen(data); i++) { if (data[i] == GDB_RUNLEN_CHAR) { if (i <= 0) goto err; runlen = data[i - 1]; continue; } if (runlen == -1) { runlen = data[i]; rcount = 1; } else { rcount = (int)data[i] - GDB_RUNLEN_OFF; if (rcount <= 0) goto err; } for (j = 0; j < rcount; j++) { if (nrem-- == 0) { ndat = xrealloc(ndat, nlen + GDB_RUNLEN_STEP); nrem += GDB_RUNLEN_STEP; } xassert(runlen >= 0 && runlen <= CHAR_MAX); ndat[nlen++] = (char)runlen; } runlen = -1; } /* shrink to actual size */ ndat = xrealloc(ndat, nlen + 1); ndat[nlen] = '\0'; return ndat; err: free(ndat); return NULL; } char * gdb_unescape(char *data) { size_t i, nlen; char *ndat; bool esc; ndat = xmalloc(strlen(data)); nlen = 0; for (esc = false, i = 0; i < strlen(data); i++) { if (data[i] == GDB_ESCAPE_CHAR) { esc = true; continue; } ndat[nlen++] = (esc) ? data[i] ^ GDB_ESCAPE_BYTE : data[i]; esc = false; } /* shrink to actual size */ ndat = xrealloc(ndat, nlen + 1); ndat[nlen] = '\0'; return ndat; } bool gdb_is_valid(gdb_packet_t *pkt) { int ret; int expcsum; char strcsum[GDB_CSUM_LEN + 1]; /* +1 for snprintf nullbyte */ if (!pkt->data) return true; expcsum = calc_csum(pkt->data); ret = snprintf(strcsum, sizeof(strcsum), "%.2x", expcsum); xassert(ret == GDB_CSUM_LEN); return !strncmp(pkt->csum, strcsum, GDB_CSUM_LEN); } gdb_command_t * gdb_new_cmd(char *name, gdb_argument_t type) { gdb_command_t *cmd; cmd = xmalloc(sizeof(*cmd)); cmd->name = name; cmd->type = type; return cmd; } void gdb_free_cmd(gdb_command_t *cmd) { gdb_vcont_t *parent, *next; if (cmd->type == GDB_ARG_MEMORYW) free(cmd->v.memw.data); if (cmd->type == GDB_ARG_VCONT) { parent = cmd->v.vval; while (parent) { next = parent->next; free(parent); parent = next; } } free(cmd->name); free(cmd); } void * xrealloc(void *ptr, size_t size) { void *r; if (!(r = realloc(ptr, size))) err(EXIT_FAILURE, "realloc failed"); return r; } void * xmalloc(size_t size) { void *r; if (!(r = malloc(size))) err(EXIT_FAILURE, "malloc failed"); return r; } char * xstrdup(char *s) { char *r; if (!(r = strdup(s))) err(EXIT_FAILURE, "strdup failed"); return r; } void gdb_free_packet(gdb_packet_t *pkt) { if (pkt->data) free(pkt->data); free(pkt); } ================================================ FILE: vp/src/core/common/gdb-mc/register_format.cpp ================================================ #include #include #include "register_format.h" RegisterFormater::RegisterFormater(Architecture arch) { this->arch = arch; this->stream << std::setfill('0') << std::hex; } void RegisterFormater::formatRegister(uint64_t value) { switch (arch) { case RV32: stream << std::setw(8) << bswap_32(value); break; case RV64: stream << std::setw(16) << bswap_64(value); break; default: throw std::invalid_argument("Architecture not implemented"); } } std::string RegisterFormater::str(void) { return this->stream.str(); } ================================================ FILE: vp/src/core/common/gdb-mc/register_format.h ================================================ #ifndef RISCV_GDB_REGISTER #define RISCV_GDB_REGISTER #include #include #include "core_defs.h" class RegisterFormater { private: Architecture arch; std::ostringstream stream; public: RegisterFormater(Architecture); void formatRegister(uint64_t); std::string str(void); }; #endif ================================================ FILE: vp/src/core/common/instr.cpp ================================================ #include "instr.h" #include "trap.h" #include "util/common.h" #include #include constexpr uint32_t LUI_MASK = 0b00000000000000000000000001111111; constexpr uint32_t LUI_ENCODING = 0b00000000000000000000000000110111; constexpr uint32_t AUIPC_MASK = 0b00000000000000000000000001111111; constexpr uint32_t AUIPC_ENCODING = 0b00000000000000000000000000010111; constexpr uint32_t JAL_MASK = 0b00000000000000000000000001111111; constexpr uint32_t JAL_ENCODING = 0b00000000000000000000000001101111; constexpr uint32_t JALR_MASK = 0b00000000000000000111000001111111; constexpr uint32_t JALR_ENCODING = 0b00000000000000000000000001100111; constexpr uint32_t BEQ_MASK = 0b00000000000000000111000001111111; constexpr uint32_t BEQ_ENCODING = 0b00000000000000000000000001100011; constexpr uint32_t BNE_MASK = 0b00000000000000000111000001111111; constexpr uint32_t BNE_ENCODING = 0b00000000000000000001000001100011; constexpr uint32_t BLT_MASK = 0b00000000000000000111000001111111; constexpr uint32_t BLT_ENCODING = 0b00000000000000000100000001100011; constexpr uint32_t BGE_MASK = 0b00000000000000000111000001111111; constexpr uint32_t BGE_ENCODING = 0b00000000000000000101000001100011; constexpr uint32_t BLTU_MASK = 0b00000000000000000111000001111111; constexpr uint32_t BLTU_ENCODING = 0b00000000000000000110000001100011; constexpr uint32_t BGEU_MASK = 0b00000000000000000111000001111111; constexpr uint32_t BGEU_ENCODING = 0b00000000000000000111000001100011; constexpr uint32_t LB_MASK = 0b00000000000000000111000001111111; constexpr uint32_t LB_ENCODING = 0b00000000000000000000000000000011; constexpr uint32_t LH_MASK = 0b00000000000000000111000001111111; constexpr uint32_t LH_ENCODING = 0b00000000000000000001000000000011; constexpr uint32_t LW_MASK = 0b00000000000000000111000001111111; constexpr uint32_t LW_ENCODING = 0b00000000000000000010000000000011; constexpr uint32_t LBU_MASK = 0b00000000000000000111000001111111; constexpr uint32_t LBU_ENCODING = 0b00000000000000000100000000000011; constexpr uint32_t LHU_MASK = 0b00000000000000000111000001111111; constexpr uint32_t LHU_ENCODING = 0b00000000000000000101000000000011; constexpr uint32_t SB_MASK = 0b00000000000000000111000001111111; constexpr uint32_t SB_ENCODING = 0b00000000000000000000000000100011; constexpr uint32_t SH_MASK = 0b00000000000000000111000001111111; constexpr uint32_t SH_ENCODING = 0b00000000000000000001000000100011; constexpr uint32_t SW_MASK = 0b00000000000000000111000001111111; constexpr uint32_t SW_ENCODING = 0b00000000000000000010000000100011; constexpr uint32_t ADDI_MASK = 0b00000000000000000111000001111111; constexpr uint32_t ADDI_ENCODING = 0b00000000000000000000000000010011; constexpr uint32_t SLTI_MASK = 0b00000000000000000111000001111111; constexpr uint32_t SLTI_ENCODING = 0b00000000000000000010000000010011; constexpr uint32_t SLTIU_MASK = 0b00000000000000000111000001111111; constexpr uint32_t SLTIU_ENCODING = 0b00000000000000000011000000010011; constexpr uint32_t XORI_MASK = 0b00000000000000000111000001111111; constexpr uint32_t XORI_ENCODING = 0b00000000000000000100000000010011; constexpr uint32_t ORI_MASK = 0b00000000000000000111000001111111; constexpr uint32_t ORI_ENCODING = 0b00000000000000000110000000010011; constexpr uint32_t ANDI_MASK = 0b00000000000000000111000001111111; constexpr uint32_t ANDI_ENCODING = 0b00000000000000000111000000010011; //-- RV64 special case (one less mask bit compared to RV32) constexpr uint32_t SLLI_MASK = 0b11111100000000000111000001111111; constexpr uint32_t SLLI_ENCODING = 0b00000000000000000001000000010011; constexpr uint32_t SRLI_MASK = 0b11111100000000000111000001111111; constexpr uint32_t SRLI_ENCODING = 0b00000000000000000101000000010011; constexpr uint32_t SRAI_MASK = 0b11111100000000000111000001111111; constexpr uint32_t SRAI_ENCODING = 0b01000000000000000101000000010011; //-- RV32 case constexpr uint32_t SLLI_32_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SLLI_32_ENCODING = 0b00000000000000000001000000010011; constexpr uint32_t SRLI_32_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SRLI_32_ENCODING = 0b00000000000000000101000000010011; constexpr uint32_t SRAI_32_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SRAI_32_ENCODING = 0b01000000000000000101000000010011; //-- constexpr uint32_t ADD_MASK = 0b11111110000000000111000001111111; constexpr uint32_t ADD_ENCODING = 0b00000000000000000000000000110011; constexpr uint32_t SUB_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SUB_ENCODING = 0b01000000000000000000000000110011; constexpr uint32_t SLL_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SLL_ENCODING = 0b00000000000000000001000000110011; constexpr uint32_t SLT_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SLT_ENCODING = 0b00000000000000000010000000110011; constexpr uint32_t SLTU_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SLTU_ENCODING = 0b00000000000000000011000000110011; constexpr uint32_t XOR_MASK = 0b11111110000000000111000001111111; constexpr uint32_t XOR_ENCODING = 0b00000000000000000100000000110011; constexpr uint32_t SRL_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SRL_ENCODING = 0b00000000000000000101000000110011; constexpr uint32_t SRA_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SRA_ENCODING = 0b01000000000000000101000000110011; constexpr uint32_t OR_MASK = 0b11111110000000000111000001111111; constexpr uint32_t OR_ENCODING = 0b00000000000000000110000000110011; constexpr uint32_t AND_MASK = 0b11111110000000000111000001111111; constexpr uint32_t AND_ENCODING = 0b00000000000000000111000000110011; constexpr uint32_t FENCE_MASK = 0b00000000000000000111000001111111; constexpr uint32_t FENCE_ENCODING = 0b00000000000000000000000000001111; constexpr uint32_t FENCE_I_MASK = 0b00000000000000000111000001111111; constexpr uint32_t FENCE_I_ENCODING = 0b00000000000000000001000000001111; constexpr uint32_t ECALL_MASK = 0b11111111111111111111111111111111; constexpr uint32_t ECALL_ENCODING = 0b00000000000000000000000001110011; constexpr uint32_t EBREAK_MASK = 0b11111111111111111111111111111111; constexpr uint32_t EBREAK_ENCODING = 0b00000000000100000000000001110011; constexpr uint32_t CSRRW_MASK = 0b00000000000000000111000001111111; constexpr uint32_t CSRRW_ENCODING = 0b00000000000000000001000001110011; constexpr uint32_t CSRRS_MASK = 0b00000000000000000111000001111111; constexpr uint32_t CSRRS_ENCODING = 0b00000000000000000010000001110011; constexpr uint32_t CSRRC_MASK = 0b00000000000000000111000001111111; constexpr uint32_t CSRRC_ENCODING = 0b00000000000000000011000001110011; constexpr uint32_t CSRRWI_MASK = 0b00000000000000000111000001111111; constexpr uint32_t CSRRWI_ENCODING = 0b00000000000000000101000001110011; constexpr uint32_t CSRRSI_MASK = 0b00000000000000000111000001111111; constexpr uint32_t CSRRSI_ENCODING = 0b00000000000000000110000001110011; constexpr uint32_t CSRRCI_MASK = 0b00000000000000000111000001111111; constexpr uint32_t CSRRCI_ENCODING = 0b00000000000000000111000001110011; constexpr uint32_t MUL_MASK = 0b11111110000000000111000001111111; constexpr uint32_t MUL_ENCODING = 0b00000010000000000000000000110011; constexpr uint32_t MULH_MASK = 0b11111110000000000111000001111111; constexpr uint32_t MULH_ENCODING = 0b00000010000000000001000000110011; constexpr uint32_t MULHSU_MASK = 0b11111110000000000111000001111111; constexpr uint32_t MULHSU_ENCODING = 0b00000010000000000010000000110011; constexpr uint32_t MULHU_MASK = 0b11111110000000000111000001111111; constexpr uint32_t MULHU_ENCODING = 0b00000010000000000011000000110011; constexpr uint32_t DIV_MASK = 0b11111110000000000111000001111111; constexpr uint32_t DIV_ENCODING = 0b00000010000000000100000000110011; constexpr uint32_t DIVU_MASK = 0b11111110000000000111000001111111; constexpr uint32_t DIVU_ENCODING = 0b00000010000000000101000000110011; constexpr uint32_t REM_MASK = 0b11111110000000000111000001111111; constexpr uint32_t REM_ENCODING = 0b00000010000000000110000000110011; constexpr uint32_t REMU_MASK = 0b11111110000000000111000001111111; constexpr uint32_t REMU_ENCODING = 0b00000010000000000111000000110011; constexpr uint32_t LR_W_MASK = 0b11111001111100000111000001111111; constexpr uint32_t LR_W_ENCODING = 0b00010000000000000010000000101111; constexpr uint32_t SC_W_MASK = 0b11111000000000000111000001111111; constexpr uint32_t SC_W_ENCODING = 0b00011000000000000010000000101111; constexpr uint32_t AMOSWAP_W_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOSWAP_W_ENCODING = 0b00001000000000000010000000101111; constexpr uint32_t AMOADD_W_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOADD_W_ENCODING = 0b00000000000000000010000000101111; constexpr uint32_t AMOXOR_W_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOXOR_W_ENCODING = 0b00100000000000000010000000101111; constexpr uint32_t AMOAND_W_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOAND_W_ENCODING = 0b01100000000000000010000000101111; constexpr uint32_t AMOOR_W_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOOR_W_ENCODING = 0b01000000000000000010000000101111; constexpr uint32_t AMOMIN_W_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOMIN_W_ENCODING = 0b10000000000000000010000000101111; constexpr uint32_t AMOMAX_W_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOMAX_W_ENCODING = 0b10100000000000000010000000101111; constexpr uint32_t AMOMINU_W_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOMINU_W_ENCODING = 0b11000000000000000010000000101111; constexpr uint32_t AMOMAXU_W_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOMAXU_W_ENCODING = 0b11100000000000000010000000101111; constexpr uint32_t URET_MASK = 0b11111111111111111111111111111111; constexpr uint32_t URET_ENCODING = 0b00000000001000000000000001110011; constexpr uint32_t SRET_MASK = 0b11111111111111111111111111111111; constexpr uint32_t SRET_ENCODING = 0b00010000001000000000000001110011; constexpr uint32_t MRET_MASK = 0b11111111111111111111111111111111; constexpr uint32_t MRET_ENCODING = 0b00110000001000000000000001110011; constexpr uint32_t WFI_MASK = 0b11111111111111111111111111111111; constexpr uint32_t WFI_ENCODING = 0b00010000010100000000000001110011; constexpr uint32_t SFENCE_VMA_MASK = 0b11111110000000000111111111111111; constexpr uint32_t SFENCE_VMA_ENCODING = 0b00010010000000000000000001110011; //-- RV64IMA Extension constexpr uint32_t LWU_MASK = 0b00000000000000000111000001111111; constexpr uint32_t LWU_ENCODING = 0b00000000000000000110000000000011; constexpr uint32_t LD_MASK = 0b00000000000000000111000001111111; constexpr uint32_t LD_ENCODING = 0b00000000000000000011000000000011; constexpr uint32_t SD_MASK = 0b00000000000000000111000001111111; constexpr uint32_t SD_ENCODING = 0b00000000000000000011000000100011; constexpr uint32_t ADDIW_MASK = 0b00000000000000000111000001111111; constexpr uint32_t ADDIW_ENCODING = 0b00000000000000000000000000011011; constexpr uint32_t SLLIW_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SLLIW_ENCODING = 0b00000000000000000001000000011011; constexpr uint32_t SRLIW_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SRLIW_ENCODING = 0b00000000000000000101000000011011; constexpr uint32_t SRAIW_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SRAIW_ENCODING = 0b01000000000000000101000000011011; constexpr uint32_t ADDW_MASK = 0b11111110000000000111000001111111; constexpr uint32_t ADDW_ENCODING = 0b00000000000000000000000000111011; constexpr uint32_t SUBW_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SUBW_ENCODING = 0b01000000000000000000000000111011; constexpr uint32_t SLLW_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SLLW_ENCODING = 0b00000000000000000001000000111011; constexpr uint32_t SRLW_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SRLW_ENCODING = 0b00000000000000000101000000111011; constexpr uint32_t SRAW_MASK = 0b11111110000000000111000001111111; constexpr uint32_t SRAW_ENCODING = 0b01000000000000000101000000111011; constexpr uint32_t MULW_MASK = 0b11111110000000000111000001111111; constexpr uint32_t MULW_ENCODING = 0b00000010000000000000000000111011; constexpr uint32_t DIVW_MASK = 0b11111110000000000111000001111111; constexpr uint32_t DIVW_ENCODING = 0b00000010000000000100000000111011; constexpr uint32_t DIVUW_MASK = 0b11111110000000000111000001111111; constexpr uint32_t DIVUW_ENCODING = 0b00000010000000000101000000111011; constexpr uint32_t REMW_MASK = 0b11111110000000000111000001111111; constexpr uint32_t REMW_ENCODING = 0b00000010000000000110000000111011; constexpr uint32_t REMUW_MASK = 0b11111110000000000111000001111111; constexpr uint32_t REMUW_ENCODING = 0b00000010000000000111000000111011; constexpr uint32_t LR_D_MASK = 0b11111001111100000111000001111111; constexpr uint32_t LR_D_ENCODING = 0b00010000000000000011000000101111; constexpr uint32_t SC_D_MASK = 0b11111000000000000111000001111111; constexpr uint32_t SC_D_ENCODING = 0b00011000000000000011000000101111; constexpr uint32_t AMOSWAP_D_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOSWAP_D_ENCODING = 0b00001000000000000011000000101111; constexpr uint32_t AMOADD_D_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOADD_D_ENCODING = 0b00000000000000000011000000101111; constexpr uint32_t AMOXOR_D_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOXOR_D_ENCODING = 0b00100000000000000011000000101111; constexpr uint32_t AMOAND_D_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOAND_D_ENCODING = 0b01100000000000000011000000101111; constexpr uint32_t AMOOR_D_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOOR_D_ENCODING = 0b01000000000000000011000000101111; constexpr uint32_t AMOMIN_D_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOMIN_D_ENCODING = 0b10000000000000000011000000101111; constexpr uint32_t AMOMAX_D_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOMAX_D_ENCODING = 0b10100000000000000011000000101111; constexpr uint32_t AMOMINU_D_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOMINU_D_ENCODING = 0b11000000000000000011000000101111; constexpr uint32_t AMOMAXU_D_MASK = 0b11111000000000000111000001111111; constexpr uint32_t AMOMAXU_D_ENCODING = 0b11100000000000000011000000101111; // RV32/64FD Extension constexpr uint32_t FLW_MASK = 0b00000000000000000111000001111111; constexpr uint32_t FLW_ENCODING = 0b00000000000000000010000000000111; constexpr uint32_t FSW_MASK = 0b00000000000000000111000001111111; constexpr uint32_t FSW_ENCODING = 0b00000000000000000010000000100111; constexpr uint32_t FMADD_S_MASK = 0b00000110000000000000000001111111; constexpr uint32_t FMADD_S_ENCODING = 0b00000000000000000000000001000011; constexpr uint32_t FMSUB_S_MASK = 0b00000110000000000000000001111111; constexpr uint32_t FMSUB_S_ENCODING = 0b00000000000000000000000001000111; constexpr uint32_t FNMADD_S_MASK = 0b00000110000000000000000001111111; constexpr uint32_t FNMADD_S_ENCODING = 0b00000000000000000000000001001111; constexpr uint32_t FNMSUB_S_MASK = 0b00000110000000000000000001111111; constexpr uint32_t FNMSUB_S_ENCODING = 0b00000000000000000000000001001011; constexpr uint32_t FADD_S_MASK = 0b11111110000000000000000001111111; constexpr uint32_t FADD_S_ENCODING = 0b00000000000000000000000001010011; constexpr uint32_t FSUB_S_MASK = 0b11111110000000000000000001111111; constexpr uint32_t FSUB_S_ENCODING = 0b00001000000000000000000001010011; constexpr uint32_t FMUL_S_MASK = 0b11111110000000000000000001111111; constexpr uint32_t FMUL_S_ENCODING = 0b00010000000000000000000001010011; constexpr uint32_t FDIV_S_MASK = 0b11111110000000000000000001111111; constexpr uint32_t FDIV_S_ENCODING = 0b00011000000000000000000001010011; constexpr uint32_t FSQRT_S_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FSQRT_S_ENCODING = 0b01011000000000000000000001010011; constexpr uint32_t FSGNJ_S_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FSGNJ_S_ENCODING = 0b00100000000000000000000001010011; constexpr uint32_t FSGNJN_S_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FSGNJN_S_ENCODING = 0b00100000000000000001000001010011; constexpr uint32_t FSGNJX_S_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FSGNJX_S_ENCODING = 0b00100000000000000010000001010011; constexpr uint32_t FMIN_S_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FMIN_S_ENCODING = 0b00101000000000000000000001010011; constexpr uint32_t FMAX_S_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FMAX_S_ENCODING = 0b00101000000000000001000001010011; constexpr uint32_t FCVT_W_S_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_W_S_ENCODING = 0b11000000000000000000000001010011; constexpr uint32_t FCVT_WU_S_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_WU_S_ENCODING = 0b11000000000100000000000001010011; constexpr uint32_t FMV_X_W_MASK = 0b11111111111100000111000001111111; constexpr uint32_t FMV_X_W_ENCODING = 0b11100000000000000000000001010011; constexpr uint32_t FEQ_S_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FEQ_S_ENCODING = 0b10100000000000000010000001010011; constexpr uint32_t FLT_S_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FLT_S_ENCODING = 0b10100000000000000001000001010011; constexpr uint32_t FLE_S_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FLE_S_ENCODING = 0b10100000000000000000000001010011; constexpr uint32_t FCLASS_S_MASK = 0b11111111111100000111000001111111; constexpr uint32_t FCLASS_S_ENCODING = 0b11100000000000000001000001010011; constexpr uint32_t FCVT_S_W_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_S_W_ENCODING = 0b11010000000000000000000001010011; constexpr uint32_t FCVT_S_WU_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_S_WU_ENCODING = 0b11010000000100000000000001010011; constexpr uint32_t FMV_W_X_MASK = 0b11111111111100000111000001111111; constexpr uint32_t FMV_W_X_ENCODING = 0b11110000000000000000000001010011; constexpr uint32_t FCVT_L_S_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_L_S_ENCODING = 0b11000000001000000000000001010011; constexpr uint32_t FCVT_LU_S_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_LU_S_ENCODING = 0b11000000001100000000000001010011; constexpr uint32_t FCVT_S_L_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_S_L_ENCODING = 0b11010000001000000000000001010011; constexpr uint32_t FCVT_S_LU_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_S_LU_ENCODING = 0b11010000001100000000000001010011; constexpr uint32_t FLD_MASK = 0b00000000000000000111000001111111; constexpr uint32_t FLD_ENCODING = 0b00000000000000000011000000000111; constexpr uint32_t FSD_MASK = 0b00000000000000000111000001111111; constexpr uint32_t FSD_ENCODING = 0b00000000000000000011000000100111; constexpr uint32_t FMADD_D_MASK = 0b00000110000000000000000001111111; constexpr uint32_t FMADD_D_ENCODING = 0b00000010000000000000000001000011; constexpr uint32_t FMSUB_D_MASK = 0b00000110000000000000000001111111; constexpr uint32_t FMSUB_D_ENCODING = 0b00000010000000000000000001000111; constexpr uint32_t FNMSUB_D_MASK = 0b00000110000000000000000001111111; constexpr uint32_t FNMSUB_D_ENCODING = 0b00000010000000000000000001001011; constexpr uint32_t FNMADD_D_MASK = 0b00000110000000000000000001111111; constexpr uint32_t FNMADD_D_ENCODING = 0b00000010000000000000000001001111; constexpr uint32_t FADD_D_MASK = 0b11111110000000000000000001111111; constexpr uint32_t FADD_D_ENCODING = 0b00000010000000000000000001010011; constexpr uint32_t FSUB_D_MASK = 0b11111110000000000000000001111111; constexpr uint32_t FSUB_D_ENCODING = 0b00001010000000000000000001010011; constexpr uint32_t FMUL_D_MASK = 0b11111110000000000000000001111111; constexpr uint32_t FMUL_D_ENCODING = 0b00010010000000000000000001010011; constexpr uint32_t FDIV_D_MASK = 0b11111110000000000000000001111111; constexpr uint32_t FDIV_D_ENCODING = 0b00011010000000000000000001010011; constexpr uint32_t FSQRT_D_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FSQRT_D_ENCODING = 0b01011010000000000000000001010011; constexpr uint32_t FSGNJ_D_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FSGNJ_D_ENCODING = 0b00100010000000000000000001010011; constexpr uint32_t FSGNJN_D_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FSGNJN_D_ENCODING = 0b00100010000000000001000001010011; constexpr uint32_t FSGNJX_D_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FSGNJX_D_ENCODING = 0b00100010000000000010000001010011; constexpr uint32_t FMIN_D_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FMIN_D_ENCODING = 0b00101010000000000000000001010011; constexpr uint32_t FMAX_D_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FMAX_D_ENCODING = 0b00101010000000000001000001010011; constexpr uint32_t FCVT_S_D_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_S_D_ENCODING = 0b01000000000100000000000001010011; constexpr uint32_t FCVT_D_S_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_D_S_ENCODING = 0b01000010000000000000000001010011; constexpr uint32_t FEQ_D_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FEQ_D_ENCODING = 0b10100010000000000010000001010011; constexpr uint32_t FLT_D_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FLT_D_ENCODING = 0b10100010000000000001000001010011; constexpr uint32_t FLE_D_MASK = 0b11111110000000000111000001111111; constexpr uint32_t FLE_D_ENCODING = 0b10100010000000000000000001010011; constexpr uint32_t FCLASS_D_MASK = 0b11111111111100000111000001111111; constexpr uint32_t FCLASS_D_ENCODING = 0b11100010000000000001000001010011; constexpr uint32_t FCVT_W_D_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_W_D_ENCODING = 0b11000010000000000000000001010011; constexpr uint32_t FCVT_WU_D_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_WU_D_ENCODING = 0b11000010000100000000000001010011; constexpr uint32_t FCVT_D_W_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_D_W_ENCODING = 0b11010010000000000000000001010011; constexpr uint32_t FCVT_D_WU_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_D_WU_ENCODING = 0b11010010000100000000000001010011; constexpr uint32_t FCVT_L_D_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_L_D_ENCODING = 0b11000010001000000000000001010011; constexpr uint32_t FCVT_LU_D_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_LU_D_ENCODING = 0b11000010001100000000000001010011; constexpr uint32_t FMV_X_D_MASK = 0b11111111111100000111000001111111; constexpr uint32_t FMV_X_D_ENCODING = 0b11100010000000000000000001010011; constexpr uint32_t FCVT_D_L_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_D_L_ENCODING = 0b11010010001000000000000001010011; constexpr uint32_t FCVT_D_LU_MASK = 0b11111111111100000000000001111111; constexpr uint32_t FCVT_D_LU_ENCODING = 0b11010010001100000000000001010011; constexpr uint32_t FMV_D_X_MASK = 0b11111111111100000111000001111111; constexpr uint32_t FMV_D_X_ENCODING = 0b11110010000000000000000001010011; #define MATCH_AND_RETURN_INSTR2(instr, result) \ if (unlikely((data() & (instr##_MASK)) != (instr##_ENCODING))) \ return UNDEF; \ return result; #define MATCH_AND_RETURN_INSTR(instr) MATCH_AND_RETURN_INSTR2(instr, instr) namespace Compressed { enum Opcode { // quadrant zero C_Illegal, C_Reserved, C_ADDI4SPN, C_FLD, C_LQ, // RV128 C_LW, C_FLW, C_LD, C_FSD, C_SQ, // RV128 C_SW, C_FSW, C_SD, // quadrant one C_NOP, C_ADDI, C_JAL, C_ADDIW, C_LI, C_ADDI16SP, C_LUI, C_SRLI, C_SRAI, C_ANDI, C_SUB, C_XOR, C_OR, C_AND, C_SUBW, C_ADDW, C_J, C_BEQZ, C_BNEZ, // quadrant two C_SLLI, C_FLDSP, C_LQSP, // RV128 C_LWSP, C_FLWSP, C_LDSP, C_JR, C_MV, C_EBREAK, C_JALR, C_ADD, C_FSDSP, C_SQSP, // RV128 C_SWSP, C_FSWSP, C_SDSP, }; } std::array Opcode::regnamePrettyStr = { "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0/fp", "s1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6" }; /* Python snippet to generate the "mappingStr": for e in [e.strip().replace(",", "") for e in s.strip().split("\n")]: if "//" in e or len(e) == 0: print(e) else: print('"{}",'.format(e)) */ std::array Opcode::mappingStr = { "ZERO-INVALID", // RV32I base instruction set "LUI", "AUIPC", "JAL", "JALR", "BEQ", "BNE", "BLT", "BGE", "BLTU", "BGEU", "LB", "LH", "LW", "LBU", "LHU", "SB", "SH", "SW", "ADDI", "SLTI", "SLTIU", "XORI", "ORI", "ANDI", "SLLI", "SRLI", "SRAI", "ADD", "SUB", "SLL", "SLT", "SLTU", "XOR", "SRL", "SRA", "OR", "AND", "FENCE", "ECALL", "EBREAK", // Zifencei standard extension "FENCE_I", // Zicsr standard extension "CSRRW", "CSRRS", "CSRRC", "CSRRWI", "CSRRSI", "CSRRCI", // RV32M Standard Extension "MUL", "MULH", "MULHSU", "MULHU", "DIV", "DIVU", "REM", "REMU", // RV32A Standard Extension "LR_W", "SC_W", "AMOSWAP_W", "AMOADD_W", "AMOXOR_W", "AMOAND_W", "AMOOR_W", "AMOMIN_W", "AMOMAX_W", "AMOMINU_W", "AMOMAXU_W", // RV64I base integer set (addition to RV32I) "LWU", "LD", "SD", "ADDIW", "SLLIW", "SRLIW", "SRAIW", "ADDW", "SUBW", "SLLW", "SRLW", "SRAW", // RV64M standard extension (addition to RV32M) "MULW", "DIVW", "DIVUW", "REMW", "REMUW", // RV64A standard extension (addition to RV32A) "LR_D", "SC_D", "AMOSWAP_D", "AMOADD_D", "AMOXOR_D", "AMOAND_D", "AMOOR_D", "AMOMIN_D", "AMOMAX_D", "AMOMINU_D", "AMOMAXU_D", // RV32F standard extension "FLW", "FSW", "FMADD_S", "FMSUB_S", "FNMADD_S", "FNMSUB_S", "FADD_S", "FSUB_S", "FMUL_S", "FDIV_S", "FSQRT_S", "FSGNJ_S", "FSGNJN_S", "FSGNJX_S", "FMIN_S", "FMAX_S", "FCVT_W_S", "FCVT_WU_S", "FMV_X_W", "FEQ_S", "FLT_S", "FLE_S", "FCLASS_S", "FCVT_S_W", "FCVT_S_WU", "FMV_W_X", // RV64F standard extension (addition to RV32F) "FCVT_L_S", "FCVT_LU_S", "FCVT_S_L", "FCVT_S_LU", // RV32D standard extension "FLD", "FSD", "FMADD_D", "FMSUB_D", "FNMSUB_D", "FNMADD_D", "FADD_D", "FSUB_D", "FMUL_D", "FDIV_D", "FSQRT_D", "FSGNJ_D", "FSGNJN_D", "FSGNJX_D", "FMIN_D", "FMAX_D", "FCVT_S_D", "FCVT_D_S", "FEQ_D", "FLT_D", "FLE_D", "FCLASS_D", "FCVT_W_D", "FCVT_WU_D", "FCVT_D_W", "FCVT_D_WU", // RV64D standard extension (addition to RV32D) "FCVT_L_D", "FCVT_LU_D", "FMV_X_D", "FCVT_D_L", "FCVT_D_LU", "FMV_D_X", // privileged instructions "URET", "SRET", "MRET", "WFI", "SFENCE_VMA", }; Opcode::Type Opcode::getType(Opcode::Mapping mapping) { switch (mapping) { case SLLI: case SRLI: case SRAI: case ADD: case SUB: case SLL: case SLT: case SLTU: case XOR: case SRL: case SRA: case OR: case AND: case MUL: case MULH: case MULHSU: case MULHU: case DIV: case DIVU: case REM: case REMU: case ADDW: case SUBW: case SLLW: case SRLW: case SRAW: case MULW: case DIVW: case DIVUW: case REMW: case REMUW: case LR_W: case SC_W: case AMOSWAP_W: case AMOADD_W: case AMOXOR_W: case AMOAND_W: case AMOOR_W: case AMOMIN_W: case AMOMAX_W: case AMOMINU_W: case AMOMAXU_W: case LR_D: case SC_D: case AMOSWAP_D: case AMOADD_D: case AMOXOR_D: case AMOAND_D: case AMOOR_D: case AMOMIN_D: case AMOMAX_D: case AMOMINU_D: case AMOMAXU_D: case FADD_S: case FSUB_S: case FMUL_S: case FDIV_S: case FSQRT_S: case FSGNJ_S: case FSGNJN_S: case FSGNJX_S: case FMIN_S: case FMAX_S: case FCVT_W_S: case FCVT_WU_S: case FMV_X_W: case FEQ_S: case FLT_S: case FLE_S: case FCLASS_S: case FCVT_S_W: case FCVT_S_WU: case FMV_W_X: case FCVT_L_S: case FCVT_LU_S: case FCVT_S_L: case FCVT_S_LU: case FADD_D: case FSUB_D: case FMUL_D: case FDIV_D: case FSQRT_D: case FSGNJ_D: case FSGNJN_D: case FSGNJX_D: case FMIN_D: case FMAX_D: case FCVT_S_D: case FCVT_D_S: case FEQ_D: case FLT_D: case FLE_D: case FCLASS_D: case FCVT_W_D: case FCVT_WU_D: case FCVT_D_W: case FCVT_D_WU: case FCVT_L_D: case FCVT_LU_D: case FMV_X_D: case FCVT_D_L: case FCVT_D_LU: case FMV_D_X: return Type::R; case JALR: case LB: case LH: case LW: case LD: case LBU: case LHU: case LWU: case ADDI: case SLTI: case SLTIU: case XORI: case ORI: case ANDI: case ADDIW: case SLLIW: case SRLIW: case SRAIW: case FLW: case FLD: return Type::I; case SB: case SH: case SW: case SD: case FSW: case FSD: return Type::S; case BEQ: case BNE: case BLT: case BGE: case BLTU: case BGEU: return Type::B; case LUI: case AUIPC: return Type::U; case JAL: return Type::J; case FMADD_S: case FMSUB_S: case FNMSUB_S: case FNMADD_S: case FMADD_D: case FMSUB_D: case FNMSUB_D: case FNMADD_D: return Type::R4; default: return Type::UNKNOWN; } } unsigned C_ADDI4SPN_NZUIMM(uint32_t n) { return (BIT_SLICE(n, 12, 11) << 4) | (BIT_SLICE(n, 10, 7) << 6) | (BIT_SINGLE_P1(n, 6) << 2) | (BIT_SINGLE_P1(n, 5) << 3); } unsigned C_LW_UIMM(uint32_t n) { return (BIT_SLICE(n, 12, 10) << 3) | (BIT_SINGLE_P1(n, 6) << 2) | (BIT_SINGLE_P1(n, 5) << 6); } unsigned C_LD_UIMM(uint32_t n) { return (BIT_SLICE(n, 12, 10) << 3) | (BIT_SLICE(n, 6, 5) << 6); } unsigned C_SW_UIMM(uint32_t n) { return C_LW_UIMM(n); } unsigned C_SD_UIMM(uint32_t n) { return C_LD_UIMM(n); } int32_t C_JAL_IMM(int32_t n) { return EXTRACT_SIGN_BIT(n, 12, 11) | BIT_SINGLE_PN(n, 11, 4) | (BIT_SLICE(n, 10, 9) << 8) | BIT_SINGLE_PN(n, 8, 10) | BIT_SINGLE_PN(n, 7, 6) | BIT_SINGLE_PN(n, 6, 7) | (BIT_SLICE(n, 5, 3) << 1) | BIT_SINGLE_PN(n, 2, 5); } int32_t C_ADDI16SP_NZIMM(int32_t n) { return EXTRACT_SIGN_BIT(n, 12, 9) | BIT_SINGLE_PN(n, 6, 4) | BIT_SINGLE_PN(n, 5, 6) | (BIT_SLICE(n, 4, 3) << 7) | BIT_SINGLE_PN(n, 2, 5); } int32_t C_LUI_NZIMM(int32_t n) { return EXTRACT_SIGN_BIT(n, 12, 17) | (BIT_SLICE(n, 6, 2) << 12); } int32_t C_J_IMM(int32_t n) { return C_JAL_IMM(n); } int32_t C_BRANCH_IMM(int32_t n) { return EXTRACT_SIGN_BIT(n, 12, 8) | (BIT_SLICE(n, 11, 10) << 3) | (BIT_SLICE(n, 6, 5) << 6) | (BIT_SLICE(n, 4, 3) << 1) | BIT_SINGLE_PN(n, 2, 5); } uint32_t C_LWSP_UIMM(uint32_t n) { return BIT_SINGLE_PN(n, 12, 5) | (BIT_SLICE(n, 6, 4) << 2) | (BIT_SLICE(n, 3, 2) << 6); } uint32_t C_SWSP_UIMM(uint32_t n) { return (BIT_SLICE(n, 12, 9) << 2) | (BIT_SLICE(n, 8, 7) << 6); } uint32_t C_LDSP_UIMM(uint32_t n) { return BIT_SINGLE_PN(n, 12, 5) | (BIT_SLICE(n, 6, 5) << 3) | (BIT_SLICE(n, 4, 2) << 6); } uint32_t C_SDSP_UIMM(uint32_t n) { return (BIT_SLICE(n, 12, 10) << 3) | (BIT_SLICE(n, 9, 7) << 6); } struct InstructionFactory { typedef Instruction T; static T ADD(unsigned rd, unsigned rs1, unsigned rs2) { return T(((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | ((rs2 & 0x1f) << 20) | 51 | (0 << 12) | (0 << 25)); } static T AND(unsigned rd, unsigned rs1, unsigned rs2) { return T(((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | ((rs2 & 0x1f) << 20) | 51 | (7 << 12) | (0 << 25)); } static T OR(unsigned rd, unsigned rs1, unsigned rs2) { return T(((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | ((rs2 & 0x1f) << 20) | 51 | (6 << 12) | (0 << 25)); } static T XOR(unsigned rd, unsigned rs1, unsigned rs2) { return T(((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | ((rs2 & 0x1f) << 20) | 51 | (4 << 12) | (0 << 25)); } static T SUB(unsigned rd, unsigned rs1, unsigned rs2) { return T(((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | ((rs2 & 0x1f) << 20) | 51 | (0 << 12) | (32 << 25)); } static T LW(unsigned rd, unsigned rs1, int I_imm) { return T(((I_imm & 4095) << 20) | ((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | 3 | (2 << 12)); } static T LD(unsigned rd, unsigned rs1, int I_imm) { return T(((I_imm & 4095) << 20) | ((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | 3 | (3 << 12)); } static T FLW(unsigned rd, unsigned rs1, int I_imm) { return T(((I_imm & 4095) << 20) | ((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | 7 | (2 << 12)); } static T FLD(unsigned rd, unsigned rs1, int I_imm) { return T(((I_imm & 4095) << 20) | ((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | 7 | (3 << 12)); } static T SW(unsigned rs1, unsigned rs2, int S_imm) { return T((((S_imm & 0b11111) << 7) | ((S_imm & (0b1111111 << 5)) << 20)) | ((rs1 & 0x1f) << 15) | ((rs2 & 0x1f) << 20) | 35 | (2 << 12)); } static T SD(unsigned rs1, unsigned rs2, int S_imm) { return T((((S_imm & 0b11111) << 7) | ((S_imm & (0b1111111 << 5)) << 20)) | ((rs1 & 0x1f) << 15) | ((rs2 & 0x1f) << 20) | 35 | (3 << 12)); } static T FSW(unsigned rs1, unsigned rs2, int S_imm) { return T((((S_imm & 0b11111) << 7) | ((S_imm & (0b1111111 << 5)) << 20)) | ((rs1 & 0x1f) << 15) | ((rs2 & 0x1f) << 20) | 39 | (2 << 12)); } static T FSD(unsigned rs1, unsigned rs2, int S_imm) { return T((((S_imm & 0b11111) << 7) | ((S_imm & (0b1111111 << 5)) << 20)) | ((rs1 & 0x1f) << 15) | ((rs2 & 0x1f) << 20) | 39 | (3 << 12)); } static T LUI(unsigned rd, int U_imm) { return T((U_imm & (1048575 << 12)) | ((rd & 0x1f) << 7) | 55); } static T ADDI(unsigned rd, unsigned rs1, int I_imm) { return T(((I_imm & 4095) << 20) | ((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | 19 | (0 << 12)); } static T ANDI(unsigned rd, unsigned rs1, int I_imm) { return T(((I_imm & 4095) << 20) | ((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | 19 | (7 << 12)); } static T SRLI(unsigned rd, unsigned rs1, unsigned shamt) { return T(((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | ((shamt & 63) << 20) | 19 | (5 << 12) | (0 << 25)); } static T SRAI(unsigned rd, unsigned rs1, unsigned shamt) { return T(((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | ((shamt & 63) << 20) | 19 | (5 << 12) | (32 << 25)); } static T SLLI(unsigned rd, unsigned rs1, unsigned shamt) { return T(((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | ((shamt & 63) << 20) | 19 | (1 << 12) | (0 << 25)); } static T JAL(unsigned rd, int J_imm) { return T(111 | ((rd & 0x1f) << 7) | ((J_imm & (0b11111111 << 12)) | ((J_imm & (1 << 11)) << 9) | ((J_imm & 0b11111111110) << 20) | ((J_imm & (1 << 20)) << 11))); } static T JALR(unsigned rd, unsigned rs1, int I_imm) { return T(((I_imm & 4095) << 20) | ((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | 103 | (0 << 12)); } static T BEQ(unsigned rs1, unsigned rs2, int B_imm) { return T(((((B_imm & 0b11110) << 7) | ((B_imm & (1 << 11)) >> 4)) | (((B_imm & (0b111111 << 5)) << 20) | ((B_imm & (1 << 12)) << 19))) | ((rs1 & 0x1f) << 15) | ((rs2 & 0x1f) << 20) | 99 | (0 << 12)); } static T BNE(unsigned rs1, unsigned rs2, int B_imm) { return T(((((B_imm & 0b11110) << 7) | ((B_imm & (1 << 11)) >> 4)) | (((B_imm & (0b111111 << 5)) << 20) | ((B_imm & (1 << 12)) << 19))) | ((rs1 & 0x1f) << 15) | ((rs2 & 0x1f) << 20) | 99 | (1 << 12)); } static T EBREAK() { return T(1048691); } static T ADDIW(unsigned rd, unsigned rs1, int I_imm) { return T(((I_imm & 4095) << 20) | ((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | 0x1b); } static T ADDW(unsigned rd, unsigned rs1, unsigned rs2) { return T(((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | ((rs2 & 0x1f) << 20) | 0x3b); } static T SUBW(unsigned rd, unsigned rs1, unsigned rs2) { return T(((rd & 0x1f) << 7) | ((rs1 & 0x1f) << 15) | ((rs2 & 0x1f) << 20) | 0x3b | 0x40000000); } }; Compressed::Opcode decode_compressed(Instruction &instr, Architecture arch) { using namespace Compressed; switch (instr.quadrant()) { case 0: switch (instr.c_opcode()) { case 0b000: if (instr.c_format() == 0) return C_Illegal; else return C_ADDI4SPN; case 0b001: return C_FLD; case 0b010: return C_LW; case 0b011: if (arch == RV32) return C_FLW; else return C_LD; case 0b100: return C_Reserved; case 0b101: return C_FSD; case 0b110: return C_SW; case 0b111: if (arch == RV32) return C_FSW; else return C_SD; } break; case 1: switch (instr.c_opcode()) { case 0b000: if (instr.c_format() == 1) return C_NOP; else return C_ADDI; case 0b001: if (arch == RV32) return C_JAL; else return C_ADDIW; case 0b010: return C_LI; case 0b011: if (instr.c_rd() == 2) return C_ADDI16SP; else return C_LUI; case 0b100: switch (instr.c_f2_high()) { case 0b00: return C_SRLI; case 0b01: return C_SRAI; case 0b10: return C_ANDI; case 0b11: if (instr.c_b12()) { switch (instr.c_f2_low()) { case 0b00: return C_SUBW; case 0b01: return C_ADDW; } return C_Reserved; } else { switch (instr.c_f2_low()) { case 0b00: return C_SUB; case 0b01: return C_XOR; case 0b10: return C_OR; case 0b11: return C_AND; } } } break; case 0b101: return C_J; case 0b110: return C_BEQZ; case 0b111: return C_BNEZ; } break; case 2: switch (instr.c_opcode()) { case 0b000: return C_SLLI; case 0b001: return C_FLDSP; case 0b010: return C_LWSP; case 0b011: if (arch == RV32) return C_FLWSP; else return C_LDSP; case 0b100: if (instr.c_b12()) { if (instr.c_rd()) { if (instr.c_rs2()) { return C_ADD; } else { return C_JALR; } } else { return C_EBREAK; } } else { if (instr.c_rs2()) { return C_MV; } else { return C_JR; } } case 0b101: return C_FSDSP; case 0b110: return C_SWSP; case 0b111: if (arch == RV32) return C_FSWSP; else return C_SDSP; } break; case 3: throw std::runtime_error("compressed instruction expected, but uncompressed found"); } // undefined/unsupported instruction return C_Illegal; } Opcode::Mapping expand_compressed(Instruction &instr, Compressed::Opcode op, Architecture arch) { using namespace Opcode; using namespace Compressed; switch (op) { case C_Illegal: return UNDEF; // RV128 currently not supported case C_LQ: case C_LQSP: case C_SQ: case C_SQSP: return UNDEF; case C_Reserved: return UNDEF; // reserved instructions should raise an illegal instruction exception case C_NOP: instr = InstructionFactory::ADD(0, 0, 0); return ADD; case C_ADD: instr = InstructionFactory::ADD(instr.c_rd(), instr.c_rd(), instr.c_rs2()); return ADD; case C_MV: instr = InstructionFactory::ADD(instr.c_rd(), 0, instr.c_rs2()); return ADD; case C_AND: instr = InstructionFactory::AND(instr.c_rd_small(), instr.c_rd_small(), instr.c_rs2_small()); return AND; case C_OR: instr = InstructionFactory::OR(instr.c_rd_small(), instr.c_rd_small(), instr.c_rs2_small()); return OR; case C_XOR: instr = InstructionFactory::XOR(instr.c_rd_small(), instr.c_rd_small(), instr.c_rs2_small()); return XOR; case C_SUB: instr = InstructionFactory::SUB(instr.c_rd_small(), instr.c_rd_small(), instr.c_rs2_small()); return SUB; case C_ADDW: instr = InstructionFactory::ADDW(instr.c_rd_small(), instr.c_rd_small(), instr.c_rs2_small()); return ADDW; case C_SUBW: instr = InstructionFactory::SUBW(instr.c_rd_small(), instr.c_rd_small(), instr.c_rs2_small()); return SUBW; case C_LW: instr = InstructionFactory::LW(instr.c_rs2_small(), instr.c_rd_small(), C_LW_UIMM(instr.data())); return LW; case C_LD: instr = InstructionFactory::LD(instr.c_rs2_small(), instr.c_rd_small(), C_LD_UIMM(instr.data())); return LD; case C_FLW: instr = InstructionFactory::FLW(instr.c_rs2_small(), instr.c_rd_small(), C_LW_UIMM(instr.data())); return FLW; case C_FLD: instr = InstructionFactory::FLD(instr.c_rs2_small(), instr.c_rd_small(), C_LD_UIMM(instr.data())); return FLD; case C_SW: instr = InstructionFactory::SW(instr.c_rd_small(), instr.c_rs2_small(), C_SW_UIMM(instr.data())); return SW; case C_SD: instr = InstructionFactory::SD(instr.c_rd_small(), instr.c_rs2_small(), C_SD_UIMM(instr.data())); return SD; case C_FSW: instr = InstructionFactory::FSW(instr.c_rd_small(), instr.c_rs2_small(), C_SW_UIMM(instr.data())); return FSW; case C_FSD: instr = InstructionFactory::FSD(instr.c_rd_small(), instr.c_rs2_small(), C_SD_UIMM(instr.data())); return FSD; case C_ADDI4SPN: { unsigned n = C_ADDI4SPN_NZUIMM(instr.data()); if (n == 0) return UNDEF; instr = InstructionFactory::ADDI(instr.c_rs2_small(), 2, n); return ADDI; } case C_ADDI: instr = InstructionFactory::ADDI(instr.c_rd(), instr.c_rd(), instr.c_imm()); return ADDI; case C_JAL: instr = InstructionFactory::JAL(1, C_JAL_IMM(instr.data())); return JAL; case C_ADDIW: if (instr.c_rd() == 0) return UNDEF; // reserved instr = InstructionFactory::ADDI(instr.c_rd(), instr.c_rd(), instr.c_imm()); return ADDIW; case C_LI: instr = InstructionFactory::ADDI(instr.c_rd(), 0, instr.c_imm()); return ADDI; case C_ADDI16SP: { auto n = C_ADDI16SP_NZIMM(instr.data()); if (n == 0) return UNDEF; // reserved instr = InstructionFactory::ADDI(2, 2, n); return ADDI; } case C_LUI: { auto n = C_LUI_NZIMM(instr.data()); if (n == 0) return UNDEF; // reserved instr = InstructionFactory::LUI(instr.c_rd(), n); return LUI; } case C_SLLI: { auto n = instr.c_uimm(); if (arch == RV32 && n > 31) return UNDEF; instr = InstructionFactory::SLLI(instr.c_rd(), instr.c_rd(), n); return SLLI; } case C_SRLI: { auto n = instr.c_uimm(); if (arch == RV32 && n > 31) return UNDEF; instr = InstructionFactory::SRLI(instr.c_rd_small(), instr.c_rd_small(), n); return SRLI; } case C_SRAI: { auto n = instr.c_uimm(); if (arch == RV32 && n > 31) return UNDEF; instr = InstructionFactory::SRAI(instr.c_rd_small(), instr.c_rd_small(), n); return SRAI; } case C_ANDI: instr = InstructionFactory::ANDI(instr.c_rd_small(), instr.c_rd_small(), instr.c_imm()); return ANDI; case C_J: instr = InstructionFactory::JAL(0, C_J_IMM(instr.data())); return JAL; case C_BEQZ: instr = InstructionFactory::BEQ(instr.c_rd_small(), 0, C_BRANCH_IMM(instr.data())); return BEQ; case C_BNEZ: instr = InstructionFactory::BNE(instr.c_rd_small(), 0, C_BRANCH_IMM(instr.data())); return BNE; case C_LWSP: if (instr.c_rd() == 0) return UNDEF; // reserved instr = InstructionFactory::LW(instr.c_rd(), 2, C_LWSP_UIMM(instr.data())); return LW; case C_LDSP: if (instr.c_rd() == 0) return UNDEF; // reserved instr = InstructionFactory::LD(instr.c_rd(), 2, C_LDSP_UIMM(instr.data())); return LD; case C_FLWSP: instr = InstructionFactory::FLW(instr.c_rd(), 2, C_LWSP_UIMM(instr.data())); return FLW; case C_FLDSP: instr = InstructionFactory::FLD(instr.c_rd(), 2, C_LDSP_UIMM(instr.data())); return FLD; case C_SWSP: instr = InstructionFactory::SW(2, instr.c_rs2(), C_SWSP_UIMM(instr.data())); return SW; case C_SDSP: instr = InstructionFactory::SD(2, instr.c_rs2(), C_SDSP_UIMM(instr.data())); return SD; case C_FSWSP: instr = InstructionFactory::FSW(2, instr.c_rs2(), C_SWSP_UIMM(instr.data())); return FSW; case C_FSDSP: instr = InstructionFactory::FSD(2, instr.c_rs2(), C_SDSP_UIMM(instr.data())); return FSD; case C_EBREAK: instr = InstructionFactory::EBREAK(); return EBREAK; case C_JR: if (instr.c_rd() == 0) return UNDEF; // reserved instr = InstructionFactory::JALR(0, instr.c_rd(), 0); return JALR; case C_JALR: instr = InstructionFactory::JALR(1, instr.c_rd(), 0); return JALR; } throw std::runtime_error("some compressed instruction not handled"); } Opcode::Mapping Instruction::decode_and_expand_compressed(Architecture arch) { auto c_op = decode_compressed(*this, arch); return expand_compressed(*this, c_op, arch); } Opcode::Mapping Instruction::decode_normal(Architecture arch) { using namespace Opcode; Instruction &instr = *this; switch (instr.opcode()) { case OP_LUI: MATCH_AND_RETURN_INSTR(LUI); case OP_AUIPC: MATCH_AND_RETURN_INSTR(AUIPC); case OP_JAL: MATCH_AND_RETURN_INSTR(JAL); case OP_JALR: { MATCH_AND_RETURN_INSTR(JALR); } case OP_BEQ: { switch (instr.funct3()) { case F3_BEQ: MATCH_AND_RETURN_INSTR(BEQ); case F3_BNE: MATCH_AND_RETURN_INSTR(BNE); case F3_BLT: MATCH_AND_RETURN_INSTR(BLT); case F3_BGE: MATCH_AND_RETURN_INSTR(BGE); case F3_BLTU: MATCH_AND_RETURN_INSTR(BLTU); case F3_BGEU: MATCH_AND_RETURN_INSTR(BGEU); } break; } case OP_LB: { switch (instr.funct3()) { case F3_LB: MATCH_AND_RETURN_INSTR(LB); case F3_LH: MATCH_AND_RETURN_INSTR(LH); case F3_LW: MATCH_AND_RETURN_INSTR(LW); case F3_LBU: MATCH_AND_RETURN_INSTR(LBU); case F3_LHU: MATCH_AND_RETURN_INSTR(LHU); case F3_LWU: MATCH_AND_RETURN_INSTR(LWU); case F3_LD: MATCH_AND_RETURN_INSTR(LD); } break; } case OP_SB: { switch (instr.funct3()) { case F3_SB: MATCH_AND_RETURN_INSTR(SB); case F3_SH: MATCH_AND_RETURN_INSTR(SH); case F3_SW: MATCH_AND_RETURN_INSTR(SW); case F3_SD: MATCH_AND_RETURN_INSTR(SD); } break; } case OP_ADDI: { switch (instr.funct3()) { case F3_ADDI: MATCH_AND_RETURN_INSTR(ADDI); case F3_SLTI: MATCH_AND_RETURN_INSTR(SLTI); case F3_SLTIU: MATCH_AND_RETURN_INSTR(SLTIU); case F3_XORI: MATCH_AND_RETURN_INSTR(XORI); case F3_ORI: MATCH_AND_RETURN_INSTR(ORI); case F3_ANDI: MATCH_AND_RETURN_INSTR(ANDI); case F3_SLLI: if (arch == RV32) { MATCH_AND_RETURN_INSTR2(SLLI_32, SLLI); } else { MATCH_AND_RETURN_INSTR(SLLI); } case F3_SRLI: { switch (instr.funct6()) { case F6_SRLI: if (arch == RV32) { MATCH_AND_RETURN_INSTR2(SRLI_32, SRLI); } else { MATCH_AND_RETURN_INSTR(SRLI); } case F6_SRAI: if (arch == RV32) { MATCH_AND_RETURN_INSTR2(SRAI_32, SRAI); } else { MATCH_AND_RETURN_INSTR(SRAI); } } } } break; } case OP_ADDIW: { switch (instr.funct3()) { case F3_ADDIW: MATCH_AND_RETURN_INSTR(ADDIW); case F3_SLLIW: MATCH_AND_RETURN_INSTR(SLLIW); case F3_SRLIW: { switch (instr.funct7()) { case F7_SRLIW: MATCH_AND_RETURN_INSTR(SRLIW); case F7_SRAIW: MATCH_AND_RETURN_INSTR(SRAIW); } } } break; } case OP_ADD: { switch (instr.funct7()) { case F7_ADD: switch (instr.funct3()) { case F3_ADD: MATCH_AND_RETURN_INSTR(ADD); case F3_SLL: MATCH_AND_RETURN_INSTR(SLL); case F3_SLT: MATCH_AND_RETURN_INSTR(SLT); case F3_SLTU: MATCH_AND_RETURN_INSTR(SLTU); case F3_XOR: MATCH_AND_RETURN_INSTR(XOR); case F3_SRL: MATCH_AND_RETURN_INSTR(SRL); case F3_OR: MATCH_AND_RETURN_INSTR(OR); case F3_AND: MATCH_AND_RETURN_INSTR(AND); } break; case F7_SUB: switch (instr.funct3()) { case F3_SUB: MATCH_AND_RETURN_INSTR(SUB); case F3_SRA: MATCH_AND_RETURN_INSTR(SRA); } break; case F7_MUL: switch (instr.funct3()) { case F3_MUL: MATCH_AND_RETURN_INSTR(MUL); case F3_MULH: MATCH_AND_RETURN_INSTR(MULH); case F3_MULHSU: MATCH_AND_RETURN_INSTR(MULHSU); case F3_MULHU: MATCH_AND_RETURN_INSTR(MULHU); case F3_DIV: MATCH_AND_RETURN_INSTR(DIV); case F3_DIVU: MATCH_AND_RETURN_INSTR(DIVU); case F3_REM: MATCH_AND_RETURN_INSTR(REM); case F3_REMU: MATCH_AND_RETURN_INSTR(REMU); } break; } break; } case OP_ADDW: { switch (instr.funct7()) { case F7_ADDW: switch (instr.funct3()) { case F3_ADDW: MATCH_AND_RETURN_INSTR(ADDW); case F3_SLLW: MATCH_AND_RETURN_INSTR(SLLW); case F3_SRLW: MATCH_AND_RETURN_INSTR(SRLW); } break; case F7_SUBW: switch (instr.funct3()) { case F3_SUBW: MATCH_AND_RETURN_INSTR(SUBW); case F3_SRAW: MATCH_AND_RETURN_INSTR(SRAW); } break; case F7_MULW: switch (instr.funct3()) { case F3_MULW: MATCH_AND_RETURN_INSTR(MULW); case F3_DIVW: MATCH_AND_RETURN_INSTR(DIVW); case F3_DIVUW: MATCH_AND_RETURN_INSTR(DIVUW); case F3_REMW: MATCH_AND_RETURN_INSTR(REMW); case F3_REMUW: MATCH_AND_RETURN_INSTR(REMUW); } break; } break; } case OP_FENCE: { switch (instr.funct3()) { case F3_FENCE: MATCH_AND_RETURN_INSTR(FENCE); case F3_FENCE_I: MATCH_AND_RETURN_INSTR(FENCE_I); } break; } case OP_ECALL: { switch (instr.funct3()) { case F3_SYS: { switch (instr.funct12()) { case F12_ECALL: MATCH_AND_RETURN_INSTR(ECALL); case F12_EBREAK: MATCH_AND_RETURN_INSTR(EBREAK); case F12_URET: MATCH_AND_RETURN_INSTR(URET); case F12_SRET: MATCH_AND_RETURN_INSTR(SRET); case F12_MRET: MATCH_AND_RETURN_INSTR(MRET); case F12_WFI: MATCH_AND_RETURN_INSTR(WFI); default: MATCH_AND_RETURN_INSTR(SFENCE_VMA); } break; } case F3_CSRRW: MATCH_AND_RETURN_INSTR(CSRRW); case F3_CSRRS: MATCH_AND_RETURN_INSTR(CSRRS); case F3_CSRRC: MATCH_AND_RETURN_INSTR(CSRRC); case F3_CSRRWI: MATCH_AND_RETURN_INSTR(CSRRWI); case F3_CSRRSI: MATCH_AND_RETURN_INSTR(CSRRSI); case F3_CSRRCI: MATCH_AND_RETURN_INSTR(CSRRCI); } break; } case OP_AMO: { switch (instr.funct5()) { case F5_LR_W: if (instr.funct3() == F3_AMO_D) { MATCH_AND_RETURN_INSTR(LR_D); } else { MATCH_AND_RETURN_INSTR(LR_W); } case F5_SC_W: if (instr.funct3() == F3_AMO_D) { MATCH_AND_RETURN_INSTR(SC_D); } else { MATCH_AND_RETURN_INSTR(SC_W); } case F5_AMOSWAP_W: if (instr.funct3() == F3_AMO_D) { MATCH_AND_RETURN_INSTR(AMOSWAP_D); } else { MATCH_AND_RETURN_INSTR(AMOSWAP_W); } case F5_AMOADD_W: if (instr.funct3() == F3_AMO_D) { MATCH_AND_RETURN_INSTR(AMOADD_D); } else { MATCH_AND_RETURN_INSTR(AMOADD_W); } case F5_AMOXOR_W: if (instr.funct3() == F3_AMO_D) { MATCH_AND_RETURN_INSTR(AMOXOR_D); } else { MATCH_AND_RETURN_INSTR(AMOXOR_W); } case F5_AMOAND_W: if (instr.funct3() == F3_AMO_D) { MATCH_AND_RETURN_INSTR(AMOAND_D); } else { MATCH_AND_RETURN_INSTR(AMOAND_W); } case F5_AMOOR_W: if (instr.funct3() == F3_AMO_D) { MATCH_AND_RETURN_INSTR(AMOOR_D); } else { MATCH_AND_RETURN_INSTR(AMOOR_W); } case F5_AMOMIN_W: if (instr.funct3() == F3_AMO_D) { MATCH_AND_RETURN_INSTR(AMOMIN_D); } else { MATCH_AND_RETURN_INSTR(AMOMIN_W); } case F5_AMOMAX_W: if (instr.funct3() == F3_AMO_D) { MATCH_AND_RETURN_INSTR(AMOMAX_D); } else { MATCH_AND_RETURN_INSTR(AMOMAX_W); } case F5_AMOMINU_W: if (instr.funct3() == F3_AMO_D) { MATCH_AND_RETURN_INSTR(AMOMINU_D); } else { MATCH_AND_RETURN_INSTR(AMOMINU_W); } case F5_AMOMAXU_W: if (instr.funct3() == F3_AMO_D) { MATCH_AND_RETURN_INSTR(AMOMAXU_D); } else { MATCH_AND_RETURN_INSTR(AMOMAXU_W); } } break; } // RV32/64 FD Extension case OP_FMADD_S: switch (instr.funct2()) { case F2_FMADD_S: MATCH_AND_RETURN_INSTR(FMADD_S); case F2_FMADD_D: MATCH_AND_RETURN_INSTR(FMADD_D); } break; case OP_FADD_S: switch (instr.funct7()) { case F7_FADD_S: MATCH_AND_RETURN_INSTR(FADD_S); case F7_FADD_D: MATCH_AND_RETURN_INSTR(FADD_D); case F7_FSUB_S: MATCH_AND_RETURN_INSTR(FSUB_S); case F7_FSUB_D: MATCH_AND_RETURN_INSTR(FSUB_D); case F7_FCVT_D_S: MATCH_AND_RETURN_INSTR(FCVT_D_S); case F7_FMUL_S: MATCH_AND_RETURN_INSTR(FMUL_S); case F7_FMUL_D: MATCH_AND_RETURN_INSTR(FMUL_D); case F7_FDIV_S: MATCH_AND_RETURN_INSTR(FDIV_S); case F7_FDIV_D: MATCH_AND_RETURN_INSTR(FDIV_D); case F7_FLE_S: switch (instr.funct3()) { case F3_FLE_S: MATCH_AND_RETURN_INSTR(FLE_S); case F3_FLT_S: MATCH_AND_RETURN_INSTR(FLT_S); case F3_FEQ_S: MATCH_AND_RETURN_INSTR(FEQ_S); } break; case F7_FSGNJ_D: switch (instr.funct3()) { case F3_FSGNJ_D: MATCH_AND_RETURN_INSTR(FSGNJ_D); case F3_FSGNJN_D: MATCH_AND_RETURN_INSTR(FSGNJN_D); case F3_FSGNJX_D: MATCH_AND_RETURN_INSTR(FSGNJX_D); } break; case F7_FMIN_S: switch (instr.funct3()) { case F3_FMIN_S: MATCH_AND_RETURN_INSTR(FMIN_S); case F3_FMAX_S: MATCH_AND_RETURN_INSTR(FMAX_S); } break; case F7_FMIN_D: switch (instr.funct3()) { case F3_FMIN_D: MATCH_AND_RETURN_INSTR(FMIN_D); case F3_FMAX_D: MATCH_AND_RETURN_INSTR(FMAX_D); } break; case F7_FCVT_S_D: MATCH_AND_RETURN_INSTR(FCVT_S_D); case F7_FSGNJ_S: switch (instr.funct3()) { case F3_FSGNJ_S: MATCH_AND_RETURN_INSTR(FSGNJ_S); case F3_FSGNJN_S: MATCH_AND_RETURN_INSTR(FSGNJN_S); case F3_FSGNJX_S: MATCH_AND_RETURN_INSTR(FSGNJX_S); } break; case F7_FLE_D: switch (instr.funct3()) { case F3_FLE_D: MATCH_AND_RETURN_INSTR(FLE_D); case F3_FLT_D: MATCH_AND_RETURN_INSTR(FLT_D); case F3_FEQ_D: MATCH_AND_RETURN_INSTR(FEQ_D); } break; case F7_FCVT_S_W: switch (instr.rs2()) { case RS2_FCVT_S_W: MATCH_AND_RETURN_INSTR(FCVT_S_W); case RS2_FCVT_S_WU: MATCH_AND_RETURN_INSTR(FCVT_S_WU); case RS2_FCVT_S_L: MATCH_AND_RETURN_INSTR(FCVT_S_L); case RS2_FCVT_S_LU: MATCH_AND_RETURN_INSTR(FCVT_S_LU); } break; case F7_FCVT_D_W: switch (instr.rs2()) { case RS2_FCVT_D_W: MATCH_AND_RETURN_INSTR(FCVT_D_W); case RS2_FCVT_D_WU: MATCH_AND_RETURN_INSTR(FCVT_D_WU); case RS2_FCVT_D_L: MATCH_AND_RETURN_INSTR(FCVT_D_L); case RS2_FCVT_D_LU: MATCH_AND_RETURN_INSTR(FCVT_D_LU); } break; case F7_FCVT_W_D: switch (instr.rs2()) { case RS2_FCVT_W_D: MATCH_AND_RETURN_INSTR(FCVT_W_D); case RS2_FCVT_WU_D: MATCH_AND_RETURN_INSTR(FCVT_WU_D); case RS2_FCVT_L_D: MATCH_AND_RETURN_INSTR(FCVT_L_D); case RS2_FCVT_LU_D: MATCH_AND_RETURN_INSTR(FCVT_LU_D); } break; case F7_FSQRT_S: MATCH_AND_RETURN_INSTR(FSQRT_S); case F7_FSQRT_D: MATCH_AND_RETURN_INSTR(FSQRT_D); case F7_FCVT_W_S: switch (instr.rs2()) { case RS2_FCVT_W_S: MATCH_AND_RETURN_INSTR(FCVT_W_S); case RS2_FCVT_WU_S: MATCH_AND_RETURN_INSTR(FCVT_WU_S); case RS2_FCVT_L_S: MATCH_AND_RETURN_INSTR(FCVT_L_S); case RS2_FCVT_LU_S: MATCH_AND_RETURN_INSTR(FCVT_LU_S); } break; case F7_FMV_X_W: switch (instr.funct3()) { case F3_FMV_X_W: MATCH_AND_RETURN_INSTR(FMV_X_W); case F3_FCLASS_S: MATCH_AND_RETURN_INSTR(FCLASS_S); } break; case F7_FMV_X_D: switch (instr.funct3()) { case F3_FMV_X_D: MATCH_AND_RETURN_INSTR(FMV_X_D); case F3_FCLASS_D: MATCH_AND_RETURN_INSTR(FCLASS_D); } break; case F7_FMV_W_X: MATCH_AND_RETURN_INSTR(FMV_W_X); case F7_FMV_D_X: MATCH_AND_RETURN_INSTR(FMV_D_X); } break; case OP_FLW: switch (instr.funct3()) { case F3_FLW: MATCH_AND_RETURN_INSTR(FLW); case F3_FLD: MATCH_AND_RETURN_INSTR(FLD); } break; case OP_FSW: switch (instr.funct3()) { case F3_FSW: MATCH_AND_RETURN_INSTR(FSW); case F3_FSD: MATCH_AND_RETURN_INSTR(FSD); } break; case OP_FMSUB_S: switch (instr.funct2()) { case F2_FMSUB_S: MATCH_AND_RETURN_INSTR(FMSUB_S); case F2_FMSUB_D: MATCH_AND_RETURN_INSTR(FMSUB_D); } break; case OP_FNMSUB_S: switch (instr.funct2()) { case F2_FNMSUB_S: MATCH_AND_RETURN_INSTR(FNMSUB_S); case F2_FNMSUB_D: MATCH_AND_RETURN_INSTR(FNMSUB_D); } break; case OP_FNMADD_S: switch (instr.funct2()) { case F2_FNMADD_S: MATCH_AND_RETURN_INSTR(FNMADD_S); case F2_FNMADD_D: MATCH_AND_RETURN_INSTR(FNMADD_D); } break; } return UNDEF; } ================================================ FILE: vp/src/core/common/instr.h ================================================ #ifndef RISCV_ISA_INSTR_H #define RISCV_ISA_INSTR_H #include #include #include #include "core_defs.h" namespace Opcode { // opcode masks used to decode an instruction enum Parts { OP_LUI = 0b0110111, OP_AUIPC = 0b0010111, OP_JAL = 0b1101111, OP_JALR = 0b1100111, F3_JALR = 0b000, OP_LB = 0b0000011, F3_LB = 0b000, F3_LH = 0b001, F3_LW = 0b010, F3_LBU = 0b100, F3_LHU = 0b101, F3_LWU = 0b110, F3_LD = 0b011, OP_SB = 0b0100011, F3_SB = 0b000, F3_SH = 0b001, F3_SW = 0b010, F3_SD = 0b011, OP_BEQ = 0b1100011, F3_BEQ = 0b000, F3_BNE = 0b001, F3_BLT = 0b100, F3_BGE = 0b101, F3_BLTU = 0b110, F3_BGEU = 0b111, OP_ADDI = 0b0010011, F3_ADDI = 0b000, F3_SLTI = 0b010, F3_SLTIU = 0b011, F3_XORI = 0b100, F3_ORI = 0b110, F3_ANDI = 0b111, F3_SLLI = 0b001, F3_SRLI = 0b101, F7_SRLI = 0b0000000, F7_SRAI = 0b0100000, F6_SRLI = 0b000000, // RV64 special case F6_SRAI = 0b010000, // RV64 special case OP_ADD = 0b0110011, F3_ADD = 0b000, F7_ADD = 0b0000000, F3_SUB = 0b000, F7_SUB = 0b0100000, F3_SLL = 0b001, F3_SLT = 0b010, F3_SLTU = 0b011, F3_XOR = 0b100, F3_SRL = 0b101, F3_SRA = 0b101, F3_OR = 0b110, F3_AND = 0b111, F3_MUL = 0b000, F7_MUL = 0b0000001, F3_MULH = 0b001, F3_MULHSU = 0b010, F3_MULHU = 0b011, F3_DIV = 0b100, F3_DIVU = 0b101, F3_REM = 0b110, F3_REMU = 0b111, OP_FENCE = 0b0001111, F3_FENCE = 0b000, F3_FENCE_I = 0b001, OP_ECALL = 0b1110011, F3_SYS = 0b000, F12_ECALL = 0b000000000000, F12_EBREAK = 0b000000000001, // begin:privileged-instructions F12_URET = 0b000000000010, F12_SRET = 0b000100000010, F12_MRET = 0b001100000010, F12_WFI = 0b000100000101, F7_SFENCE_VMA = 0b0001001, // end:privileged-instructions F3_CSRRW = 0b001, F3_CSRRS = 0b010, F3_CSRRC = 0b011, F3_CSRRWI = 0b101, F3_CSRRSI = 0b110, F3_CSRRCI = 0b111, OP_AMO = 0b0101111, F5_LR_W = 0b00010, F5_SC_W = 0b00011, F5_AMOSWAP_W = 0b00001, F5_AMOADD_W = 0b00000, F5_AMOXOR_W = 0b00100, F5_AMOAND_W = 0b01100, F5_AMOOR_W = 0b01000, F5_AMOMIN_W = 0b10000, F5_AMOMAX_W = 0b10100, F5_AMOMINU_W = 0b11000, F5_AMOMAXU_W = 0b11100, F3_AMO_W = 0b010, F3_AMO_D = 0b011, OP_ADDIW = 0b0011011, F3_ADDIW = 0b000, F3_SLLIW = 0b001, F3_SRLIW = 0b101, F7_SRLIW = 0b0000000, F7_SRAIW = 0b0100000, OP_ADDW = 0b0111011, F3_ADDW = 0b000, F7_ADDW = 0b0000000, F3_SUBW = 0b000, F7_SUBW = 0b0100000, F3_SLLW = 0b001, F3_SRLW = 0b101, F7_SRLW = 0b0000000, F3_SRAW = 0b101, F7_SRAW = 0b0100000, F7_MULW = 0b0000001, F3_MULW = 0b000, F3_DIVW = 0b100, F3_DIVUW = 0b101, F3_REMW = 0b110, F3_REMUW = 0b111, // F and D extension OP_FMADD_S = 0b1000011, F2_FMADD_S = 0b00, F2_FMADD_D = 0b01, OP_FADD_S = 0b1010011, F7_FADD_S = 0b0000000, F7_FADD_D = 0b0000001, F7_FSUB_S = 0b0000100, F7_FSUB_D = 0b0000101, F7_FCVT_D_S = 0b0100001, F7_FMUL_S = 0b0001000, F7_FMUL_D = 0b0001001, F7_FDIV_S = 0b0001100, F7_FDIV_D = 0b0001101, F7_FLE_S = 0b1010000, F3_FLE_S = 0b000, F3_FLT_S = 0b001, F3_FEQ_S = 0b010, F7_FSGNJ_D = 0b0010001, F3_FSGNJ_D = 0b000, F3_FSGNJN_D = 0b001, F3_FSGNJX_D = 0b010, F7_FMIN_S = 0b0010100, F3_FMIN_S = 0b000, F3_FMAX_S = 0b001, F7_FMIN_D = 0b0010101, F3_FMIN_D = 0b000, F3_FMAX_D = 0b001, F7_FCVT_S_D = 0b0100000, F7_FSGNJ_S = 0b0010000, F3_FSGNJ_S = 0b000, F3_FSGNJN_S = 0b001, F3_FSGNJX_S = 0b010, F7_FLE_D = 0b1010001, F3_FLE_D = 0b000, F3_FLT_D = 0b001, F3_FEQ_D = 0b010, F7_FCVT_S_W = 0b1101000, RS2_FCVT_S_W = 0b00000, RS2_FCVT_S_WU = 0b00001, RS2_FCVT_S_L = 0b00010, RS2_FCVT_S_LU = 0b00011, F7_FCVT_D_W = 0b1101001, RS2_FCVT_D_W = 0b00000, RS2_FCVT_D_WU = 0b00001, RS2_FCVT_D_L = 0b00010, RS2_FCVT_D_LU = 0b00011, F7_FCVT_W_D = 0b1100001, RS2_FCVT_W_D = 0b00000, RS2_FCVT_WU_D = 0b00001, RS2_FCVT_L_D = 0b00010, RS2_FCVT_LU_D = 0b00011, F7_FSQRT_S = 0b0101100, F7_FSQRT_D = 0b0101101, F7_FCVT_W_S = 0b1100000, RS2_FCVT_W_S = 0b00000, RS2_FCVT_WU_S = 0b00001, RS2_FCVT_L_S = 0b00010, RS2_FCVT_LU_S = 0b00011, F7_FMV_X_W = 0b1110000, F3_FMV_X_W = 0b000, F3_FCLASS_S = 0b001, F7_FMV_X_D = 0b1110001, F3_FMV_X_D = 0b000, F3_FCLASS_D = 0b001, F7_FMV_W_X = 0b1111000, F7_FMV_D_X = 0b1111001, OP_FLW = 0b0000111, F3_FLW = 0b010, F3_FLD = 0b011, OP_FSW = 0b0100111, F3_FSW = 0b010, F3_FSD = 0b011, OP_FMSUB_S = 0b1000111, F2_FMSUB_S = 0b00, F2_FMSUB_D = 0b01, OP_FNMSUB_S = 0b1001011, F2_FNMSUB_S = 0b00, F2_FNMSUB_D = 0b01, OP_FNMADD_S = 0b1001111, F2_FNMADD_S = 0b00, F2_FNMADD_D = 0b01, // reserved opcodes for custom instructions OP_CUST1 = 0b0101011, OP_CUST0 = 0b0001011, }; // each instruction is mapped by the decoder to the following mapping enum Mapping { UNDEF = 0, // RV32I base instruction set LUI = 1, AUIPC, JAL, JALR, BEQ, BNE, BLT, BGE, BLTU, BGEU, LB, LH, LW, LBU, LHU, SB, SH, SW, ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI, ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND, FENCE, ECALL, EBREAK, // Zifencei standard extension FENCE_I, // Zicsr standard extension CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI, // RV32M standard extension MUL, MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU, // RV32A standard extension LR_W, SC_W, AMOSWAP_W, AMOADD_W, AMOXOR_W, AMOAND_W, AMOOR_W, AMOMIN_W, AMOMAX_W, AMOMINU_W, AMOMAXU_W, // RV64I base integer set (addition to RV32I) LWU, LD, SD, ADDIW, SLLIW, SRLIW, SRAIW, ADDW, SUBW, SLLW, SRLW, SRAW, // RV64M standard extension (addition to RV32M) MULW, DIVW, DIVUW, REMW, REMUW, // RV64A standard extension (addition to RV32A) LR_D, SC_D, AMOSWAP_D, AMOADD_D, AMOXOR_D, AMOAND_D, AMOOR_D, AMOMIN_D, AMOMAX_D, AMOMINU_D, AMOMAXU_D, // RV32F standard extension FLW, FSW, FMADD_S, FMSUB_S, FNMADD_S, FNMSUB_S, FADD_S, FSUB_S, FMUL_S, FDIV_S, FSQRT_S, FSGNJ_S, FSGNJN_S, FSGNJX_S, FMIN_S, FMAX_S, FCVT_W_S, FCVT_WU_S, FMV_X_W, FEQ_S, FLT_S, FLE_S, FCLASS_S, FCVT_S_W, FCVT_S_WU, FMV_W_X, // RV64F standard extension (addition to RV32F) FCVT_L_S, FCVT_LU_S, FCVT_S_L, FCVT_S_LU, // RV32D standard extension FLD, FSD, FMADD_D, FMSUB_D, FNMSUB_D, FNMADD_D, FADD_D, FSUB_D, FMUL_D, FDIV_D, FSQRT_D, FSGNJ_D, FSGNJN_D, FSGNJX_D, FMIN_D, FMAX_D, FCVT_S_D, FCVT_D_S, FEQ_D, FLT_D, FLE_D, FCLASS_D, FCVT_W_D, FCVT_WU_D, FCVT_D_W, FCVT_D_WU, // RV64D standard extension (addition to RV32D) FCVT_L_D, FCVT_LU_D, FMV_X_D, FCVT_D_L, FCVT_D_LU, FMV_D_X, // privileged instructions URET, SRET, MRET, WFI, SFENCE_VMA, NUMBER_OF_INSTRUCTIONS }; // type denotes the instruction format enum class Type { UNKNOWN = 0, R, I, S, B, U, J, R4, }; extern std::array mappingStr; extern std::array regnamePrettyStr; Type getType(Mapping mapping); } // namespace Opcode #define BIT_RANGE(instr, upper, lower) (instr & (((1 << (upper - lower + 1)) - 1) << lower)) #define BIT_SLICE(instr, upper, lower) (BIT_RANGE(instr, upper, lower) >> lower) #define BIT_SINGLE(instr, pos) (instr & (1 << pos)) #define BIT_SINGLE_P1(instr, pos) (BIT_SINGLE(instr, pos) >> pos) #define BIT_SINGLE_PN(instr, pos, new_pos) ((BIT_SINGLE(instr, pos) >> pos) << new_pos) #define EXTRACT_SIGN_BIT(instr, pos, new_pos) ((BIT_SINGLE_P1(instr, pos) << 31) >> (31 - new_pos)) struct Instruction { Instruction() : instr(0) {} Instruction(uint32_t instr) : instr(instr) {} inline uint32_t quadrant() { return instr & 0x3; } inline bool is_compressed() { return quadrant() < 3; } inline uint32_t c_format() { return instr & 0xffff; } inline uint32_t c_opcode() { return BIT_SLICE(instr, 15, 13); } inline uint32_t c_b12() { return BIT_SINGLE_P1(instr, 12); } inline uint32_t c_rd() { return rd(); } inline uint32_t c_rd_small() { return BIT_SLICE(instr, 9, 7) | 8; } inline uint32_t c_rs2_small() { return BIT_SLICE(instr, 4, 2) | 8; } inline uint32_t c_rs2() { return BIT_SLICE(instr, 6, 2); } inline uint32_t c_imm() { return BIT_SLICE(instr, 6, 2) | EXTRACT_SIGN_BIT(instr, 12, 5); } inline uint32_t c_uimm() { return BIT_SLICE(instr, 6, 2) | (BIT_SINGLE_P1(instr, 12) << 5); } inline uint32_t c_f2_high() { return BIT_SLICE(instr, 11, 10); } inline uint32_t c_f2_low() { return BIT_SLICE(instr, 6, 5); } Opcode::Mapping decode_normal(Architecture arch); Opcode::Mapping decode_and_expand_compressed(Architecture arch); inline uint32_t csr() { // cast to unsigned to avoid sign extension when shifting return BIT_RANGE((uint32_t)instr, 31, 20) >> 20; } inline uint32_t zimm() { return BIT_RANGE(instr, 19, 15) >> 15; } inline unsigned shamt() { return (BIT_RANGE(instr, 25, 20) >> 20); } inline unsigned shamt_w() { return (BIT_RANGE(instr, 24, 20) >> 20); } inline int32_t funct2() { return (BIT_RANGE(instr, 26, 25) >> 25); } inline int32_t funct3() { return (BIT_RANGE(instr, 14, 12) >> 12); } inline int32_t funct12() { // cast to unsigned to avoid sign extension when shifting return (BIT_RANGE((uint32_t)instr, 31, 20) >> 20); } inline int32_t funct7() { // cast to unsigned to avoid sign extension when shifting return (BIT_RANGE((uint32_t)instr, 31, 25) >> 25); } inline int32_t funct6() { // cast to unsigned to avoid sign extension when shifting return (BIT_RANGE((uint32_t)instr, 31, 26) >> 26); } inline int32_t funct5() { // cast to unsigned to avoid sign extension when shifting return (BIT_RANGE((uint32_t)instr, 31, 27) >> 27); } inline uint32_t frm() { return BIT_SLICE(instr, 14, 12); } inline uint32_t fence_succ() { return BIT_SLICE(instr, 23, 20); } inline uint32_t fence_pred() { return BIT_SLICE(instr, 27, 24); } inline uint32_t fence_fm() { return BIT_SLICE(instr, 31, 28); } inline bool aq() { return BIT_SINGLE(instr, 26); } inline bool rl() { return BIT_SINGLE(instr, 25); } inline int32_t opcode() { return BIT_RANGE(instr, 6, 0); } inline int32_t J_imm() { return (BIT_SINGLE(instr, 31) >> 11) | BIT_RANGE(instr, 19, 12) | (BIT_SINGLE(instr, 20) >> 9) | (BIT_RANGE(instr, 30, 21) >> 20); } inline int32_t I_imm() { return BIT_RANGE(instr, 31, 20) >> 20; } inline int32_t S_imm() { return (BIT_RANGE(instr, 31, 25) >> 20) | (BIT_RANGE(instr, 11, 7) >> 7); } inline int32_t B_imm() { return (BIT_SINGLE(instr, 31) >> 19) | (BIT_SINGLE(instr, 7) << 4) | (BIT_RANGE(instr, 30, 25) >> 20) | (BIT_RANGE(instr, 11, 8) >> 7); } inline int32_t U_imm() { return BIT_RANGE(instr, 31, 12); } inline uint32_t rs1() { return BIT_RANGE(instr, 19, 15) >> 15; } inline uint32_t rs2() { return BIT_RANGE(instr, 24, 20) >> 20; } inline uint32_t rs3() { return BIT_RANGE((uint32_t)instr, 31, 27) >> 27; } inline uint32_t rd() { return BIT_RANGE(instr, 11, 7) >> 7; } inline uint32_t data() { return instr; } private: // use signed variable to have correct sign extension in immediates int32_t instr; }; #endif // RISCV_ISA_INSTR_H ================================================ FILE: vp/src/core/common/irq_if.h ================================================ #ifndef RISCV_ISA_IRQ_IF_H #define RISCV_ISA_IRQ_IF_H #include typedef uint32_t PrivilegeLevel; constexpr uint32_t MachineMode = 0b11; constexpr uint32_t HypervisorMode = 0b10; constexpr uint32_t SupervisorMode = 0b01; constexpr uint32_t UserMode = 0b00; constexpr uint32_t NoneMode = -1; // invalid sentinel to avoid passing a boolean alongside a privilege level struct external_interrupt_target { virtual ~external_interrupt_target() {} virtual void trigger_external_interrupt(PrivilegeLevel level) = 0; virtual void clear_external_interrupt(PrivilegeLevel level) = 0; }; struct clint_interrupt_target { virtual ~clint_interrupt_target() {} virtual void trigger_timer_interrupt(bool status) = 0; virtual void trigger_software_interrupt(bool status) = 0; }; struct interrupt_gateway { virtual ~interrupt_gateway() {} virtual void gateway_trigger_interrupt(uint32_t irq_id) = 0; }; #endif // RISCV_ISA_IRQ_IF_H ================================================ FILE: vp/src/core/common/load_if.h ================================================ #ifndef RISCV_VP_LOAD_IF_H #define RISCV_VP_LOAD_IF_H #include #include class load_if { public: virtual void load_data(const char *src, uint64_t dst_addr, size_t n) = 0; virtual void load_zero(uint64_t dst_addr, size_t n) = 0; }; #endif ================================================ FILE: vp/src/core/common/mmu.h ================================================ #pragma once #include "mmu_mem_if.h" constexpr unsigned PTE_PPN_SHIFT = 10; constexpr unsigned PGSHIFT = 12; constexpr unsigned PGSIZE = 1 << PGSHIFT; constexpr unsigned PGMASK = PGSIZE - 1; constexpr unsigned PTE_V = 1; constexpr unsigned PTE_R = 1 << 1; constexpr unsigned PTE_W = 1 << 2; constexpr unsigned PTE_X = 1 << 3; constexpr unsigned PTE_U = 1 << 4; constexpr unsigned PTE_G = 1 << 5; constexpr unsigned PTE_A = 1 << 6; constexpr unsigned PTE_D = 1 << 7; constexpr unsigned PTE_RSW = 0b11 << 8; struct pte_t { uint64_t value; bool V() { return value & PTE_V; } bool R() { return value & PTE_R; } bool W() { return value & PTE_W; } bool X() { return value & PTE_X; } bool U() { return value & PTE_U; } bool G() { return value & PTE_G; } bool A() { return value & PTE_A; } bool D() { return value & PTE_D; } operator uint64_t() { return value; } }; struct vm_info { int levels; int idxbits; int ptesize; uint64_t ptbase; }; template struct GenericMMU { RVX_ISS &core; tlm_utils::tlm_quantumkeeper &quantum_keeper; sc_core::sc_time clock_cycle = sc_core::sc_time(10, sc_core::SC_NS); sc_core::sc_time mmu_access_delay = clock_cycle * 3; mmu_memory_if *mem = nullptr; bool page_fault_on_AD = false; struct tlb_entry_t { uint64_t ppn = -1; uint64_t vpn = -1; }; static constexpr unsigned TLB_ENTRIES = 256; static constexpr unsigned NUM_MODES = 2; // User and Supervisor static constexpr unsigned NUM_ACCESS_TYPES = 3; // FETCH, LOAD, STORE tlb_entry_t tlb[NUM_MODES][NUM_ACCESS_TYPES][TLB_ENTRIES]; GenericMMU(RVX_ISS &core) : core(core), quantum_keeper(core.quantum_keeper) { flush_tlb(); } void flush_tlb() { memset(&tlb[0], -1, NUM_MODES * NUM_ACCESS_TYPES * TLB_ENTRIES * sizeof(tlb_entry_t)); } uint64_t translate_virtual_to_physical_addr(uint64_t vaddr, MemoryAccessType type) { if (core.csrs.satp.fields.mode == SATP_MODE_BARE) return vaddr; auto mode = core.prv; if (type != FETCH) { if (core.csrs.mstatus.fields.mprv) mode = core.csrs.mstatus.fields.mpp; } if (mode == MachineMode) return vaddr; // optional timing quantum_keeper.inc(mmu_access_delay); // optimization only, to void page walk assert(mode == 0 || mode == 1); assert(type == 0 || type == 1 || type == 2); auto vpn = (vaddr >> PGSHIFT); auto idx = vpn % TLB_ENTRIES; auto &x = tlb[mode][type][idx]; if (x.vpn == vpn) return x.ppn | (vaddr & PGMASK); uint64_t paddr = walk(vaddr, type, mode); // optimization only, to void page walk x.ppn = (paddr & ~PGMASK); x.vpn = vpn; return paddr; } vm_info decode_vm_info(PrivilegeLevel prv) { assert(prv <= SupervisorMode); uint64_t ptbase = (uint64_t)core.csrs.satp.fields.ppn << PGSHIFT; unsigned mode = core.csrs.satp.fields.mode; switch (mode) { case SATP_MODE_SV32: return {2, 10, 4, ptbase}; case SATP_MODE_SV39: return {3, 9, 8, ptbase}; case SATP_MODE_SV48: return {4, 9, 8, ptbase}; case SATP_MODE_SV57: return {5, 9, 8, ptbase}; case SATP_MODE_SV64: return {6, 9, 8, ptbase}; default: throw std::runtime_error("unknown Sv (satp) mode " + std::to_string(mode)); } } bool check_vaddr_extension(uint64_t vaddr, const vm_info &vm) { int highbit = vm.idxbits * vm.levels + PGSHIFT - 1; assert(highbit > 0); uint64_t ext_mask = (uint64_t(1) << (core.xlen - highbit)) - 1; uint64_t bits = (vaddr >> highbit) & ext_mask; bool ok = (bits == 0) || (bits == ext_mask); return ok; } uint64_t walk(uint64_t vaddr, MemoryAccessType type, PrivilegeLevel mode) { bool s_mode = mode == SupervisorMode; bool sum = core.csrs.mstatus.fields.sum; bool mxr = core.csrs.mstatus.fields.mxr; vm_info vm = decode_vm_info(mode); if (!check_vaddr_extension(vaddr, vm)) vm.levels = 0; // skip loop and raise page fault uint64_t base = vm.ptbase; for (int i = vm.levels - 1; i >= 0; --i) { // obtain VPN field for current level, NOTE: all VPN fields have the same length for each separate VM // implementation int ptshift = i * vm.idxbits; unsigned vpn_field = (vaddr >> (PGSHIFT + ptshift)) & ((1 << vm.idxbits) - 1); auto pte_paddr = base + vpn_field * vm.ptesize; // TODO: PMP checks for pte_paddr with (LOAD, PRV_S) assert(vm.ptesize == 4 || vm.ptesize == 8); assert(mem); pte_t pte; if (vm.ptesize == 4) pte.value = mem->mmu_load_pte32(pte_paddr); else pte.value = mem->mmu_load_pte64(pte_paddr); uint64_t ppn = pte >> PTE_PPN_SHIFT; if (!pte.V() || (!pte.R() && pte.W())) { // std::cout << "[mmu] !pte.V() || (!pte.R() && pte.W())" << std::endl; break; } if (!pte.R() && !pte.X()) { base = ppn << PGSHIFT; continue; } assert(type == FETCH || type == LOAD || type == STORE); if ((type == FETCH) && !pte.X()) { // std::cout << "[mmu] (type == FETCH) && !pte.X()" << std::endl; break; } if ((type == LOAD) && !pte.R() && !(mxr && pte.X())) { // std::cout << "[mmu] (type == LOAD) && !pte.R() && !(mxr && pte.X())" << std::endl; break; } if ((type == STORE) && !(pte.R() && pte.W())) { // std::cout << "[mmu] (type == STORE) && !(pte.R() && pte.W())" << std::endl; break; } if (pte.U()) { if (s_mode && ((type == FETCH) || !sum)) break; } else { if (!s_mode) break; } // NOTE: all PPN (except the highest one) have the same bitwidth as the VPNs, hence ptshift can be used if ((ppn & ((uint64_t(1) << ptshift) - 1)) != 0) break; // misaligned superpage uint64_t ad = PTE_A | ((type == STORE) * PTE_D); if ((pte & ad) != ad) { if (page_fault_on_AD) { break; // let SW deal with this } else { // TODO: PMP checks for pte_paddr with (STORE, PRV_S) // NOTE: the store has to be atomic with the above load of the PTE, i.e. lock the bus if required // NOTE: only need to update A / D flags, hence it is enough to store 32 bit (8 bit might be enough // too) mem->mmu_store_pte32(pte_paddr, pte | ad); } } // translation successful, return physical address uint64_t mask = ((uint64_t(1) << ptshift) - 1); uint64_t vpn = vaddr >> PGSHIFT; uint64_t pgoff = vaddr & (PGSIZE - 1); uint64_t paddr = (((ppn & ~mask) | (vpn & mask)) << PGSHIFT) | pgoff; return paddr; } switch (type) { case FETCH: raise_trap(EXC_INSTR_PAGE_FAULT, vaddr); break; case LOAD: raise_trap(EXC_LOAD_PAGE_FAULT, vaddr); break; case STORE: raise_trap(EXC_STORE_AMO_PAGE_FAULT, vaddr); break; } throw std::runtime_error("[mmu] unknown access type " + std::to_string(type)); } }; ================================================ FILE: vp/src/core/common/mmu_mem_if.h ================================================ #ifndef RISCV_VP_MMU_MEM_IF_H #define RISCV_VP_MMU_MEM_IF_H #include enum MemoryAccessType { FETCH, LOAD, STORE }; struct mmu_memory_if { virtual ~mmu_memory_if() {} virtual uint64_t v2p(uint64_t vaddr, MemoryAccessType type) = 0; virtual uint64_t mmu_load_pte64(uint64_t addr) = 0; virtual uint64_t mmu_load_pte32(uint64_t addr) = 0; virtual void mmu_store_pte32(uint64_t addr, uint32_t value) = 0; }; #endif //RISCV_VP_MMU_MEM_IF_H ================================================ FILE: vp/src/core/common/rawmode.cpp ================================================ /* Copied from linenoise with slight modifications. * * Copyright (c) 2019, Sören Tempel * Copyright (c) 2010-2014, Salvatore Sanfilippo * Copyright (c) 2010-2013, Pieter Noordhuis * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE */ #include #include #include #include #include #include #include #include "rawmode.h" static int rawfd = -1; static struct termios orig_termios; static void reset_term(void) { // Signal might arrive before enableRawMode() if (rawfd < 0) return; disableRawMode(rawfd); } static void sighandler(int num) { (void)num; reset_term(); exit(EXIT_FAILURE); } static void sethandler(void) { size_t i; struct sigaction act; int signals[] = {SIGINT, SIGTERM, SIGQUIT, SIGHUP}; act.sa_flags = 0; act.sa_handler = sighandler; if (sigfillset(&act.sa_mask) == -1) throw std::system_error(errno, std::generic_category()); for (i = 0; i < (sizeof(signals) / sizeof(signals[0])); i++) { if (sigaction(signals[i], &act, NULL)) throw std::system_error(errno, std::generic_category()); } /* also make sure we cleanup on exit(3) */ if (atexit(reset_term)) throw std::system_error(errno, std::generic_category()); } void enableRawMode(int fd) { struct termios raw; // Check if rawm ode was already activated if (rawfd >= 0) return; if (!isatty(STDIN_FILENO)) return; // not a tty, nothing to do if (tcgetattr(fd, &orig_termios) == -1) goto fatal; raw = orig_termios; /* modify the original mode */ /* input modes: no break, no CR to NL, no parity check, no strip char, * no start/stop output control. */ raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); /* control modes - set 8 bit chars */ raw.c_cflag |= (CS8); /* local modes - choing off, canonical off, no extended functions, * no signal chars (^Z,^C) */ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); /* control chars - set return condition: min number of bytes and timer. * We want read to return every single byte, without timeout. */ raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */ /* put terminal in raw mode after flushing */ if (tcsetattr(fd, TCSAFLUSH, &raw) < 0) goto fatal; rawfd = fd; sethandler(); return; fatal: throw std::system_error(errno, std::generic_category()); } void disableRawMode(int fd) { if (rawfd < 0) return; if (tcsetattr(fd, TCSAFLUSH, &orig_termios) == -1) throw std::system_error(errno, std::generic_category()); rawfd = -1; } ================================================ FILE: vp/src/core/common/rawmode.h ================================================ #ifndef RISCV_VP_RAWMODE_H #define RISCV_VP_RAWMODE_H void enableRawMode(int); void disableRawMode(int); #endif ================================================ FILE: vp/src/core/common/real_clint.cpp ================================================ #include #include #include "real_clint.h" enum { MSIP_BASE = 0, MSIP_SIZE = 4, MTIMECMP_BASE = 0x4000, MTIMECMP_SIZE = 8, MTIME_BASE = 0xBFF8, MTIME_SIZE = 8, }; enum { MSIP_MASK = 0x1, // The upper MSIP bits are tied to zero }; /* This is used to quantize a 1MHz value to the closest 32768Hz value */ #define DIVIDEND (uint64_t(15625)/uint64_t(512)) static void timercb(void *arg) { AsyncEvent *event = (AsyncEvent *)arg; event->notify(); } RealCLINT::RealCLINT(sc_core::sc_module_name, std::vector &_harts) : regs_msip(MSIP_BASE, MSIP_SIZE * _harts.size()), regs_mtimecmp(MTIMECMP_BASE, MTIMECMP_SIZE * _harts.size()), regs_mtime(MTIME_BASE, MTIME_SIZE), msip(regs_msip), mtimecmp(regs_mtimecmp), mtime(regs_mtime), harts(_harts) { for (size_t i = 0; i < harts.size(); i++) { Timer *timer = new Timer(timercb, &event); timers.push_back(timer); } register_ranges.insert(register_ranges.end(), {®s_mtimecmp, ®s_msip, ®s_mtime}); for (auto reg : register_ranges) reg->alignment = 4; regs_mtimecmp.post_write_callback = std::bind(&RealCLINT::post_write_mtimecmp, this, std::placeholders::_1); regs_msip.post_write_callback = std::bind(&RealCLINT::post_write_msip, this, std::placeholders::_1); regs_mtime.pre_read_callback = std::bind(&RealCLINT::pre_read_mtime, this, std::placeholders::_1); regs_mtime.post_write_callback = std::bind(&RealCLINT::post_write_mtime, this, std::placeholders::_1); first_mtime = std::chrono::high_resolution_clock::now(); tsock.register_b_transport(this, &RealCLINT::transport); SC_METHOD(interrupt); sensitive << event; dont_initialize(); } RealCLINT::~RealCLINT(void) { for (auto timer : timers) delete timer; } uint64_t RealCLINT::update_and_get_mtime(void) { time_point now = std::chrono::high_resolution_clock::now(); usecs duration = std::chrono::duration_cast(now - first_mtime); mtime = usec_to_ticks(duration); return mtime; } uint64_t RealCLINT::usec_to_ticks(usecs usec) { // This algorithm is inspired by the implementation provided by RIOT-OS. // https://github.com/RIOT-OS/RIOT/blob/d382bd656569599691c1a3e1c9b1662e07cf1a42/sys/include/xtimer/tick_conversion.h#L100-L106 uint64_t microseconds = usec.count(); return microseconds / DIVIDEND; } RealCLINT::usecs RealCLINT::ticks_to_usec(uint64_t ticks) { // See comment in RealCLINT::usec_to_ticks return usecs(ticks * DIVIDEND); } void RealCLINT::post_write_mtimecmp(RegisterRange::WriteInfo info) { assert(info.addr % 4 == 0); unsigned hart = info.addr / MTIMECMP_SIZE; uint64_t cmp = mtimecmp.at(hart); uint64_t time = update_and_get_mtime(); Timer *timer = timers.at(hart); timer->pause(); if (time >= cmp) { harts.at(hart)->trigger_timer_interrupt(true); return; } harts.at(hart)->trigger_timer_interrupt(false); uint64_t goal_ticks = cmp - time; usecs duration = ticks_to_usec(goal_ticks); timer->start(duration); } void RealCLINT::post_write_msip(RegisterRange::WriteInfo info) { assert(info.addr % 4 == 0); unsigned hart = info.addr / MSIP_SIZE; msip.at(hart) &= MSIP_MASK; harts.at(hart)->trigger_software_interrupt(msip.at(hart) != 0); } void RealCLINT::post_write_mtime(RegisterRange::WriteInfo info) { /* TODO: * 1. Adjust first_mtime to reflect new mtime register value. * 2. Notify asyncEvent to check if a timmer intr must be raised. * Potentially requires stopping existing timers. */ (void)info; } bool RealCLINT::pre_read_mtime(RegisterRange::ReadInfo info) { (void)info; update_and_get_mtime(); return true; } void RealCLINT::interrupt(void) { update_and_get_mtime(); for (size_t i = 0; i < harts.size(); i++) { auto cmp = mtimecmp.at(i); if (mtime >= cmp) harts.at(i)->trigger_timer_interrupt(true); } } void RealCLINT::transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { vp::mm::route("RealCLINT", register_ranges, trans, delay); } ================================================ FILE: vp/src/core/common/real_clint.h ================================================ #ifndef RISCV_VP_REAL_CLINT_H #define RISCV_VP_REAL_CLINT_H #include #include #include #include #include #include "platform/common/async_event.h" #include "util/memory_map.h" #include "clint_if.h" #include "irq_if.h" #include "timer.h" // This class implements a CLINT as specified in the FE310-G000 manual // and the RISC-V Privileged Specification. As per the FE310-G000 // manual, this CLINT uses an input clock which runs at a frequency of // 32.768 kHz. Currently, this frequency cannot be configured. // // Contrary to the CLINT class, also provided in this directory, this // CLINT is based on "real time" instead of SystemC simulation time. class RealCLINT : public clint_if, public sc_core::sc_module { public: RealCLINT(sc_core::sc_module_name, std::vector&); ~RealCLINT(void); tlm_utils::simple_target_socket tsock; uint64_t update_and_get_mtime(void) override; SC_HAS_PROCESS(RealCLINT); public: typedef std::chrono::high_resolution_clock::time_point time_point; typedef Timer::usecs usecs; RegisterRange regs_msip; RegisterRange regs_mtimecmp; RegisterRange regs_mtime; ArrayView msip; ArrayView mtimecmp; IntegerView mtime; std::vector register_ranges; std::vector &harts; AsyncEvent event; std::vector timers; time_point first_mtime; void post_write_mtimecmp(RegisterRange::WriteInfo info); void post_write_msip(RegisterRange::WriteInfo info); void post_write_mtime(RegisterRange::WriteInfo info); bool pre_read_mtime(RegisterRange::ReadInfo info); uint64_t usec_to_ticks(usecs usec); usecs ticks_to_usec(uint64_t ticks); void interrupt(void); void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay); }; #endif ================================================ FILE: vp/src/core/common/timer.cpp ================================================ #include #include #include #include #include #include #include "timer.h" /* As defined in nanosleep(3) */ #define NS_MAX 999999999UL #define US_MAX (NS_MAX / 1000) /* Signal used to unblock nanosleep in thread */ #define SIGNUM SIGUSR1 static int xnanosleep(const struct timespec *timespec) { if (nanosleep(timespec, NULL) == 0) return 0; /* success */ if (errno == EINTR) return -1; /* received signal via pthread_kill, terminate */ err(EXIT_FAILURE, "nanosleep failed"); /* EFAULT, EINVAL, … */ } static void * callback(void *arg) { struct timespec timespec; Timer::Context *ctx = (Timer::Context*)arg; /* Initialize the seconds field, we use nanoseconds though */ timespec.tv_sec = 0; auto count = ctx->duration.count(); while (count > US_MAX) { timespec.tv_nsec = NS_MAX; if (xnanosleep(×pec)) return NULL; /* pthread_kill */ count -= US_MAX; } // Convert remaining us → ns with overflow check uint64_t ns = count * 1000; assert(ns > count); assert(ns <= LONG_MAX); // tv_nsec is a long timespec.tv_nsec = ns; if (xnanosleep(×pec)) return NULL; /* pthread_kill */ ctx->fn(ctx->arg); return NULL; } Timer::Timer(Callback fn, void *arg) : ctx(usecs(0), fn, arg) { running = false; } Timer::~Timer(void) { pause(); } void Timer::start(usecs duration) { if (running && (errno = pthread_join(thread, NULL))) throw std::system_error(errno, std::generic_category()); /* Update duration for new callback */ ctx.duration = duration; if ((errno = pthread_create(&thread, NULL, callback, &ctx))) throw std::system_error(errno, std::generic_category()); running = true; } void Timer::pause(void) { struct sigaction sa; if (!running) return; sa.sa_handler = SIG_IGN; sa.sa_flags = SA_RESTART; if (sigemptyset(&sa.sa_mask) == -1) throw std::system_error(errno, std::generic_category()); if (sigaction(SIGNUM, &sa, NULL) == -1) throw std::system_error(errno, std::generic_category()); /* Signal is ignored in main thread, send it to background * thread and restore the default handler afterwards. */ stop_thread(); sa.sa_handler = SIG_DFL; if (sigaction(SIGNUM, &sa, NULL) == -1) throw std::system_error(errno, std::generic_category()); } void Timer::stop_thread(void) { /* Attempt to cancel thread first, for the event that it hasn't * invoked nanosleep yet. The nanosleep function is a * cancelation point, as per pthreads(7). If the thread is * blocked in nanosleep the signal should interrupt the * nanosleep system call and cause thread termination. */ assert(running); // Either pthread_cancel or pthread_kill will stop the thread, in // which case the other one will error out thus the error is ignored. pthread_cancel(thread); pthread_kill(thread, SIGNUM); if ((errno = pthread_join(thread, NULL))) throw std::system_error(errno, std::generic_category()); running = false; } ================================================ FILE: vp/src/core/common/timer.h ================================================ #ifndef RISCV_VP_TIMER_H #define RISCV_VP_TIMER_H #include #include #include #include #include class Timer { public: typedef std::chrono::duration usecs; typedef void (*Callback) (void*); class Context { public: Timer::usecs duration; Callback fn; void *arg; Context(usecs _duration, Callback _fn, void *_arg) : duration(_duration), fn(_fn), arg(_arg) {}; }; Timer(Callback fn, void *arg); ~Timer(void); void pause(void); void start(usecs duration); private: Context ctx; pthread_t thread; bool running; void stop_thread(void); }; #endif ================================================ FILE: vp/src/core/common/trap.h ================================================ #pragma once enum ExceptionCode { // interrupt exception codes (mcause) EXC_U_SOFTWARE_INTERRUPT = 0, EXC_S_SOFTWARE_INTERRUPT = 1, EXC_M_SOFTWARE_INTERRUPT = 3, EXC_U_TIMER_INTERRUPT = 4, EXC_S_TIMER_INTERRUPT = 5, EXC_M_TIMER_INTERRUPT = 7, EXC_U_EXTERNAL_INTERRUPT = 8, EXC_S_EXTERNAL_INTERRUPT = 9, EXC_M_EXTERNAL_INTERRUPT = 11, // non-interrupt exception codes (mcause) EXC_INSTR_ADDR_MISALIGNED = 0, EXC_INSTR_ACCESS_FAULT = 1, EXC_ILLEGAL_INSTR = 2, EXC_BREAKPOINT = 3, EXC_LOAD_ADDR_MISALIGNED = 4, EXC_LOAD_ACCESS_FAULT = 5, EXC_STORE_AMO_ADDR_MISALIGNED = 6, EXC_STORE_AMO_ACCESS_FAULT = 7, EXC_ECALL_U_MODE = 8, EXC_ECALL_S_MODE = 9, EXC_ECALL_M_MODE = 11, EXC_INSTR_PAGE_FAULT = 12, EXC_LOAD_PAGE_FAULT = 13, EXC_STORE_AMO_PAGE_FAULT = 15, }; struct SimulationTrap { ExceptionCode reason; unsigned long mtval; }; inline void raise_trap(ExceptionCode exc, unsigned long mtval) { throw SimulationTrap({exc, mtval}); } ================================================ FILE: vp/src/core/rv32/CMakeLists.txt ================================================ file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) add_library(rv32 iss.cpp syscall.cpp ${HEADERS}) target_link_libraries(rv32 systemc core-common softfloat) if(COLOR_THEME STREQUAL "LIGHT") message("> using color theme LIGHT") target_compile_definitions(rv32 PRIVATE COLOR_THEME_LIGHT) elseif(COLOR_THEME STREQUAL "DARK") message("> using color theme DARK") target_compile_definitions(rv32 PRIVATE COLOR_THEME_DARK) endif() target_include_directories(rv32 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) ================================================ FILE: vp/src/core/rv32/csr.h ================================================ #pragma once #include #include #include #include #include "core/common/trap.h" #include "util/common.h" namespace rv32 { constexpr unsigned FS_OFF = 0b00; constexpr unsigned FS_INITIAL = 0b01; constexpr unsigned FS_CLEAN = 0b10; constexpr unsigned FS_DIRTY = 0b11; inline bool is_valid_privilege_level(PrivilegeLevel mode) { return mode == MachineMode || mode == SupervisorMode || mode == UserMode; } struct csr_32 { uint32_t reg = 0; }; struct csr_misa { csr_misa() { init(); } union { uint32_t reg = 0; struct { unsigned extensions : 26; unsigned wiri : 4; unsigned mxl : 2; } fields; }; bool has_C_extension() { return fields.extensions & C; } bool has_E_base_isa() { return fields.extensions & E; } void select_E_base_isa() { fields.extensions &= ~I; fields.extensions |= E; } bool has_user_mode_extension() { return fields.extensions & U; } bool has_supervisor_mode_extension() { return fields.extensions & S; } enum { A = 1, C = 1 << 2, D = 1 << 3, E = 1 << 4, F = 1 << 5, I = 1 << 8, M = 1 << 12, N = 1 << 13, S = 1 << 18, U = 1 << 20, }; void init() { fields.extensions = I | M | A | F | C | N | U | S; // IMACF + NUS fields.wiri = 0; fields.mxl = 1; // RV32 } }; constexpr unsigned M_ISA_EXT = csr_misa::M; constexpr unsigned A_ISA_EXT = csr_misa::A; constexpr unsigned F_ISA_EXT = csr_misa::F; constexpr unsigned D_ISA_EXT = csr_misa::D; constexpr unsigned C_ISA_EXT = csr_misa::C; struct csr_mvendorid { union { uint32_t reg = 0; struct { unsigned offset : 7; unsigned bank : 25; } fields; }; }; struct csr_mstatus { union { uint32_t reg = 0; struct { unsigned uie : 1; unsigned sie : 1; unsigned wpri1 : 1; unsigned mie : 1; unsigned upie : 1; unsigned spie : 1; unsigned wpri2 : 1; unsigned mpie : 1; unsigned spp : 1; unsigned wpri3 : 2; unsigned mpp : 2; unsigned fs : 2; unsigned xs : 2; unsigned mprv : 1; unsigned sum : 1; unsigned mxr : 1; unsigned tvm : 1; unsigned tw : 1; unsigned tsr : 1; unsigned wpri4 : 8; unsigned sd : 1; } fields; }; }; struct csr_mtvec { union { uint32_t reg = 0; struct { unsigned mode : 2; // WARL unsigned base : 30; // WARL } fields; }; uint32_t get_base_address() { return fields.base << 2; } enum Mode { Direct = 0, Vectored = 1 }; void checked_write(uint32_t val) { reg = val; if (fields.mode >= 1) fields.mode = 0; } }; struct csr_mie { union { uint32_t reg = 0; struct { unsigned usie : 1; unsigned ssie : 1; unsigned wpri1 : 1; unsigned msie : 1; unsigned utie : 1; unsigned stie : 1; unsigned wpri2 : 1; unsigned mtie : 1; unsigned ueie : 1; unsigned seie : 1; unsigned wpri3 : 1; unsigned meie : 1; unsigned wpri4 : 20; } fields; }; }; struct csr_mip { union { uint32_t reg = 0; struct { unsigned usip : 1; unsigned ssip : 1; unsigned wiri1 : 1; unsigned msip : 1; unsigned utip : 1; unsigned stip : 1; unsigned wiri2 : 1; unsigned mtip : 1; unsigned ueip : 1; unsigned seip : 1; unsigned wiri3 : 1; unsigned meip : 1; unsigned wiri4 : 20; } fields; }; }; struct csr_mepc { union { uint32_t reg = 0; }; }; struct csr_mcause { union { uint32_t reg = 0; struct { unsigned exception_code : 31; // WLRL unsigned interrupt : 1; } fields; }; }; struct csr_mcounteren { union { uint32_t reg = 0; struct { unsigned CY : 1; unsigned TM : 1; unsigned IR : 1; unsigned reserved : 29; } fields; }; }; struct csr_mcountinhibit { union { uint32_t reg = 0; struct { unsigned CY : 1; unsigned zero : 1; unsigned IR : 1; unsigned reserved : 29; } fields; }; }; struct csr_pmpcfg { union { uint32_t reg = 0; struct { unsigned UNIMPLEMENTED : 24; // WARL unsigned L0 : 1; // WARL unsigned _wiri0 : 2; // WIRI unsigned A0 : 2; // WARL unsigned X0 : 1; // WARL unsigned W0 : 1; // WARL unsigned R0 : 1; // WARL } fields; }; }; struct csr_satp { union { uint32_t reg = 0; struct { unsigned ppn : 22; // WARL unsigned asid : 9; // WARL unsigned mode : 1; // WARL } fields; }; }; struct csr_fcsr { union { uint32_t reg = 0; struct { unsigned fflags : 5; unsigned frm : 3; unsigned reserved : 24; } fields; // fflags accessed separately struct { unsigned NX : 1; // invalid operation unsigned UF : 1; // divide by zero unsigned OF : 1; // overflow unsigned DZ : 1; // underflow unsigned NV : 1; // inexact unsigned _ : 27; } fflags; }; }; /* * Add new subclasses with specific consistency check (e.g. by adding virtual * write_low, write_high functions) if necessary. */ struct csr_64 { union { uint64_t reg = 0; struct { int32_t low; int32_t high; } words; }; void increment() { ++reg; } }; namespace csr { template inline bool is_bitset(T &csr, unsigned bitpos) { return csr.reg & (1 << bitpos); } constexpr uint32_t MIE_MASK = 0b101110111011; constexpr uint32_t SIE_MASK = 0b001100110011; constexpr uint32_t UIE_MASK = 0b000100010001; constexpr uint32_t MIP_WRITE_MASK = 0b001100110011; constexpr uint32_t MIP_READ_MASK = MIE_MASK; constexpr uint32_t SIP_MASK = 0b11; constexpr uint32_t UIP_MASK = 0b1; constexpr uint32_t MEDELEG_MASK = 0b1011101111111111; constexpr uint32_t MIDELEG_MASK = MIE_MASK; constexpr uint32_t MTVEC_MASK = ~2; constexpr uint32_t MCOUNTEREN_MASK = 0b111; constexpr uint32_t MCOUNTINHIBIT_MASK = 0b101; constexpr uint32_t SEDELEG_MASK = 0b1011000111111111; constexpr uint32_t SIDELEG_MASK = MIDELEG_MASK; constexpr uint32_t MSTATUS_MASK = 0b10000000011111111111100110111011; constexpr uint32_t SSTATUS_MASK = 0b10000000000011011110000100110011; constexpr uint32_t USTATUS_MASK = 0b00000000000000000000000000010001; constexpr uint32_t SATP_MASK = 0b10000000001111111111111111111111; constexpr uint32_t SATP_MODE = 0b10000000000000000000000000000000; constexpr uint32_t FCSR_MASK = 0b11111111; // 64 bit timer csrs constexpr unsigned CYCLE_ADDR = 0xC00; constexpr unsigned CYCLEH_ADDR = 0xC80; constexpr unsigned TIME_ADDR = 0xC01; constexpr unsigned TIMEH_ADDR = 0xC81; constexpr unsigned INSTRET_ADDR = 0xC02; constexpr unsigned INSTRETH_ADDR = 0xC82; // shadows for the above CSRs constexpr unsigned MCYCLE_ADDR = 0xB00; constexpr unsigned MCYCLEH_ADDR = 0xB80; constexpr unsigned MTIME_ADDR = 0xB01; constexpr unsigned MTIMEH_ADDR = 0xB81; constexpr unsigned MINSTRET_ADDR = 0xB02; constexpr unsigned MINSTRETH_ADDR = 0xB82; // debug CSRs constexpr unsigned TSELECT_ADDR = 0x7A0; constexpr unsigned TDATA1_ADDR = 0x7A1; constexpr unsigned TDATA2_ADDR = 0x7A2; constexpr unsigned TDATA3_ADDR = 0x7A3; constexpr unsigned DCSR_ADDR = 0x7B0; constexpr unsigned DPC_ADDR = 0x7B1; constexpr unsigned DSCRATCH0_ADDR = 0x7B2; constexpr unsigned DSCRATCH1_ADDR = 0x7B3; // 32 bit machine CSRs constexpr unsigned MVENDORID_ADDR = 0xF11; constexpr unsigned MARCHID_ADDR = 0xF12; constexpr unsigned MIMPID_ADDR = 0xF13; constexpr unsigned MHARTID_ADDR = 0xF14; constexpr unsigned MSTATUS_ADDR = 0x300; constexpr unsigned MISA_ADDR = 0x301; constexpr unsigned MEDELEG_ADDR = 0x302; constexpr unsigned MIDELEG_ADDR = 0x303; constexpr unsigned MIE_ADDR = 0x304; constexpr unsigned MTVEC_ADDR = 0x305; constexpr unsigned MCOUNTEREN_ADDR = 0x306; constexpr unsigned MCOUNTINHIBIT_ADDR = 0x320; constexpr unsigned MSCRATCH_ADDR = 0x340; constexpr unsigned MEPC_ADDR = 0x341; constexpr unsigned MCAUSE_ADDR = 0x342; constexpr unsigned MTVAL_ADDR = 0x343; constexpr unsigned MIP_ADDR = 0x344; constexpr unsigned PMPCFG0_ADDR = 0x3A0; constexpr unsigned PMPCFG1_ADDR = 0x3A1; constexpr unsigned PMPCFG2_ADDR = 0x3A2; constexpr unsigned PMPCFG3_ADDR = 0x3A3; constexpr unsigned PMPADDR0_ADDR = 0x3B0; constexpr unsigned PMPADDR1_ADDR = 0x3B1; constexpr unsigned PMPADDR2_ADDR = 0x3B2; constexpr unsigned PMPADDR3_ADDR = 0x3B3; constexpr unsigned PMPADDR4_ADDR = 0x3B4; constexpr unsigned PMPADDR5_ADDR = 0x3B5; constexpr unsigned PMPADDR6_ADDR = 0x3B6; constexpr unsigned PMPADDR7_ADDR = 0x3B7; constexpr unsigned PMPADDR8_ADDR = 0x3B8; constexpr unsigned PMPADDR9_ADDR = 0x3B9; constexpr unsigned PMPADDR10_ADDR = 0x3BA; constexpr unsigned PMPADDR11_ADDR = 0x3BB; constexpr unsigned PMPADDR12_ADDR = 0x3BC; constexpr unsigned PMPADDR13_ADDR = 0x3BD; constexpr unsigned PMPADDR14_ADDR = 0x3BE; constexpr unsigned PMPADDR15_ADDR = 0x3BF; // 32 bit supervisor CSRs constexpr unsigned SSTATUS_ADDR = 0x100; constexpr unsigned SEDELEG_ADDR = 0x102; constexpr unsigned SIDELEG_ADDR = 0x103; constexpr unsigned SIE_ADDR = 0x104; constexpr unsigned STVEC_ADDR = 0x105; constexpr unsigned SCOUNTEREN_ADDR = 0x106; constexpr unsigned SSCRATCH_ADDR = 0x140; constexpr unsigned SEPC_ADDR = 0x141; constexpr unsigned SCAUSE_ADDR = 0x142; constexpr unsigned STVAL_ADDR = 0x143; constexpr unsigned SIP_ADDR = 0x144; constexpr unsigned SATP_ADDR = 0x180; // 32 bit user CSRs constexpr unsigned USTATUS_ADDR = 0x000; constexpr unsigned UIE_ADDR = 0x004; constexpr unsigned UTVEC_ADDR = 0x005; constexpr unsigned USCRATCH_ADDR = 0x040; constexpr unsigned UEPC_ADDR = 0x041; constexpr unsigned UCAUSE_ADDR = 0x042; constexpr unsigned UTVAL_ADDR = 0x043; constexpr unsigned UIP_ADDR = 0x044; // floating point CSRs constexpr unsigned FFLAGS_ADDR = 0x001; constexpr unsigned FRM_ADDR = 0x002; constexpr unsigned FCSR_ADDR = 0x003; // performance counters constexpr unsigned HPMCOUNTER3_ADDR = 0xC03; constexpr unsigned HPMCOUNTER4_ADDR = 0xC04; constexpr unsigned HPMCOUNTER5_ADDR = 0xC05; constexpr unsigned HPMCOUNTER6_ADDR = 0xC06; constexpr unsigned HPMCOUNTER7_ADDR = 0xC07; constexpr unsigned HPMCOUNTER8_ADDR = 0xC08; constexpr unsigned HPMCOUNTER9_ADDR = 0xC09; constexpr unsigned HPMCOUNTER10_ADDR = 0xC0A; constexpr unsigned HPMCOUNTER11_ADDR = 0xC0B; constexpr unsigned HPMCOUNTER12_ADDR = 0xC0C; constexpr unsigned HPMCOUNTER13_ADDR = 0xC0D; constexpr unsigned HPMCOUNTER14_ADDR = 0xC0E; constexpr unsigned HPMCOUNTER15_ADDR = 0xC0F; constexpr unsigned HPMCOUNTER16_ADDR = 0xC10; constexpr unsigned HPMCOUNTER17_ADDR = 0xC11; constexpr unsigned HPMCOUNTER18_ADDR = 0xC12; constexpr unsigned HPMCOUNTER19_ADDR = 0xC13; constexpr unsigned HPMCOUNTER20_ADDR = 0xC14; constexpr unsigned HPMCOUNTER21_ADDR = 0xC15; constexpr unsigned HPMCOUNTER22_ADDR = 0xC16; constexpr unsigned HPMCOUNTER23_ADDR = 0xC17; constexpr unsigned HPMCOUNTER24_ADDR = 0xC18; constexpr unsigned HPMCOUNTER25_ADDR = 0xC19; constexpr unsigned HPMCOUNTER26_ADDR = 0xC1A; constexpr unsigned HPMCOUNTER27_ADDR = 0xC1B; constexpr unsigned HPMCOUNTER28_ADDR = 0xC1C; constexpr unsigned HPMCOUNTER29_ADDR = 0xC1D; constexpr unsigned HPMCOUNTER30_ADDR = 0xC1E; constexpr unsigned HPMCOUNTER31_ADDR = 0xC1F; constexpr unsigned HPMCOUNTER3H_ADDR = 0xC83; constexpr unsigned HPMCOUNTER4H_ADDR = 0xC84; constexpr unsigned HPMCOUNTER5H_ADDR = 0xC85; constexpr unsigned HPMCOUNTER6H_ADDR = 0xC86; constexpr unsigned HPMCOUNTER7H_ADDR = 0xC87; constexpr unsigned HPMCOUNTER8H_ADDR = 0xC88; constexpr unsigned HPMCOUNTER9H_ADDR = 0xC89; constexpr unsigned HPMCOUNTER10H_ADDR = 0xC8A; constexpr unsigned HPMCOUNTER11H_ADDR = 0xC8B; constexpr unsigned HPMCOUNTER12H_ADDR = 0xC8C; constexpr unsigned HPMCOUNTER13H_ADDR = 0xC8D; constexpr unsigned HPMCOUNTER14H_ADDR = 0xC8E; constexpr unsigned HPMCOUNTER15H_ADDR = 0xC8F; constexpr unsigned HPMCOUNTER16H_ADDR = 0xC90; constexpr unsigned HPMCOUNTER17H_ADDR = 0xC91; constexpr unsigned HPMCOUNTER18H_ADDR = 0xC92; constexpr unsigned HPMCOUNTER19H_ADDR = 0xC93; constexpr unsigned HPMCOUNTER20H_ADDR = 0xC94; constexpr unsigned HPMCOUNTER21H_ADDR = 0xC95; constexpr unsigned HPMCOUNTER22H_ADDR = 0xC96; constexpr unsigned HPMCOUNTER23H_ADDR = 0xC97; constexpr unsigned HPMCOUNTER24H_ADDR = 0xC98; constexpr unsigned HPMCOUNTER25H_ADDR = 0xC99; constexpr unsigned HPMCOUNTER26H_ADDR = 0xC9A; constexpr unsigned HPMCOUNTER27H_ADDR = 0xC9B; constexpr unsigned HPMCOUNTER28H_ADDR = 0xC9C; constexpr unsigned HPMCOUNTER29H_ADDR = 0xC9D; constexpr unsigned HPMCOUNTER30H_ADDR = 0xC9E; constexpr unsigned HPMCOUNTER31H_ADDR = 0xC9F; constexpr unsigned MHPMCOUNTER3_ADDR = 0xB03; constexpr unsigned MHPMCOUNTER4_ADDR = 0xB04; constexpr unsigned MHPMCOUNTER5_ADDR = 0xB05; constexpr unsigned MHPMCOUNTER6_ADDR = 0xB06; constexpr unsigned MHPMCOUNTER7_ADDR = 0xB07; constexpr unsigned MHPMCOUNTER8_ADDR = 0xB08; constexpr unsigned MHPMCOUNTER9_ADDR = 0xB09; constexpr unsigned MHPMCOUNTER10_ADDR = 0xB0A; constexpr unsigned MHPMCOUNTER11_ADDR = 0xB0B; constexpr unsigned MHPMCOUNTER12_ADDR = 0xB0C; constexpr unsigned MHPMCOUNTER13_ADDR = 0xB0D; constexpr unsigned MHPMCOUNTER14_ADDR = 0xB0E; constexpr unsigned MHPMCOUNTER15_ADDR = 0xB0F; constexpr unsigned MHPMCOUNTER16_ADDR = 0xB10; constexpr unsigned MHPMCOUNTER17_ADDR = 0xB11; constexpr unsigned MHPMCOUNTER18_ADDR = 0xB12; constexpr unsigned MHPMCOUNTER19_ADDR = 0xB13; constexpr unsigned MHPMCOUNTER20_ADDR = 0xB14; constexpr unsigned MHPMCOUNTER21_ADDR = 0xB15; constexpr unsigned MHPMCOUNTER22_ADDR = 0xB16; constexpr unsigned MHPMCOUNTER23_ADDR = 0xB17; constexpr unsigned MHPMCOUNTER24_ADDR = 0xB18; constexpr unsigned MHPMCOUNTER25_ADDR = 0xB19; constexpr unsigned MHPMCOUNTER26_ADDR = 0xB1A; constexpr unsigned MHPMCOUNTER27_ADDR = 0xB1B; constexpr unsigned MHPMCOUNTER28_ADDR = 0xB1C; constexpr unsigned MHPMCOUNTER29_ADDR = 0xB1D; constexpr unsigned MHPMCOUNTER30_ADDR = 0xB1E; constexpr unsigned MHPMCOUNTER31_ADDR = 0xB1F; constexpr unsigned MHPMCOUNTER3H_ADDR = 0xB83; constexpr unsigned MHPMCOUNTER4H_ADDR = 0xB84; constexpr unsigned MHPMCOUNTER5H_ADDR = 0xB85; constexpr unsigned MHPMCOUNTER6H_ADDR = 0xB86; constexpr unsigned MHPMCOUNTER7H_ADDR = 0xB87; constexpr unsigned MHPMCOUNTER8H_ADDR = 0xB88; constexpr unsigned MHPMCOUNTER9H_ADDR = 0xB89; constexpr unsigned MHPMCOUNTER10H_ADDR = 0xB8A; constexpr unsigned MHPMCOUNTER11H_ADDR = 0xB8B; constexpr unsigned MHPMCOUNTER12H_ADDR = 0xB8C; constexpr unsigned MHPMCOUNTER13H_ADDR = 0xB8D; constexpr unsigned MHPMCOUNTER14H_ADDR = 0xB8E; constexpr unsigned MHPMCOUNTER15H_ADDR = 0xB8F; constexpr unsigned MHPMCOUNTER16H_ADDR = 0xB90; constexpr unsigned MHPMCOUNTER17H_ADDR = 0xB91; constexpr unsigned MHPMCOUNTER18H_ADDR = 0xB92; constexpr unsigned MHPMCOUNTER19H_ADDR = 0xB93; constexpr unsigned MHPMCOUNTER20H_ADDR = 0xB94; constexpr unsigned MHPMCOUNTER21H_ADDR = 0xB95; constexpr unsigned MHPMCOUNTER22H_ADDR = 0xB96; constexpr unsigned MHPMCOUNTER23H_ADDR = 0xB97; constexpr unsigned MHPMCOUNTER24H_ADDR = 0xB98; constexpr unsigned MHPMCOUNTER25H_ADDR = 0xB99; constexpr unsigned MHPMCOUNTER26H_ADDR = 0xB9A; constexpr unsigned MHPMCOUNTER27H_ADDR = 0xB9B; constexpr unsigned MHPMCOUNTER28H_ADDR = 0xB9C; constexpr unsigned MHPMCOUNTER29H_ADDR = 0xB9D; constexpr unsigned MHPMCOUNTER30H_ADDR = 0xB9E; constexpr unsigned MHPMCOUNTER31H_ADDR = 0xB9F; constexpr unsigned MHPMEVENT3_ADDR = 0x323; constexpr unsigned MHPMEVENT4_ADDR = 0x324; constexpr unsigned MHPMEVENT5_ADDR = 0x325; constexpr unsigned MHPMEVENT6_ADDR = 0x326; constexpr unsigned MHPMEVENT7_ADDR = 0x327; constexpr unsigned MHPMEVENT8_ADDR = 0x328; constexpr unsigned MHPMEVENT9_ADDR = 0x329; constexpr unsigned MHPMEVENT10_ADDR = 0x32A; constexpr unsigned MHPMEVENT11_ADDR = 0x32B; constexpr unsigned MHPMEVENT12_ADDR = 0x32C; constexpr unsigned MHPMEVENT13_ADDR = 0x32D; constexpr unsigned MHPMEVENT14_ADDR = 0x32E; constexpr unsigned MHPMEVENT15_ADDR = 0x32F; constexpr unsigned MHPMEVENT16_ADDR = 0x330; constexpr unsigned MHPMEVENT17_ADDR = 0x331; constexpr unsigned MHPMEVENT18_ADDR = 0x332; constexpr unsigned MHPMEVENT19_ADDR = 0x333; constexpr unsigned MHPMEVENT20_ADDR = 0x334; constexpr unsigned MHPMEVENT21_ADDR = 0x335; constexpr unsigned MHPMEVENT22_ADDR = 0x336; constexpr unsigned MHPMEVENT23_ADDR = 0x337; constexpr unsigned MHPMEVENT24_ADDR = 0x338; constexpr unsigned MHPMEVENT25_ADDR = 0x339; constexpr unsigned MHPMEVENT26_ADDR = 0x33A; constexpr unsigned MHPMEVENT27_ADDR = 0x33B; constexpr unsigned MHPMEVENT28_ADDR = 0x33C; constexpr unsigned MHPMEVENT29_ADDR = 0x33D; constexpr unsigned MHPMEVENT30_ADDR = 0x33E; constexpr unsigned MHPMEVENT31_ADDR = 0x33F; }; // namespace csr struct csr_table { csr_64 cycle; csr_64 time; csr_64 instret; csr_mvendorid mvendorid; csr_32 marchid; csr_32 mimpid; csr_32 mhartid; csr_mstatus mstatus; csr_misa misa; csr_32 medeleg; csr_32 mideleg; csr_mie mie; csr_mtvec mtvec; csr_mcounteren mcounteren; csr_mcountinhibit mcountinhibit; csr_32 mscratch; csr_mepc mepc; csr_mcause mcause; csr_32 mtval; csr_mip mip; // pmp configuration std::array pmpaddr; std::array pmpcfg; // supervisor csrs (please note: some are already covered by the machine mode csrs, i.e. sstatus, sie and sip, and // some are required but have the same fields, hence the machine mode classes are used) csr_32 sedeleg; csr_32 sideleg; csr_mtvec stvec; csr_mcounteren scounteren; csr_32 sscratch; csr_mepc sepc; csr_mcause scause; csr_32 stval; csr_satp satp; // user csrs (see above comment) csr_mtvec utvec; csr_32 uscratch; csr_mepc uepc; csr_mcause ucause; csr_32 utval; csr_fcsr fcsr; std::unordered_map register_mapping; csr_table() { using namespace csr; register_mapping[CYCLE_ADDR] = (uint32_t *)(&cycle.reg); register_mapping[CYCLEH_ADDR] = (uint32_t *)(&cycle.reg) + 1; register_mapping[TIME_ADDR] = (uint32_t *)(&time.reg); register_mapping[TIMEH_ADDR] = (uint32_t *)(&time.reg) + 1; register_mapping[INSTRET_ADDR] = (uint32_t *)(&instret.reg); register_mapping[INSTRETH_ADDR] = (uint32_t *)(&instret.reg) + 1; register_mapping[MCYCLE_ADDR] = (uint32_t *)(&cycle.reg); register_mapping[MCYCLEH_ADDR] = (uint32_t *)(&cycle.reg) + 1; register_mapping[MTIME_ADDR] = (uint32_t *)(&time.reg); register_mapping[MTIMEH_ADDR] = (uint32_t *)(&time.reg) + 1; register_mapping[MINSTRET_ADDR] = (uint32_t *)(&instret.reg); register_mapping[MINSTRETH_ADDR] = (uint32_t *)(&instret.reg) + 1; register_mapping[MVENDORID_ADDR] = &mvendorid.reg; register_mapping[MARCHID_ADDR] = &marchid.reg; register_mapping[MIMPID_ADDR] = &mimpid.reg; register_mapping[MHARTID_ADDR] = &mhartid.reg; register_mapping[MSTATUS_ADDR] = &mstatus.reg; register_mapping[MISA_ADDR] = &misa.reg; register_mapping[MEDELEG_ADDR] = &medeleg.reg; register_mapping[MIDELEG_ADDR] = &mideleg.reg; register_mapping[MIE_ADDR] = &mie.reg; register_mapping[MTVEC_ADDR] = &mtvec.reg; register_mapping[MCOUNTEREN_ADDR] = &mcounteren.reg; register_mapping[MCOUNTINHIBIT_ADDR] = &mcountinhibit.reg; register_mapping[MSCRATCH_ADDR] = &mscratch.reg; register_mapping[MEPC_ADDR] = &mepc.reg; register_mapping[MCAUSE_ADDR] = &mcause.reg; register_mapping[MTVAL_ADDR] = &mtval.reg; register_mapping[MIP_ADDR] = &mip.reg; for (unsigned i = 0; i < 16; ++i) register_mapping[PMPADDR0_ADDR + i] = &pmpaddr[i].reg; for (unsigned i = 0; i < 4; ++i) register_mapping[PMPCFG0_ADDR + i] = &pmpcfg[i].reg; register_mapping[SEDELEG_ADDR] = &sedeleg.reg; register_mapping[SIDELEG_ADDR] = &sideleg.reg; register_mapping[STVEC_ADDR] = &stvec.reg; register_mapping[SCOUNTEREN_ADDR] = &scounteren.reg; register_mapping[SSCRATCH_ADDR] = &sscratch.reg; register_mapping[SEPC_ADDR] = &sepc.reg; register_mapping[SCAUSE_ADDR] = &scause.reg; register_mapping[STVAL_ADDR] = &stval.reg; register_mapping[SATP_ADDR] = &satp.reg; register_mapping[UTVEC_ADDR] = &utvec.reg; register_mapping[USCRATCH_ADDR] = &uscratch.reg; register_mapping[UEPC_ADDR] = &uepc.reg; register_mapping[UCAUSE_ADDR] = &ucause.reg; register_mapping[UTVAL_ADDR] = &utval.reg; register_mapping[FCSR_ADDR] = &fcsr.reg; } bool is_valid_csr32_addr(unsigned addr) { return register_mapping.find(addr) != register_mapping.end(); } void default_write32(unsigned addr, uint32_t value) { auto it = register_mapping.find(addr); ensure((it != register_mapping.end()) && "validate address before calling this function"); *it->second = value; } uint32_t default_read32(unsigned addr) { auto it = register_mapping.find(addr); ensure((it != register_mapping.end()) && "validate address before calling this function"); return *it->second; } }; #define SWITCH_CASE_MATCH_ANY_HPMCOUNTER_RV32 \ case HPMCOUNTER3_ADDR: \ case HPMCOUNTER4_ADDR: \ case HPMCOUNTER5_ADDR: \ case HPMCOUNTER6_ADDR: \ case HPMCOUNTER7_ADDR: \ case HPMCOUNTER8_ADDR: \ case HPMCOUNTER9_ADDR: \ case HPMCOUNTER10_ADDR: \ case HPMCOUNTER11_ADDR: \ case HPMCOUNTER12_ADDR: \ case HPMCOUNTER13_ADDR: \ case HPMCOUNTER14_ADDR: \ case HPMCOUNTER15_ADDR: \ case HPMCOUNTER16_ADDR: \ case HPMCOUNTER17_ADDR: \ case HPMCOUNTER18_ADDR: \ case HPMCOUNTER19_ADDR: \ case HPMCOUNTER20_ADDR: \ case HPMCOUNTER21_ADDR: \ case HPMCOUNTER22_ADDR: \ case HPMCOUNTER23_ADDR: \ case HPMCOUNTER24_ADDR: \ case HPMCOUNTER25_ADDR: \ case HPMCOUNTER26_ADDR: \ case HPMCOUNTER27_ADDR: \ case HPMCOUNTER28_ADDR: \ case HPMCOUNTER29_ADDR: \ case HPMCOUNTER30_ADDR: \ case HPMCOUNTER31_ADDR: \ case HPMCOUNTER3H_ADDR: \ case HPMCOUNTER4H_ADDR: \ case HPMCOUNTER5H_ADDR: \ case HPMCOUNTER6H_ADDR: \ case HPMCOUNTER7H_ADDR: \ case HPMCOUNTER8H_ADDR: \ case HPMCOUNTER9H_ADDR: \ case HPMCOUNTER10H_ADDR: \ case HPMCOUNTER11H_ADDR: \ case HPMCOUNTER12H_ADDR: \ case HPMCOUNTER13H_ADDR: \ case HPMCOUNTER14H_ADDR: \ case HPMCOUNTER15H_ADDR: \ case HPMCOUNTER16H_ADDR: \ case HPMCOUNTER17H_ADDR: \ case HPMCOUNTER18H_ADDR: \ case HPMCOUNTER19H_ADDR: \ case HPMCOUNTER20H_ADDR: \ case HPMCOUNTER21H_ADDR: \ case HPMCOUNTER22H_ADDR: \ case HPMCOUNTER23H_ADDR: \ case HPMCOUNTER24H_ADDR: \ case HPMCOUNTER25H_ADDR: \ case HPMCOUNTER26H_ADDR: \ case HPMCOUNTER27H_ADDR: \ case HPMCOUNTER28H_ADDR: \ case HPMCOUNTER29H_ADDR: \ case HPMCOUNTER30H_ADDR: \ case HPMCOUNTER31H_ADDR: \ case MHPMCOUNTER3_ADDR: \ case MHPMCOUNTER4_ADDR: \ case MHPMCOUNTER5_ADDR: \ case MHPMCOUNTER6_ADDR: \ case MHPMCOUNTER7_ADDR: \ case MHPMCOUNTER8_ADDR: \ case MHPMCOUNTER9_ADDR: \ case MHPMCOUNTER10_ADDR: \ case MHPMCOUNTER11_ADDR: \ case MHPMCOUNTER12_ADDR: \ case MHPMCOUNTER13_ADDR: \ case MHPMCOUNTER14_ADDR: \ case MHPMCOUNTER15_ADDR: \ case MHPMCOUNTER16_ADDR: \ case MHPMCOUNTER17_ADDR: \ case MHPMCOUNTER18_ADDR: \ case MHPMCOUNTER19_ADDR: \ case MHPMCOUNTER20_ADDR: \ case MHPMCOUNTER21_ADDR: \ case MHPMCOUNTER22_ADDR: \ case MHPMCOUNTER23_ADDR: \ case MHPMCOUNTER24_ADDR: \ case MHPMCOUNTER25_ADDR: \ case MHPMCOUNTER26_ADDR: \ case MHPMCOUNTER27_ADDR: \ case MHPMCOUNTER28_ADDR: \ case MHPMCOUNTER29_ADDR: \ case MHPMCOUNTER30_ADDR: \ case MHPMCOUNTER31_ADDR: \ case MHPMCOUNTER3H_ADDR: \ case MHPMCOUNTER4H_ADDR: \ case MHPMCOUNTER5H_ADDR: \ case MHPMCOUNTER6H_ADDR: \ case MHPMCOUNTER7H_ADDR: \ case MHPMCOUNTER8H_ADDR: \ case MHPMCOUNTER9H_ADDR: \ case MHPMCOUNTER10H_ADDR: \ case MHPMCOUNTER11H_ADDR: \ case MHPMCOUNTER12H_ADDR: \ case MHPMCOUNTER13H_ADDR: \ case MHPMCOUNTER14H_ADDR: \ case MHPMCOUNTER15H_ADDR: \ case MHPMCOUNTER16H_ADDR: \ case MHPMCOUNTER17H_ADDR: \ case MHPMCOUNTER18H_ADDR: \ case MHPMCOUNTER19H_ADDR: \ case MHPMCOUNTER20H_ADDR: \ case MHPMCOUNTER21H_ADDR: \ case MHPMCOUNTER22H_ADDR: \ case MHPMCOUNTER23H_ADDR: \ case MHPMCOUNTER24H_ADDR: \ case MHPMCOUNTER25H_ADDR: \ case MHPMCOUNTER26H_ADDR: \ case MHPMCOUNTER27H_ADDR: \ case MHPMCOUNTER28H_ADDR: \ case MHPMCOUNTER29H_ADDR: \ case MHPMCOUNTER30H_ADDR: \ case MHPMCOUNTER31H_ADDR: \ case MHPMEVENT3_ADDR: \ case MHPMEVENT4_ADDR: \ case MHPMEVENT5_ADDR: \ case MHPMEVENT6_ADDR: \ case MHPMEVENT7_ADDR: \ case MHPMEVENT8_ADDR: \ case MHPMEVENT9_ADDR: \ case MHPMEVENT10_ADDR: \ case MHPMEVENT11_ADDR: \ case MHPMEVENT12_ADDR: \ case MHPMEVENT13_ADDR: \ case MHPMEVENT14_ADDR: \ case MHPMEVENT15_ADDR: \ case MHPMEVENT16_ADDR: \ case MHPMEVENT17_ADDR: \ case MHPMEVENT18_ADDR: \ case MHPMEVENT19_ADDR: \ case MHPMEVENT20_ADDR: \ case MHPMEVENT21_ADDR: \ case MHPMEVENT22_ADDR: \ case MHPMEVENT23_ADDR: \ case MHPMEVENT24_ADDR: \ case MHPMEVENT25_ADDR: \ case MHPMEVENT26_ADDR: \ case MHPMEVENT27_ADDR: \ case MHPMEVENT28_ADDR: \ case MHPMEVENT29_ADDR: \ case MHPMEVENT30_ADDR: \ case MHPMEVENT31_ADDR } // namespace rv32 ================================================ FILE: vp/src/core/rv32/elf_loader.h ================================================ #pragma once #include "core/common/elf_loader.h" namespace rv32 { // see: http://wiki.osdev.org/ELF_Tutorial for ELF definitions typedef uint16_t Elf32_Half; // Unsigned half int typedef uint32_t Elf32_Off; // Unsigned offset typedef uint32_t Elf32_Addr; // Unsigned address typedef uint32_t Elf32_Word; // Unsigned int typedef int32_t Elf32_Sword; // Signed int constexpr unsigned ELF_NIDENT = 16; typedef struct { uint8_t e_ident[ELF_NIDENT]; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx; } Elf32_Ehdr; typedef struct { Elf32_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; Elf32_Word p_filesz; Elf32_Word p_memsz; Elf32_Word p_flags; Elf32_Word p_align; } Elf32_Phdr; typedef struct { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; } Elf32_Shdr; typedef struct { Elf32_Word st_name; Elf32_Addr st_value; Elf32_Word st_size; unsigned char st_info; unsigned char st_other; Elf32_Half st_shndx; } Elf32_Sym; enum Elf32_PhdrType { PT_NULL = 0, PT_LOAD = 1, PT_DYNAMIC = 2, PT_INTERP = 3, PT_NOTE = 4, PT_SHLIB = 5, PT_PHDR = 6 }; struct Elf32Types { typedef uint32_t addr_t; typedef Elf32_Ehdr Elf_Ehdr; typedef Elf32_Phdr Elf_Phdr; typedef Elf32_Shdr Elf_Shdr; typedef Elf32_Sym Elf_Sym; static constexpr unsigned PT_LOAD = Elf32_PhdrType::PT_LOAD; }; typedef GenericElfLoader ELFLoader; } // namespace rv32 ================================================ FILE: vp/src/core/rv32/iss.cpp ================================================ #include "iss.h" // to save *cout* format setting, see *ISS::show* #include // for safe down-cast #include using namespace rv32; #define RAISE_ILLEGAL_INSTRUCTION() raise_trap(EXC_ILLEGAL_INSTR, instr.data()); #define REQUIRE_ISA(X) \ if (!(csrs.misa.reg & X)) \ RAISE_ILLEGAL_INSTRUCTION() #define RD instr.rd() #define RS1 instr.rs1() #define RS2 instr.rs2() #define RS3 instr.rs3() const char *regnames[] = { "zero (x0)", "ra (x1)", "sp (x2)", "gp (x3)", "tp (x4)", "t0 (x5)", "t1 (x6)", "t2 (x7)", "s0/fp(x8)", "s1 (x9)", "a0 (x10)", "a1 (x11)", "a2 (x12)", "a3 (x13)", "a4 (x14)", "a5 (x15)", "a6 (x16)", "a7 (x17)", "s2 (x18)", "s3 (x19)", "s4 (x20)", "s5 (x21)", "s6 (x22)", "s7 (x23)", "s8 (x24)", "s9 (x25)", "s10 (x26)", "s11 (x27)", "t3 (x28)", "t4 (x29)", "t5 (x30)", "t6 (x31)", }; int regcolors[] = { #if defined(COLOR_THEME_DARK) 0, 1, 2, 3, 4, 5, 6, 52, 8, 9, 53, 54, 55, 56, 57, 58, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, #elif defined(COLOR_THEME_LIGHT) 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 153, 154, 155, 156, 157, 158, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, #else 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, #endif }; RegFile::RegFile() { memset(regs, 0, sizeof(regs)); } RegFile::RegFile(const RegFile &other) { memcpy(regs, other.regs, sizeof(regs)); } void RegFile::write(uint32_t index, int32_t value) { assert(index <= x31); assert(index != x0); regs[index] = value; } int32_t RegFile::read(uint32_t index) { if (index > x31) throw std::out_of_range("out-of-range register access"); return regs[index]; } uint32_t RegFile::shamt(uint32_t index) { assert(index <= x31); return BIT_RANGE(regs[index], 4, 0); } int32_t &RegFile::operator[](const uint32_t idx) { return regs[idx]; } #if defined(COLOR_THEME_LIGHT) || defined(COLOR_THEME_DARK) #define COLORFRMT "\e[38;5;%um%s\e[39m" #define COLORPRINT(fmt, data) fmt, data #else #define COLORFRMT "%s" #define COLORPRINT(fmt, data) data #endif void RegFile::show() { for (unsigned i = 0; i < NUM_REGS; ++i) { printf(COLORFRMT " = %8x\n", COLORPRINT(regcolors[i], regnames[i]), regs[i]); } } ISS::ISS(uint32_t hart_id, bool use_E_base_isa) : systemc_name("Core-" + std::to_string(hart_id)) { csrs.mhartid.reg = hart_id; if (use_E_base_isa) csrs.misa.select_E_base_isa(); sc_core::sc_time qt = tlm::tlm_global_quantum::instance().get(); cycle_time = sc_core::sc_time(10, sc_core::SC_NS); assert(qt >= cycle_time); assert(qt % cycle_time == sc_core::SC_ZERO_TIME); for (int i = 0; i < Opcode::NUMBER_OF_INSTRUCTIONS; ++i) instr_cycles[i] = cycle_time; const sc_core::sc_time memory_access_cycles = 4 * cycle_time; const sc_core::sc_time mul_div_cycles = 8 * cycle_time; instr_cycles[Opcode::LB] = memory_access_cycles; instr_cycles[Opcode::LBU] = memory_access_cycles; instr_cycles[Opcode::LH] = memory_access_cycles; instr_cycles[Opcode::LHU] = memory_access_cycles; instr_cycles[Opcode::LW] = memory_access_cycles; instr_cycles[Opcode::SB] = memory_access_cycles; instr_cycles[Opcode::SH] = memory_access_cycles; instr_cycles[Opcode::SW] = memory_access_cycles; instr_cycles[Opcode::MUL] = mul_div_cycles; instr_cycles[Opcode::MULH] = mul_div_cycles; instr_cycles[Opcode::MULHU] = mul_div_cycles; instr_cycles[Opcode::MULHSU] = mul_div_cycles; instr_cycles[Opcode::DIV] = mul_div_cycles; instr_cycles[Opcode::DIVU] = mul_div_cycles; instr_cycles[Opcode::REM] = mul_div_cycles; instr_cycles[Opcode::REMU] = mul_div_cycles; op = Opcode::UNDEF; } void ISS::exec_step() { assert(((pc & ~pc_alignment_mask()) == 0) && "misaligned instruction"); try { uint32_t mem_word = instr_mem->load_instr(pc); instr = Instruction(mem_word); } catch (SimulationTrap &e) { op = Opcode::UNDEF; instr = Instruction(0); throw; } if (instr.is_compressed()) { op = instr.decode_and_expand_compressed(RV32); pc += 2; if (op != Opcode::UNDEF) REQUIRE_ISA(C_ISA_EXT); } else { op = instr.decode_normal(RV32); pc += 4; } if (trace) { printf("core %2u: prv %1x: pc %8x: %s ", csrs.mhartid.reg, prv, last_pc, Opcode::mappingStr[op]); switch (Opcode::getType(op)) { case Opcode::Type::R: printf(COLORFRMT ", " COLORFRMT ", " COLORFRMT, COLORPRINT(regcolors[instr.rd()], regnames[instr.rd()]), COLORPRINT(regcolors[instr.rs1()], regnames[instr.rs1()]), COLORPRINT(regcolors[instr.rs2()], regnames[instr.rs2()])); break; case Opcode::Type::I: printf(COLORFRMT ", " COLORFRMT ", 0x%x", COLORPRINT(regcolors[instr.rd()], regnames[instr.rd()]), COLORPRINT(regcolors[instr.rs1()], regnames[instr.rs1()]), instr.I_imm()); break; case Opcode::Type::S: printf(COLORFRMT ", " COLORFRMT ", 0x%x", COLORPRINT(regcolors[instr.rs1()], regnames[instr.rs1()]), COLORPRINT(regcolors[instr.rs2()], regnames[instr.rs2()]), instr.S_imm()); break; case Opcode::Type::B: printf(COLORFRMT ", " COLORFRMT ", 0x%x", COLORPRINT(regcolors[instr.rs1()], regnames[instr.rs1()]), COLORPRINT(regcolors[instr.rs2()], regnames[instr.rs2()]), instr.B_imm()); break; case Opcode::Type::U: printf(COLORFRMT ", 0x%x", COLORPRINT(regcolors[instr.rd()], regnames[instr.rd()]), instr.U_imm()); break; case Opcode::Type::J: printf(COLORFRMT ", 0x%x", COLORPRINT(regcolors[instr.rd()], regnames[instr.rd()]), instr.J_imm()); break; default:; } puts(""); } switch (op) { case Opcode::UNDEF: if (trace) std::cout << "[ISS] WARNING: unknown instruction '" << std::to_string(instr.data()) << "' at address '" << std::to_string(last_pc) << "'" << std::endl; raise_trap(EXC_ILLEGAL_INSTR, instr.data()); break; case Opcode::ADDI: regs[instr.rd()] = regs[instr.rs1()] + instr.I_imm(); break; case Opcode::SLTI: regs[instr.rd()] = regs[instr.rs1()] < instr.I_imm(); break; case Opcode::SLTIU: regs[instr.rd()] = ((uint32_t)regs[instr.rs1()]) < ((uint32_t)instr.I_imm()); break; case Opcode::XORI: regs[instr.rd()] = regs[instr.rs1()] ^ instr.I_imm(); break; case Opcode::ORI: regs[instr.rd()] = regs[instr.rs1()] | instr.I_imm(); break; case Opcode::ANDI: regs[instr.rd()] = regs[instr.rs1()] & instr.I_imm(); break; case Opcode::ADD: regs[instr.rd()] = regs[instr.rs1()] + regs[instr.rs2()]; break; case Opcode::SUB: regs[instr.rd()] = regs[instr.rs1()] - regs[instr.rs2()]; break; case Opcode::SLL: regs[instr.rd()] = regs[instr.rs1()] << regs.shamt(instr.rs2()); break; case Opcode::SLT: regs[instr.rd()] = regs[instr.rs1()] < regs[instr.rs2()]; break; case Opcode::SLTU: regs[instr.rd()] = ((uint32_t)regs[instr.rs1()]) < ((uint32_t)regs[instr.rs2()]); break; case Opcode::SRL: regs[instr.rd()] = ((uint32_t)regs[instr.rs1()]) >> regs.shamt(instr.rs2()); break; case Opcode::SRA: regs[instr.rd()] = regs[instr.rs1()] >> regs.shamt(instr.rs2()); break; case Opcode::XOR: regs[instr.rd()] = regs[instr.rs1()] ^ regs[instr.rs2()]; break; case Opcode::OR: regs[instr.rd()] = regs[instr.rs1()] | regs[instr.rs2()]; break; case Opcode::AND: regs[instr.rd()] = regs[instr.rs1()] & regs[instr.rs2()]; break; case Opcode::SLLI: regs[instr.rd()] = regs[instr.rs1()] << instr.shamt(); break; case Opcode::SRLI: regs[instr.rd()] = ((uint32_t)regs[instr.rs1()]) >> instr.shamt(); break; case Opcode::SRAI: regs[instr.rd()] = regs[instr.rs1()] >> instr.shamt(); break; case Opcode::LUI: regs[instr.rd()] = instr.U_imm(); break; case Opcode::AUIPC: regs[instr.rd()] = last_pc + instr.U_imm(); break; case Opcode::JAL: { auto link = pc; pc = last_pc + instr.J_imm(); trap_check_pc_alignment(); regs[instr.rd()] = link; } break; case Opcode::JALR: { auto link = pc; pc = (regs[instr.rs1()] + instr.I_imm()) & ~1; trap_check_pc_alignment(); regs[instr.rd()] = link; } break; case Opcode::SB: { uint32_t addr = regs[instr.rs1()] + instr.S_imm(); mem->store_byte(addr, regs[instr.rs2()]); } break; case Opcode::SH: { uint32_t addr = regs[instr.rs1()] + instr.S_imm(); trap_check_addr_alignment<2, false>(addr); mem->store_half(addr, regs[instr.rs2()]); } break; case Opcode::SW: { uint32_t addr = regs[instr.rs1()] + instr.S_imm(); trap_check_addr_alignment<4, false>(addr); mem->store_word(addr, regs[instr.rs2()]); } break; case Opcode::LB: { uint32_t addr = regs[instr.rs1()] + instr.I_imm(); regs[instr.rd()] = mem->load_byte(addr); } break; case Opcode::LH: { uint32_t addr = regs[instr.rs1()] + instr.I_imm(); trap_check_addr_alignment<2, true>(addr); regs[instr.rd()] = mem->load_half(addr); } break; case Opcode::LW: { uint32_t addr = regs[instr.rs1()] + instr.I_imm(); trap_check_addr_alignment<4, true>(addr); regs[instr.rd()] = mem->load_word(addr); } break; case Opcode::LBU: { uint32_t addr = regs[instr.rs1()] + instr.I_imm(); regs[instr.rd()] = mem->load_ubyte(addr); } break; case Opcode::LHU: { uint32_t addr = regs[instr.rs1()] + instr.I_imm(); trap_check_addr_alignment<2, true>(addr); regs[instr.rd()] = mem->load_uhalf(addr); } break; case Opcode::BEQ: if (regs[instr.rs1()] == regs[instr.rs2()]) { pc = last_pc + instr.B_imm(); trap_check_pc_alignment(); } break; case Opcode::BNE: if (regs[instr.rs1()] != regs[instr.rs2()]) { pc = last_pc + instr.B_imm(); trap_check_pc_alignment(); } break; case Opcode::BLT: if (regs[instr.rs1()] < regs[instr.rs2()]) { pc = last_pc + instr.B_imm(); trap_check_pc_alignment(); } break; case Opcode::BGE: if (regs[instr.rs1()] >= regs[instr.rs2()]) { pc = last_pc + instr.B_imm(); trap_check_pc_alignment(); } break; case Opcode::BLTU: if ((uint32_t)regs[instr.rs1()] < (uint32_t)regs[instr.rs2()]) { pc = last_pc + instr.B_imm(); trap_check_pc_alignment(); } break; case Opcode::BGEU: if ((uint32_t)regs[instr.rs1()] >= (uint32_t)regs[instr.rs2()]) { pc = last_pc + instr.B_imm(); trap_check_pc_alignment(); } break; case Opcode::FENCE: case Opcode::FENCE_I: { // not using out of order execution so can be ignored } break; case Opcode::ECALL: { if (sys) { sys->execute_syscall(this); } else { switch (prv) { case MachineMode: raise_trap(EXC_ECALL_M_MODE, last_pc); break; case SupervisorMode: raise_trap(EXC_ECALL_S_MODE, last_pc); break; case UserMode: raise_trap(EXC_ECALL_U_MODE, last_pc); break; default: throw std::runtime_error("unknown privilege level " + std::to_string(prv)); } } } break; case Opcode::EBREAK: { // TODO: also raise trap and let the SW deal with it? status = CoreExecStatus::HitBreakpoint; } break; case Opcode::CSRRW: { auto addr = instr.csr(); if (is_invalid_csr_access(addr, true)) { RAISE_ILLEGAL_INSTRUCTION(); } else { auto rd = instr.rd(); auto rs1_val = regs[instr.rs1()]; if (rd != RegFile::zero) { regs[instr.rd()] = get_csr_value(addr); } set_csr_value(addr, rs1_val); } } break; case Opcode::CSRRS: { auto addr = instr.csr(); auto rs1 = instr.rs1(); auto write = rs1 != RegFile::zero; if (is_invalid_csr_access(addr, write)) { RAISE_ILLEGAL_INSTRUCTION(); } else { auto rd = instr.rd(); auto rs1_val = regs[rs1]; auto csr_val = get_csr_value(addr); if (rd != RegFile::zero) regs[rd] = csr_val; if (write) set_csr_value(addr, csr_val | rs1_val); } } break; case Opcode::CSRRC: { auto addr = instr.csr(); auto rs1 = instr.rs1(); auto write = rs1 != RegFile::zero; if (is_invalid_csr_access(addr, write)) { RAISE_ILLEGAL_INSTRUCTION(); } else { auto rd = instr.rd(); auto rs1_val = regs[rs1]; auto csr_val = get_csr_value(addr); if (rd != RegFile::zero) regs[rd] = csr_val; if (write) set_csr_value(addr, csr_val & ~rs1_val); } } break; case Opcode::CSRRWI: { auto addr = instr.csr(); if (is_invalid_csr_access(addr, true)) { RAISE_ILLEGAL_INSTRUCTION(); } else { auto rd = instr.rd(); if (rd != RegFile::zero) { regs[rd] = get_csr_value(addr); } set_csr_value(addr, instr.zimm()); } } break; case Opcode::CSRRSI: { auto addr = instr.csr(); auto zimm = instr.zimm(); auto write = zimm != 0; if (is_invalid_csr_access(addr, write)) { RAISE_ILLEGAL_INSTRUCTION(); } else { auto csr_val = get_csr_value(addr); auto rd = instr.rd(); if (rd != RegFile::zero) regs[rd] = csr_val; if (write) set_csr_value(addr, csr_val | zimm); } } break; case Opcode::CSRRCI: { auto addr = instr.csr(); auto zimm = instr.zimm(); auto write = zimm != 0; if (is_invalid_csr_access(addr, write)) { RAISE_ILLEGAL_INSTRUCTION(); } else { auto csr_val = get_csr_value(addr); auto rd = instr.rd(); if (rd != RegFile::zero) regs[rd] = csr_val; if (write) set_csr_value(addr, csr_val & ~zimm); } } break; case Opcode::MUL: { REQUIRE_ISA(M_ISA_EXT); int64_t ans = (int64_t)regs[instr.rs1()] * (int64_t)regs[instr.rs2()]; regs[instr.rd()] = ans & 0xFFFFFFFF; } break; case Opcode::MULH: { REQUIRE_ISA(M_ISA_EXT); int64_t ans = (int64_t)regs[instr.rs1()] * (int64_t)regs[instr.rs2()]; regs[instr.rd()] = (ans & 0xFFFFFFFF00000000) >> 32; } break; case Opcode::MULHU: { REQUIRE_ISA(M_ISA_EXT); int64_t ans = ((uint64_t)(uint32_t)regs[instr.rs1()]) * (uint64_t)((uint32_t)regs[instr.rs2()]); regs[instr.rd()] = (ans & 0xFFFFFFFF00000000) >> 32; } break; case Opcode::MULHSU: { REQUIRE_ISA(M_ISA_EXT); int64_t ans = (int64_t)regs[instr.rs1()] * (uint64_t)((uint32_t)regs[instr.rs2()]); regs[instr.rd()] = (ans & 0xFFFFFFFF00000000) >> 32; } break; case Opcode::DIV: { REQUIRE_ISA(M_ISA_EXT); auto a = regs[instr.rs1()]; auto b = regs[instr.rs2()]; if (b == 0) { regs[instr.rd()] = -1; } else if (a == REG_MIN && b == -1) { regs[instr.rd()] = a; } else { regs[instr.rd()] = a / b; } } break; case Opcode::DIVU: { REQUIRE_ISA(M_ISA_EXT); auto a = regs[instr.rs1()]; auto b = regs[instr.rs2()]; if (b == 0) { regs[instr.rd()] = -1; } else { regs[instr.rd()] = (uint32_t)a / (uint32_t)b; } } break; case Opcode::REM: { REQUIRE_ISA(M_ISA_EXT); auto a = regs[instr.rs1()]; auto b = regs[instr.rs2()]; if (b == 0) { regs[instr.rd()] = a; } else if (a == REG_MIN && b == -1) { regs[instr.rd()] = 0; } else { regs[instr.rd()] = a % b; } } break; case Opcode::REMU: { REQUIRE_ISA(M_ISA_EXT); auto a = regs[instr.rs1()]; auto b = regs[instr.rs2()]; if (b == 0) { regs[instr.rd()] = a; } else { regs[instr.rd()] = (uint32_t)a % (uint32_t)b; } } break; case Opcode::LR_W: { REQUIRE_ISA(A_ISA_EXT); uint32_t addr = regs[instr.rs1()]; trap_check_addr_alignment<4, true>(addr); regs[instr.rd()] = mem->atomic_load_reserved_word(addr); if (lr_sc_counter == 0) lr_sc_counter = 17; // this instruction + 16 additional ones, (an over-approximation) to cover the RISC-V forward progress property } break; case Opcode::SC_W: { REQUIRE_ISA(A_ISA_EXT); uint32_t addr = regs[instr.rs1()]; trap_check_addr_alignment<4, false>(addr); uint32_t val = regs[instr.rs2()]; regs[instr.rd()] = 1; // failure by default (in case a trap is thrown) regs[instr.rd()] = mem->atomic_store_conditional_word(addr, val) ? 0 : 1; // overwrite result (in case no trap is thrown) lr_sc_counter = 0; } break; case Opcode::AMOSWAP_W: { REQUIRE_ISA(A_ISA_EXT); execute_amo(instr, [](int32_t a, int32_t b) { (void)a; return b; }); } break; case Opcode::AMOADD_W: { REQUIRE_ISA(A_ISA_EXT); execute_amo(instr, [](int32_t a, int32_t b) { return a + b; }); } break; case Opcode::AMOXOR_W: { REQUIRE_ISA(A_ISA_EXT); execute_amo(instr, [](int32_t a, int32_t b) { return a ^ b; }); } break; case Opcode::AMOAND_W: { REQUIRE_ISA(A_ISA_EXT); execute_amo(instr, [](int32_t a, int32_t b) { return a & b; }); } break; case Opcode::AMOOR_W: { REQUIRE_ISA(A_ISA_EXT); execute_amo(instr, [](int32_t a, int32_t b) { return a | b; }); } break; case Opcode::AMOMIN_W: { REQUIRE_ISA(A_ISA_EXT); execute_amo(instr, [](int32_t a, int32_t b) { return std::min(a, b); }); } break; case Opcode::AMOMINU_W: { REQUIRE_ISA(A_ISA_EXT); execute_amo(instr, [](int32_t a, int32_t b) { return std::min((uint32_t)a, (uint32_t)b); }); } break; case Opcode::AMOMAX_W: { REQUIRE_ISA(A_ISA_EXT); execute_amo(instr, [](int32_t a, int32_t b) { return std::max(a, b); }); } break; case Opcode::AMOMAXU_W: { REQUIRE_ISA(A_ISA_EXT); execute_amo(instr, [](int32_t a, int32_t b) { return std::max((uint32_t)a, (uint32_t)b); }); } break; // RV32F Extension case Opcode::FLW: { REQUIRE_ISA(F_ISA_EXT); uint32_t addr = regs[instr.rs1()] + instr.I_imm(); trap_check_addr_alignment<4, true>(addr); fp_regs.write(RD, float32_t{(uint32_t)mem->load_word(addr)}); } break; case Opcode::FSW: { REQUIRE_ISA(F_ISA_EXT); uint32_t addr = regs[instr.rs1()] + instr.S_imm(); trap_check_addr_alignment<4, false>(addr); mem->store_word(addr, fp_regs.u32(RS2)); } break; case Opcode::FADD_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_add(fp_regs.f32(RS1), fp_regs.f32(RS2))); fp_finish_instr(); } break; case Opcode::FSUB_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_sub(fp_regs.f32(RS1), fp_regs.f32(RS2))); fp_finish_instr(); } break; case Opcode::FMUL_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_mul(fp_regs.f32(RS1), fp_regs.f32(RS2))); fp_finish_instr(); } break; case Opcode::FDIV_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_div(fp_regs.f32(RS1), fp_regs.f32(RS2))); fp_finish_instr(); } break; case Opcode::FSQRT_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_sqrt(fp_regs.f32(RS1))); fp_finish_instr(); } break; case Opcode::FMIN_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); bool rs1_smaller = f32_lt_quiet(fp_regs.f32(RS1), fp_regs.f32(RS2)) || (f32_eq(fp_regs.f32(RS1), fp_regs.f32(RS2)) && f32_isNegative(fp_regs.f32(RS1))); if (f32_isNaN(fp_regs.f32(RS1)) && f32_isNaN(fp_regs.f32(RS2))) { fp_regs.write(RD, f32_defaultNaN); } else { if (rs1_smaller) fp_regs.write(RD, fp_regs.f32(RS1)); else fp_regs.write(RD, fp_regs.f32(RS2)); } fp_finish_instr(); } break; case Opcode::FMAX_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); bool rs1_greater = f32_lt_quiet(fp_regs.f32(RS2), fp_regs.f32(RS1)) || (f32_eq(fp_regs.f32(RS2), fp_regs.f32(RS1)) && f32_isNegative(fp_regs.f32(RS2))); if (f32_isNaN(fp_regs.f32(RS1)) && f32_isNaN(fp_regs.f32(RS2))) { fp_regs.write(RD, f32_defaultNaN); } else { if (rs1_greater) fp_regs.write(RD, fp_regs.f32(RS1)); else fp_regs.write(RD, fp_regs.f32(RS2)); } fp_finish_instr(); } break; case Opcode::FMADD_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_mulAdd(fp_regs.f32(RS1), fp_regs.f32(RS2), fp_regs.f32(RS3))); fp_finish_instr(); } break; case Opcode::FMSUB_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_mulAdd(fp_regs.f32(RS1), fp_regs.f32(RS2), f32_neg(fp_regs.f32(RS3)))); fp_finish_instr(); } break; case Opcode::FNMADD_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_mulAdd(f32_neg(fp_regs.f32(RS1)), fp_regs.f32(RS2), f32_neg(fp_regs.f32(RS3)))); fp_finish_instr(); } break; case Opcode::FNMSUB_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_mulAdd(f32_neg(fp_regs.f32(RS1)), fp_regs.f32(RS2), fp_regs.f32(RS3))); fp_finish_instr(); } break; case Opcode::FCVT_W_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); regs[RD] = f32_to_i32(fp_regs.f32(RS1), softfloat_roundingMode, true); fp_finish_instr(); } break; case Opcode::FCVT_WU_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); regs[RD] = f32_to_ui32(fp_regs.f32(RS1), softfloat_roundingMode, true); fp_finish_instr(); } break; case Opcode::FCVT_S_W: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, i32_to_f32(regs[RS1])); fp_finish_instr(); } break; case Opcode::FCVT_S_WU: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, ui32_to_f32(regs[RS1])); fp_finish_instr(); } break; case Opcode::FSGNJ_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); auto f1 = fp_regs.f32(RS1); auto f2 = fp_regs.f32(RS2); fp_regs.write(RD, float32_t{(f1.v & ~F32_SIGN_BIT) | (f2.v & F32_SIGN_BIT)}); fp_set_dirty(); } break; case Opcode::FSGNJN_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); auto f1 = fp_regs.f32(RS1); auto f2 = fp_regs.f32(RS2); fp_regs.write(RD, float32_t{(f1.v & ~F32_SIGN_BIT) | (~f2.v & F32_SIGN_BIT)}); fp_set_dirty(); } break; case Opcode::FSGNJX_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); auto f1 = fp_regs.f32(RS1); auto f2 = fp_regs.f32(RS2); fp_regs.write(RD, float32_t{f1.v ^ (f2.v & F32_SIGN_BIT)}); fp_set_dirty(); } break; case Opcode::FMV_W_X: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); fp_regs.write(RD, float32_t{(uint32_t)regs[RS1]}); fp_set_dirty(); } break; case Opcode::FMV_X_W: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); regs[RD] = fp_regs.u32(RS1); } break; case Opcode::FEQ_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); regs[RD] = f32_eq(fp_regs.f32(RS1), fp_regs.f32(RS2)); fp_update_exception_flags(); } break; case Opcode::FLT_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); regs[RD] = f32_lt(fp_regs.f32(RS1), fp_regs.f32(RS2)); fp_update_exception_flags(); } break; case Opcode::FLE_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); regs[RD] = f32_le(fp_regs.f32(RS1), fp_regs.f32(RS2)); fp_update_exception_flags(); } break; case Opcode::FCLASS_S: { REQUIRE_ISA(F_ISA_EXT); fp_prepare_instr(); regs[RD] = f32_classify(fp_regs.f32(RS1)); } break; // RV32D Extension case Opcode::FLD: { REQUIRE_ISA(D_ISA_EXT); uint32_t addr = regs[instr.rs1()] + instr.I_imm(); trap_check_addr_alignment<8, true>(addr); fp_regs.write(RD, float64_t{(uint64_t)mem->load_double(addr)}); } break; case Opcode::FSD: { REQUIRE_ISA(D_ISA_EXT); uint32_t addr = regs[instr.rs1()] + instr.S_imm(); trap_check_addr_alignment<8, false>(addr); mem->store_double(addr, fp_regs.f64(RS2).v); } break; case Opcode::FADD_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_add(fp_regs.f64(RS1), fp_regs.f64(RS2))); fp_finish_instr(); } break; case Opcode::FSUB_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_sub(fp_regs.f64(RS1), fp_regs.f64(RS2))); fp_finish_instr(); } break; case Opcode::FMUL_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_mul(fp_regs.f64(RS1), fp_regs.f64(RS2))); fp_finish_instr(); } break; case Opcode::FDIV_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_div(fp_regs.f64(RS1), fp_regs.f64(RS2))); fp_finish_instr(); } break; case Opcode::FSQRT_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_sqrt(fp_regs.f64(RS1))); fp_finish_instr(); } break; case Opcode::FMIN_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); bool rs1_smaller = f64_lt_quiet(fp_regs.f64(RS1), fp_regs.f64(RS2)) || (f64_eq(fp_regs.f64(RS1), fp_regs.f64(RS2)) && f64_isNegative(fp_regs.f64(RS1))); if (f64_isNaN(fp_regs.f64(RS1)) && f64_isNaN(fp_regs.f64(RS2))) { fp_regs.write(RD, f64_defaultNaN); } else { if (rs1_smaller) fp_regs.write(RD, fp_regs.f64(RS1)); else fp_regs.write(RD, fp_regs.f64(RS2)); } fp_finish_instr(); } break; case Opcode::FMAX_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); bool rs1_greater = f64_lt_quiet(fp_regs.f64(RS2), fp_regs.f64(RS1)) || (f64_eq(fp_regs.f64(RS2), fp_regs.f64(RS1)) && f64_isNegative(fp_regs.f64(RS2))); if (f64_isNaN(fp_regs.f64(RS1)) && f64_isNaN(fp_regs.f64(RS2))) { fp_regs.write(RD, f64_defaultNaN); } else { if (rs1_greater) fp_regs.write(RD, fp_regs.f64(RS1)); else fp_regs.write(RD, fp_regs.f64(RS2)); } fp_finish_instr(); } break; case Opcode::FMADD_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_mulAdd(fp_regs.f64(RS1), fp_regs.f64(RS2), fp_regs.f64(RS3))); fp_finish_instr(); } break; case Opcode::FMSUB_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_mulAdd(fp_regs.f64(RS1), fp_regs.f64(RS2), f64_neg(fp_regs.f64(RS3)))); fp_finish_instr(); } break; case Opcode::FNMADD_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_mulAdd(f64_neg(fp_regs.f64(RS1)), fp_regs.f64(RS2), f64_neg(fp_regs.f64(RS3)))); fp_finish_instr(); } break; case Opcode::FNMSUB_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_mulAdd(f64_neg(fp_regs.f64(RS1)), fp_regs.f64(RS2), fp_regs.f64(RS3))); fp_finish_instr(); } break; case Opcode::FSGNJ_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); auto f1 = fp_regs.f64(RS1); auto f2 = fp_regs.f64(RS2); fp_regs.write(RD, float64_t{(f1.v & ~F64_SIGN_BIT) | (f2.v & F64_SIGN_BIT)}); fp_set_dirty(); } break; case Opcode::FSGNJN_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); auto f1 = fp_regs.f64(RS1); auto f2 = fp_regs.f64(RS2); fp_regs.write(RD, float64_t{(f1.v & ~F64_SIGN_BIT) | (~f2.v & F64_SIGN_BIT)}); fp_set_dirty(); } break; case Opcode::FSGNJX_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); auto f1 = fp_regs.f64(RS1); auto f2 = fp_regs.f64(RS2); fp_regs.write(RD, float64_t{f1.v ^ (f2.v & F64_SIGN_BIT)}); fp_set_dirty(); } break; case Opcode::FCVT_S_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_to_f32(fp_regs.f64(RS1))); fp_finish_instr(); } break; case Opcode::FCVT_D_S: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_to_f64(fp_regs.f32(RS1))); fp_finish_instr(); } break; case Opcode::FEQ_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); regs[RD] = f64_eq(fp_regs.f64(RS1), fp_regs.f64(RS2)); fp_update_exception_flags(); } break; case Opcode::FLT_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); regs[RD] = f64_lt(fp_regs.f64(RS1), fp_regs.f64(RS2)); fp_update_exception_flags(); } break; case Opcode::FLE_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); regs[RD] = f64_le(fp_regs.f64(RS1), fp_regs.f64(RS2)); fp_update_exception_flags(); } break; case Opcode::FCLASS_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); regs[RD] = (int64_t)f64_classify(fp_regs.f64(RS1)); } break; case Opcode::FCVT_W_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); regs[RD] = f64_to_i32(fp_regs.f64(RS1), softfloat_roundingMode, true); fp_finish_instr(); } break; case Opcode::FCVT_WU_D: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); regs[RD] = (int32_t)f64_to_ui32(fp_regs.f64(RS1), softfloat_roundingMode, true); fp_finish_instr(); } break; case Opcode::FCVT_D_W: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, i32_to_f64((int32_t)regs[RS1])); fp_finish_instr(); } break; case Opcode::FCVT_D_WU: { REQUIRE_ISA(D_ISA_EXT); fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, ui32_to_f64((int32_t)regs[RS1])); fp_finish_instr(); } break; // privileged instructions case Opcode::WFI: // NOTE: only a hint, can be implemented as NOP // std::cout << "[sim:wfi] CSR mstatus.mie " << csrs.mstatus->mie << std::endl; release_lr_sc_reservation(); if (s_mode() && csrs.mstatus.fields.tw) raise_trap(EXC_ILLEGAL_INSTR, instr.data()); if (u_mode() && csrs.misa.has_supervisor_mode_extension()) raise_trap(EXC_ILLEGAL_INSTR, instr.data()); if (!ignore_wfi && !has_local_pending_enabled_interrupts()) sc_core::wait(wfi_event); break; case Opcode::SFENCE_VMA: if (s_mode() && csrs.mstatus.fields.tvm) raise_trap(EXC_ILLEGAL_INSTR, instr.data()); mem->flush_tlb(); break; case Opcode::URET: if (!csrs.misa.has_user_mode_extension()) raise_trap(EXC_ILLEGAL_INSTR, instr.data()); return_from_trap_handler(UserMode); break; case Opcode::SRET: if (!csrs.misa.has_supervisor_mode_extension() || (s_mode() && csrs.mstatus.fields.tsr)) raise_trap(EXC_ILLEGAL_INSTR, instr.data()); return_from_trap_handler(SupervisorMode); break; case Opcode::MRET: return_from_trap_handler(MachineMode); break; // instructions accepted by decoder but not by this RV32IMACF ISS -> do normal trap // RV64I case Opcode::LWU: case Opcode::LD: case Opcode::SD: case Opcode::ADDIW: case Opcode::SLLIW: case Opcode::SRLIW: case Opcode::SRAIW: case Opcode::ADDW: case Opcode::SUBW: case Opcode::SLLW: case Opcode::SRLW: case Opcode::SRAW: // RV64M case Opcode::MULW: case Opcode::DIVW: case Opcode::DIVUW: case Opcode::REMW: case Opcode::REMUW: // RV64A case Opcode::LR_D: case Opcode::SC_D: case Opcode::AMOSWAP_D: case Opcode::AMOADD_D: case Opcode::AMOXOR_D: case Opcode::AMOAND_D: case Opcode::AMOOR_D: case Opcode::AMOMIN_D: case Opcode::AMOMAX_D: case Opcode::AMOMINU_D: case Opcode::AMOMAXU_D: // RV64F case Opcode::FCVT_L_S: case Opcode::FCVT_LU_S: case Opcode::FCVT_S_L: case Opcode::FCVT_S_LU: // RV64D case Opcode::FCVT_L_D: case Opcode::FCVT_LU_D: case Opcode::FMV_X_D: case Opcode::FCVT_D_L: case Opcode::FCVT_D_LU: case Opcode::FMV_D_X: RAISE_ILLEGAL_INSTRUCTION(); break; default: throw std::runtime_error("unknown opcode"); } } uint64_t ISS::_compute_and_get_current_cycles() { assert(cycle_counter % cycle_time == sc_core::SC_ZERO_TIME); assert(cycle_counter.value() % cycle_time.value() == 0); uint64_t num_cycles = cycle_counter.value() / cycle_time.value(); return num_cycles; } bool ISS::is_invalid_csr_access(uint32_t csr_addr, bool is_write) { if (csr_addr == csr::FFLAGS_ADDR || csr_addr == csr::FRM_ADDR || csr_addr == csr::FCSR_ADDR) { REQUIRE_ISA(F_ISA_EXT); } PrivilegeLevel csr_prv = (0x300 & csr_addr) >> 8; bool csr_readonly = ((0xC00 & csr_addr) >> 10) == 3; bool s_invalid = (csr_prv == SupervisorMode) && !csrs.misa.has_supervisor_mode_extension(); bool u_invalid = (csr_prv == UserMode) && !csrs.misa.has_user_mode_extension(); return (is_write && csr_readonly) || (prv < csr_prv) || s_invalid || u_invalid; } void ISS::validate_csr_counter_read_access_rights(uint32_t addr) { // match against counter CSR addresses, see RISC-V privileged spec for the address definitions if ((addr >= 0xC00 && addr <= 0xC1F) || (addr >= 0xC80 && addr <= 0xC9F)) { auto cnt = addr & 0x1F; // 32 counter in total, naturally aligned with the mcounteren and scounteren CSRs if (s_mode() && !csr::is_bitset(csrs.mcounteren, cnt)) RAISE_ILLEGAL_INSTRUCTION(); if (u_mode() && (!csr::is_bitset(csrs.mcounteren, cnt) || !csr::is_bitset(csrs.scounteren, cnt))) RAISE_ILLEGAL_INSTRUCTION(); } } uint32_t ISS::get_csr_value(uint32_t addr) { validate_csr_counter_read_access_rights(addr); auto read = [=](auto &x, uint32_t mask) { return x.reg & mask; }; using namespace csr; switch (addr) { case TIME_ADDR: case MTIME_ADDR: { uint64_t mtime = clint->update_and_get_mtime(); csrs.time.reg = mtime; return csrs.time.words.low; } case TIMEH_ADDR: case MTIMEH_ADDR: { uint64_t mtime = clint->update_and_get_mtime(); csrs.time.reg = mtime; return csrs.time.words.high; } case MCYCLE_ADDR: csrs.cycle.reg = _compute_and_get_current_cycles(); return csrs.cycle.words.low; case MCYCLEH_ADDR: csrs.cycle.reg = _compute_and_get_current_cycles(); return csrs.cycle.words.high; case MINSTRET_ADDR: return csrs.instret.words.low; case MINSTRETH_ADDR: return csrs.instret.words.high; SWITCH_CASE_MATCH_ANY_HPMCOUNTER_RV32: // not implemented return 0; case MSTATUS_ADDR: return read(csrs.mstatus, MSTATUS_MASK); case SSTATUS_ADDR: return read(csrs.mstatus, SSTATUS_MASK); case USTATUS_ADDR: return read(csrs.mstatus, USTATUS_MASK); case MIP_ADDR: return read(csrs.mip, MIP_READ_MASK); case SIP_ADDR: return read(csrs.mip, SIP_MASK); case UIP_ADDR: return read(csrs.mip, UIP_MASK); case MIE_ADDR: return read(csrs.mie, MIE_MASK); case SIE_ADDR: return read(csrs.mie, SIE_MASK); case UIE_ADDR: return read(csrs.mie, UIE_MASK); case SATP_ADDR: if (csrs.mstatus.fields.tvm) RAISE_ILLEGAL_INSTRUCTION(); break; case FCSR_ADDR: return read(csrs.fcsr, FCSR_MASK); case FFLAGS_ADDR: return csrs.fcsr.fields.fflags; case FRM_ADDR: return csrs.fcsr.fields.frm; // debug CSRs not supported, thus hardwired case TSELECT_ADDR: return 1; // if a zero write by SW is preserved, then debug mode is supported (thus hardwire to non-zero) case TDATA1_ADDR: case TDATA2_ADDR: case TDATA3_ADDR: case DCSR_ADDR: case DPC_ADDR: case DSCRATCH0_ADDR: case DSCRATCH1_ADDR: return 0; } if (!csrs.is_valid_csr32_addr(addr)) RAISE_ILLEGAL_INSTRUCTION(); return csrs.default_read32(addr); } void ISS::set_csr_value(uint32_t addr, uint32_t value) { auto write = [=](auto &x, uint32_t mask) { x.reg = (x.reg & ~mask) | (value & mask); }; using namespace csr; switch (addr) { case MISA_ADDR: // currently, read-only, thus cannot be changed at runtime SWITCH_CASE_MATCH_ANY_HPMCOUNTER_RV32: // not implemented break; case SATP_ADDR: { if (csrs.mstatus.fields.tvm) RAISE_ILLEGAL_INSTRUCTION(); write(csrs.satp, SATP_MASK); // std::cout << "[iss] satp=" << boost::format("%x") % csrs.satp.reg << std::endl; } break; case MTVEC_ADDR: write(csrs.mtvec, MTVEC_MASK); break; case STVEC_ADDR: write(csrs.stvec, MTVEC_MASK); break; case UTVEC_ADDR: write(csrs.utvec, MTVEC_MASK); break; case MEPC_ADDR: write(csrs.mepc, pc_alignment_mask()); break; case SEPC_ADDR: write(csrs.sepc, pc_alignment_mask()); break; case UEPC_ADDR: write(csrs.uepc, pc_alignment_mask()); break; case MSTATUS_ADDR: write(csrs.mstatus, MSTATUS_MASK); break; case SSTATUS_ADDR: write(csrs.mstatus, SSTATUS_MASK); break; case USTATUS_ADDR: write(csrs.mstatus, USTATUS_MASK); break; case MIP_ADDR: write(csrs.mip, MIP_WRITE_MASK); break; case SIP_ADDR: write(csrs.mip, SIP_MASK); break; case UIP_ADDR: write(csrs.mip, UIP_MASK); break; case MIE_ADDR: write(csrs.mie, MIE_MASK); break; case SIE_ADDR: write(csrs.mie, SIE_MASK); break; case UIE_ADDR: write(csrs.mie, UIE_MASK); break; case MIDELEG_ADDR: write(csrs.mideleg, MIDELEG_MASK); break; case MEDELEG_ADDR: write(csrs.medeleg, MEDELEG_MASK); break; case SIDELEG_ADDR: write(csrs.sideleg, SIDELEG_MASK); break; case SEDELEG_ADDR: write(csrs.sedeleg, SEDELEG_MASK); break; case MCOUNTEREN_ADDR: write(csrs.mcounteren, MCOUNTEREN_MASK); break; case SCOUNTEREN_ADDR: write(csrs.scounteren, MCOUNTEREN_MASK); break; case MCOUNTINHIBIT_ADDR: write(csrs.mcountinhibit, MCOUNTINHIBIT_MASK); break; case FCSR_ADDR: write(csrs.fcsr, FCSR_MASK); break; case FFLAGS_ADDR: csrs.fcsr.fields.fflags = value; break; case FRM_ADDR: csrs.fcsr.fields.frm = value; break; // debug CSRs not supported, thus hardwired case TSELECT_ADDR: case TDATA1_ADDR: case TDATA2_ADDR: case TDATA3_ADDR: case DCSR_ADDR: case DPC_ADDR: case DSCRATCH0_ADDR: case DSCRATCH1_ADDR: break; default: if (!csrs.is_valid_csr32_addr(addr)) RAISE_ILLEGAL_INSTRUCTION(); csrs.default_write32(addr, value); } } void ISS::init(instr_memory_if *instr_mem, data_memory_if *data_mem, clint_if *clint, uint32_t entrypoint, uint32_t sp) { this->instr_mem = instr_mem; this->mem = data_mem; this->clint = clint; regs[RegFile::sp] = sp; pc = entrypoint; } void ISS::sys_exit() { shall_exit = true; } unsigned ISS::get_syscall_register_index() { if (csrs.misa.has_E_base_isa()) return RegFile::a5; else return RegFile::a7; } uint64_t ISS::read_register(unsigned idx) { return (uint32_t)regs.read(idx); //NOTE: zero extend } void ISS::write_register(unsigned idx, uint64_t value) { // Since the value parameter in the function prototype is // a uint64_t, signed integer values (e.g. -1) get promoted // to values within this range. For example, -1 would be // promoted to (2**64)-1. As such, we cannot perform a // Boost lexical or numeric cast to uint32_t here as // these perform bounds checks. Instead, we perform a C // cast without bounds checks. regs.write(idx, (uint32_t)value); } uint64_t ISS::get_progam_counter(void) { return pc; } void ISS::block_on_wfi(bool block) { ignore_wfi = !block; } CoreExecStatus ISS::get_status(void) { return status; } void ISS::set_status(CoreExecStatus s) { status = s; } void ISS::enable_debug(void) { debug_mode = true; } void ISS::insert_breakpoint(uint64_t addr) { breakpoints.insert(addr); } void ISS::remove_breakpoint(uint64_t addr) { breakpoints.erase(addr); } uint64_t ISS::get_hart_id() { return csrs.mhartid.reg; } std::vector ISS::get_registers(void) { std::vector regvals; for (auto v : regs.regs) regvals.push_back((uint32_t)v); //NOTE: zero extend return regvals; } void ISS::fp_finish_instr() { fp_set_dirty(); fp_update_exception_flags(); } void ISS::fp_prepare_instr() { assert(softfloat_exceptionFlags == 0); fp_require_not_off(); } void ISS::fp_set_dirty() { csrs.mstatus.fields.sd = 1; csrs.mstatus.fields.fs = FS_DIRTY; } void ISS::fp_update_exception_flags() { if (softfloat_exceptionFlags) { fp_set_dirty(); csrs.fcsr.fields.fflags |= softfloat_exceptionFlags; softfloat_exceptionFlags = 0; } } void ISS::fp_setup_rm() { auto rm = instr.frm(); if (rm == FRM_DYN) rm = csrs.fcsr.fields.frm; if (rm >= FRM_RMM) RAISE_ILLEGAL_INSTRUCTION(); softfloat_roundingMode = rm; } void ISS::fp_require_not_off() { if (csrs.mstatus.fields.fs == FS_OFF) RAISE_ILLEGAL_INSTRUCTION(); } void ISS::return_from_trap_handler(PrivilegeLevel return_mode) { switch (return_mode) { case MachineMode: prv = csrs.mstatus.fields.mpp; csrs.mstatus.fields.mie = csrs.mstatus.fields.mpie; csrs.mstatus.fields.mpie = 1; pc = csrs.mepc.reg; if (csrs.misa.has_user_mode_extension()) csrs.mstatus.fields.mpp = UserMode; else csrs.mstatus.fields.mpp = MachineMode; break; case SupervisorMode: prv = csrs.mstatus.fields.spp; csrs.mstatus.fields.sie = csrs.mstatus.fields.spie; csrs.mstatus.fields.spie = 1; pc = csrs.sepc.reg; if (csrs.misa.has_user_mode_extension()) csrs.mstatus.fields.spp = UserMode; else csrs.mstatus.fields.spp = SupervisorMode; break; case UserMode: prv = UserMode; csrs.mstatus.fields.uie = csrs.mstatus.fields.upie; csrs.mstatus.fields.upie = 1; pc = csrs.uepc.reg; break; default: throw std::runtime_error("unknown privilege level " + std::to_string(return_mode)); } if (trace) printf("[vp::iss] return from trap handler, time %s, pc %8x, prv %1x\n", quantum_keeper.get_current_time().to_string().c_str(), pc, prv); } void ISS::trigger_external_interrupt(PrivilegeLevel level) { if (trace) std::cout << "[vp::iss] trigger external interrupt, " << sc_core::sc_time_stamp() << std::endl; switch (level) { case UserMode: csrs.mip.fields.ueip = true; break; case SupervisorMode: csrs.mip.fields.seip = true; break; case MachineMode: csrs.mip.fields.meip = true; break; } wfi_event.notify(sc_core::SC_ZERO_TIME); } void ISS::clear_external_interrupt(PrivilegeLevel level) { if (trace) std::cout << "[vp::iss] clear external interrupt, " << sc_core::sc_time_stamp() << std::endl; switch (level) { case UserMode: csrs.mip.fields.ueip = false; break; case SupervisorMode: csrs.mip.fields.seip = false; break; case MachineMode: csrs.mip.fields.meip = false; break; } } void ISS::trigger_timer_interrupt(bool status) { if (trace) std::cout << "[vp::iss] trigger timer interrupt=" << status << ", " << sc_core::sc_time_stamp() << std::endl; csrs.mip.fields.mtip = status; wfi_event.notify(sc_core::SC_ZERO_TIME); } void ISS::trigger_software_interrupt(bool status) { if (trace) std::cout << "[vp::iss] trigger software interrupt=" << status << ", " << sc_core::sc_time_stamp() << std::endl; csrs.mip.fields.msip = status; wfi_event.notify(sc_core::SC_ZERO_TIME); } PrivilegeLevel ISS::prepare_trap(SimulationTrap &e) { // undo any potential pc update (for traps the pc should point to the originating instruction and not it's // successor) pc = last_pc; unsigned exc_bit = (1 << e.reason); // 1) machine mode execution takes any traps, independent of delegation setting // 2) non-delegated traps are processed in machine mode, independent of current execution mode if (prv == MachineMode || !(exc_bit & csrs.medeleg.reg)) { csrs.mcause.fields.interrupt = 0; csrs.mcause.fields.exception_code = e.reason; csrs.mtval.reg = boost::lexical_cast(e.mtval); return MachineMode; } // see above machine mode comment if (prv == SupervisorMode || !(exc_bit & csrs.sedeleg.reg)) { csrs.scause.fields.interrupt = 0; csrs.scause.fields.exception_code = e.reason; csrs.stval.reg = boost::lexical_cast(e.mtval); return SupervisorMode; } assert(prv == UserMode && (exc_bit & csrs.medeleg.reg) && (exc_bit & csrs.sedeleg.reg)); csrs.ucause.fields.interrupt = 0; csrs.ucause.fields.exception_code = e.reason; csrs.utval.reg = boost::lexical_cast(e.mtval); return UserMode; } void ISS::prepare_interrupt(const PendingInterrupts &e) { if (trace) { std::cout << "[vp::iss] prepare interrupt, pending=" << e.pending << ", target-mode=" << e.target_mode << std::endl; } csr_mip x{e.pending}; ExceptionCode exc; if (x.fields.meip) exc = EXC_M_EXTERNAL_INTERRUPT; else if (x.fields.msip) exc = EXC_M_SOFTWARE_INTERRUPT; else if (x.fields.mtip) exc = EXC_M_TIMER_INTERRUPT; else if (x.fields.seip) exc = EXC_S_EXTERNAL_INTERRUPT; else if (x.fields.ssip) exc = EXC_S_SOFTWARE_INTERRUPT; else if (x.fields.stip) exc = EXC_S_TIMER_INTERRUPT; else if (x.fields.ueip) exc = EXC_U_EXTERNAL_INTERRUPT; else if (x.fields.usip) exc = EXC_U_SOFTWARE_INTERRUPT; else if (x.fields.utip) exc = EXC_U_TIMER_INTERRUPT; else throw std::runtime_error("some pending interrupt must be available here"); switch (e.target_mode) { case MachineMode: csrs.mcause.fields.exception_code = exc; csrs.mcause.fields.interrupt = 1; break; case SupervisorMode: csrs.scause.fields.exception_code = exc; csrs.scause.fields.interrupt = 1; break; case UserMode: csrs.ucause.fields.exception_code = exc; csrs.ucause.fields.interrupt = 1; break; default: throw std::runtime_error("unknown privilege level " + std::to_string(e.target_mode)); } } PendingInterrupts ISS::compute_pending_interrupts() { uint32_t pending = csrs.mie.reg & csrs.mip.reg; if (!pending) return {NoneMode, 0}; auto m_pending = pending & ~csrs.mideleg.reg; if (m_pending && (prv < MachineMode || (prv == MachineMode && csrs.mstatus.fields.mie))) { return {MachineMode, m_pending}; } pending = pending & csrs.mideleg.reg; auto s_pending = pending & ~csrs.sideleg.reg; if (s_pending && (prv < SupervisorMode || (prv == SupervisorMode && csrs.mstatus.fields.sie))) { return {SupervisorMode, s_pending}; } auto u_pending = pending & csrs.sideleg.reg; if (u_pending && (prv == UserMode && csrs.mstatus.fields.uie)) { return {UserMode, u_pending}; } return {NoneMode, 0}; } void ISS::switch_to_trap_handler(PrivilegeLevel target_mode) { if (trace) { printf("[vp::iss] switch to trap handler, time %s, last_pc %8x, pc %8x, irq %u, t-prv %1x\n", quantum_keeper.get_current_time().to_string().c_str(), last_pc, pc, csrs.mcause.fields.interrupt, target_mode); } // free any potential LR/SC bus lock before processing a trap/interrupt release_lr_sc_reservation(); auto pp = prv; prv = target_mode; switch (target_mode) { case MachineMode: csrs.mepc.reg = pc; csrs.mstatus.fields.mpie = csrs.mstatus.fields.mie; csrs.mstatus.fields.mie = 0; csrs.mstatus.fields.mpp = pp; pc = csrs.mtvec.get_base_address(); if(pc == 0) { if(error_on_zero_traphandler) { throw std::runtime_error("[ISS] Took null trap handler in machine mode"); } else { static bool once = true; if (once) std::cout << "[ISS] Warn: Taking trap handler in machine mode to 0x0, this is probably an error." << std::endl; once = false; } } if (csrs.mcause.fields.interrupt && csrs.mtvec.fields.mode == csr_mtvec::Mode::Vectored) pc += 4 * csrs.mcause.fields.exception_code; break; case SupervisorMode: assert(prv == SupervisorMode || prv == UserMode); csrs.sepc.reg = pc; csrs.mstatus.fields.spie = csrs.mstatus.fields.sie; csrs.mstatus.fields.sie = 0; csrs.mstatus.fields.spp = pp; pc = csrs.stvec.get_base_address(); if (csrs.scause.fields.interrupt && csrs.stvec.fields.mode == csr_mtvec::Mode::Vectored) pc += 4 * csrs.scause.fields.exception_code; break; case UserMode: assert(prv == UserMode); csrs.uepc.reg = pc; csrs.mstatus.fields.upie = csrs.mstatus.fields.uie; csrs.mstatus.fields.uie = 0; pc = csrs.utvec.get_base_address(); if (csrs.ucause.fields.interrupt && csrs.utvec.fields.mode == csr_mtvec::Mode::Vectored) pc += 4 * csrs.ucause.fields.exception_code; break; default: throw std::runtime_error("unknown privilege level " + std::to_string(target_mode)); } } void ISS::performance_and_sync_update(Opcode::Mapping executed_op) { ++total_num_instr; if (!csrs.mcountinhibit.fields.IR) ++csrs.instret.reg; if (lr_sc_counter != 0) { --lr_sc_counter; assert (lr_sc_counter >= 0); if (lr_sc_counter == 0) release_lr_sc_reservation(); } auto new_cycles = instr_cycles[executed_op]; if (!csrs.mcountinhibit.fields.CY) cycle_counter += new_cycles; quantum_keeper.inc(new_cycles); if (quantum_keeper.need_sync()) { if (lr_sc_counter == 0) // match SystemC sync with bus unlocking in a tight LR_W/SC_W loop quantum_keeper.sync(); } } void ISS::run_step() { assert(regs.read(0) == 0); // speeds up the execution performance (non debug mode) significantly by // checking the additional flag first if (debug_mode && (breakpoints.find(pc) != breakpoints.end())) { status = CoreExecStatus::HitBreakpoint; return; } last_pc = pc; try { exec_step(); auto x = compute_pending_interrupts(); if (x.target_mode != NoneMode) { prepare_interrupt(x); switch_to_trap_handler(x.target_mode); } } catch (SimulationTrap &e) { if (trace) std::cout << "take trap " << e.reason << ", mtval=" << e.mtval << std::endl; auto target_mode = prepare_trap(e); switch_to_trap_handler(target_mode); } // NOTE: writes to zero register are supposedly allowed but must be ignored // (reset it after every instruction, instead of checking *rd != zero* // before every register write) regs.regs[regs.zero] = 0; // Do not use a check *pc == last_pc* here. The reason is that due to // interrupts *pc* can be set to *last_pc* accidentally (when jumping back // to *mepc*). if (shall_exit) status = CoreExecStatus::Terminated; performance_and_sync_update(op); } void ISS::run() { // run a single step until either a breakpoint is hit or the execution // terminates do { run_step(); } while (status == CoreExecStatus::Runnable); // force sync to make sure that no action is missed quantum_keeper.sync(); } void ISS::show() { boost::io::ios_flags_saver ifs(std::cout); std::cout << "=[ core : " << csrs.mhartid.reg << " ]===========================" << std::endl; std::cout << "simulation time: " << sc_core::sc_time_stamp() << std::endl; regs.show(); std::cout << "pc = " << std::hex << pc << std::endl; std::cout << "num-instr = " << std::dec << csrs.instret.reg << std::endl; } ================================================ FILE: vp/src/core/rv32/iss.h ================================================ #pragma once #include "core/common/bus_lock_if.h" #include "core/common/clint_if.h" #include "core/common/instr.h" #include "core/common/irq_if.h" #include "core/common/trap.h" #include "core/common/debug.h" #include "csr.h" #include "fp.h" #include "mem_if.h" #include "syscall_if.h" #include "util/common.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace rv32 { struct RegFile { static constexpr unsigned NUM_REGS = 32; int32_t regs[NUM_REGS]; RegFile(); RegFile(const RegFile &other); void write(uint32_t index, int32_t value); int32_t read(uint32_t index); uint32_t shamt(uint32_t index); int32_t &operator[](const uint32_t idx); void show(); enum e : uint16_t { x0 = 0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, zero = x0, ra = x1, sp = x2, gp = x3, tp = x4, t0 = x5, t1 = x6, t2 = x7, s0 = x8, fp = x8, s1 = x9, a0 = x10, a1 = x11, a2 = x12, a3 = x13, a4 = x14, a5 = x15, a6 = x16, a7 = x17, s2 = x18, s3 = x19, s4 = x20, s5 = x21, s6 = x22, s7 = x23, s8 = x24, s9 = x25, s10 = x26, s11 = x27, t3 = x28, t4 = x29, t5 = x30, t6 = x31, }; }; // NOTE: on this branch, currently the *simple-timing* model is still directly // integrated in the ISS. Merge the *timedb* branch to use the timing_if. struct ISS; struct timing_if { virtual ~timing_if() {} virtual void update_timing(Instruction instr, Opcode::Mapping op, ISS &iss) = 0; }; /* Buffer to be used between the ISS and instruction memory interface to cache compressed instructions. * In case the ISS does not support compressed instructions, then this buffer is not necessary and the ISS * can use the memory interface directly. */ struct InstructionBuffer { instr_memory_if *instr_mem = nullptr; uint32_t last_fetch_addr = 0; uint32_t buffer = 0; uint32_t load_instr(uint64_t addr) { if (addr == (last_fetch_addr + 2)) return (buffer >> 16); last_fetch_addr = addr; buffer = instr_mem->load_instr(addr); return buffer; } }; struct PendingInterrupts { PrivilegeLevel target_mode; uint32_t pending; }; struct ISS : public external_interrupt_target, public clint_interrupt_target, public iss_syscall_if, public debug_target_if { clint_if *clint = nullptr; instr_memory_if *instr_mem = nullptr; data_memory_if *mem = nullptr; syscall_emulator_if *sys = nullptr; // optional, if provided, the iss will intercept and handle syscalls directly RegFile regs; FpRegs fp_regs; uint32_t pc = 0; uint32_t last_pc = 0; bool trace = false; bool shall_exit = false; bool ignore_wfi = false; bool error_on_zero_traphandler = false; csr_table csrs; PrivilegeLevel prv = MachineMode; int64_t lr_sc_counter = 0; uint64_t total_num_instr = 0; // last decoded and executed instruction and opcode Instruction instr; Opcode::Mapping op; CoreExecStatus status = CoreExecStatus::Runnable; std::unordered_set breakpoints; bool debug_mode = false; sc_core::sc_event wfi_event; std::string systemc_name; tlm_utils::tlm_quantumkeeper quantum_keeper; sc_core::sc_time cycle_time; sc_core::sc_time cycle_counter; // use a separate cycle counter, since cycle count can be inhibited std::array instr_cycles; static constexpr int32_t REG_MIN = INT32_MIN; static constexpr unsigned xlen = 32; ISS(uint32_t hart_id, bool use_E_base_isa = false); void exec_step(); uint64_t _compute_and_get_current_cycles(); void init(instr_memory_if *instr_mem, data_memory_if *data_mem, clint_if *clint, uint32_t entrypoint, uint32_t sp); void trigger_external_interrupt(PrivilegeLevel level) override; void clear_external_interrupt(PrivilegeLevel level) override; void trigger_timer_interrupt(bool status) override; void trigger_software_interrupt(bool status) override; void sys_exit() override; unsigned get_syscall_register_index() override; uint64_t read_register(unsigned idx) override; void write_register(unsigned idx, uint64_t value) override; std::vector get_registers(void) override; Architecture get_architecture(void) override { return RV32; } uint64_t get_progam_counter(void) override; void enable_debug(void) override; CoreExecStatus get_status(void) override; void set_status(CoreExecStatus) override; void block_on_wfi(bool) override; void insert_breakpoint(uint64_t) override; void remove_breakpoint(uint64_t) override; uint64_t get_hart_id() override; void release_lr_sc_reservation() { lr_sc_counter = 0; mem->atomic_unlock(); } void fp_prepare_instr(); void fp_finish_instr(); void fp_set_dirty(); void fp_update_exception_flags(); void fp_setup_rm(); void fp_require_not_off(); uint32_t get_csr_value(uint32_t addr); void set_csr_value(uint32_t addr, uint32_t value); bool is_invalid_csr_access(uint32_t csr_addr, bool is_write); void validate_csr_counter_read_access_rights(uint32_t addr); unsigned pc_alignment_mask() { if (csrs.misa.has_C_extension()) return ~0x1; else return ~0x3; } inline void trap_check_pc_alignment() { assert(!(pc & 0x1) && "not possible due to immediate formats and jump execution"); if (unlikely((pc & 0x3) && (!csrs.misa.has_C_extension()))) { // NOTE: misaligned instruction address not possible on machines supporting compressed instructions raise_trap(EXC_INSTR_ADDR_MISALIGNED, pc); } } template inline void trap_check_addr_alignment(uint32_t addr) { if (unlikely(addr % Alignment)) { raise_trap(isLoad ? EXC_LOAD_ADDR_MISALIGNED : EXC_STORE_AMO_ADDR_MISALIGNED, addr); } } inline void execute_amo(Instruction &instr, std::function operation) { uint32_t addr = regs[instr.rs1()]; trap_check_addr_alignment<4, false>(addr); uint32_t data; try { data = mem->atomic_load_word(addr); } catch (SimulationTrap &e) { if (e.reason == EXC_LOAD_ACCESS_FAULT) e.reason = EXC_STORE_AMO_ACCESS_FAULT; throw e; } uint32_t val = operation(data, regs[instr.rs2()]); mem->atomic_store_word(addr, val); regs[instr.rd()] = data; } inline bool m_mode() { return prv == MachineMode; } inline bool s_mode() { return prv == SupervisorMode; } inline bool u_mode() { return prv == UserMode; } PrivilegeLevel prepare_trap(SimulationTrap &e); void prepare_interrupt(const PendingInterrupts &x); PendingInterrupts compute_pending_interrupts(); bool has_pending_enabled_interrupts() { return compute_pending_interrupts().target_mode != NoneMode; } bool has_local_pending_enabled_interrupts() { return csrs.mie.reg & csrs.mip.reg; } void return_from_trap_handler(PrivilegeLevel return_mode); void switch_to_trap_handler(PrivilegeLevel target_mode); void performance_and_sync_update(Opcode::Mapping executed_op); void run_step() override; void run() override; void show(); }; /* Do not call the run function of the ISS directly but use one of the Runner * wrappers. */ struct DirectCoreRunner : public sc_core::sc_module { ISS &core; std::string thread_name; SC_HAS_PROCESS(DirectCoreRunner); DirectCoreRunner(ISS &core) : sc_module(sc_core::sc_module_name(core.systemc_name.c_str())), core(core) { thread_name = "run" + std::to_string(core.get_hart_id()); SC_NAMED_THREAD(run, thread_name.c_str()); } void run() { core.run(); if (core.status == CoreExecStatus::HitBreakpoint) { throw std::runtime_error( "Breakpoints are not supported in the direct runner, use the debug " "runner instead."); } assert(core.status == CoreExecStatus::Terminated); sc_core::sc_stop(); } }; } // namespace rv32 ================================================ FILE: vp/src/core/rv32/mem.h ================================================ #pragma once #include "core/common/dmi.h" #include "iss.h" #include "mmu.h" namespace rv32 { /* For optimization, use DMI to fetch instructions */ struct InstrMemoryProxy : public instr_memory_if { MemoryDMI dmi; tlm_utils::tlm_quantumkeeper &quantum_keeper; sc_core::sc_time clock_cycle = sc_core::sc_time(10, sc_core::SC_NS); sc_core::sc_time access_delay = clock_cycle * 2; InstrMemoryProxy(const MemoryDMI &dmi, ISS &owner) : dmi(dmi), quantum_keeper(owner.quantum_keeper) {} virtual uint32_t load_instr(uint64_t pc) override { quantum_keeper.inc(access_delay); return dmi.load(pc); } }; struct CombinedMemoryInterface : public sc_core::sc_module, public instr_memory_if, public data_memory_if, public mmu_memory_if { ISS &iss; std::shared_ptr bus_lock; uint64_t lr_addr = 0; tlm_utils::simple_initiator_socket isock; tlm_utils::tlm_quantumkeeper &quantum_keeper; // optionally add DMI ranges for optimization sc_core::sc_time clock_cycle = sc_core::sc_time(10, sc_core::SC_NS); sc_core::sc_time dmi_access_delay = clock_cycle * 4; std::vector dmi_ranges; MMU *mmu; CombinedMemoryInterface(sc_core::sc_module_name, ISS &owner, MMU *mmu = nullptr) : iss(owner), quantum_keeper(iss.quantum_keeper), mmu(mmu) { } uint64_t v2p(uint64_t vaddr, MemoryAccessType type) override { if (mmu == nullptr) return vaddr; return mmu->translate_virtual_to_physical_addr(vaddr, type); } inline void _do_transaction(tlm::tlm_command cmd, uint64_t addr, uint8_t *data, unsigned num_bytes) { tlm::tlm_generic_payload trans; trans.set_command(cmd); trans.set_address(addr); trans.set_data_ptr(data); trans.set_data_length(num_bytes); trans.set_response_status(tlm::TLM_OK_RESPONSE); sc_core::sc_time local_delay = quantum_keeper.get_local_time(); isock->b_transport(trans, local_delay); assert(local_delay >= quantum_keeper.get_local_time()); quantum_keeper.set(local_delay); if (trans.is_response_error()) { if (iss.trace || iss.sys) // if iss has syscall interface, it likely has no traphandler for this std::cout << "WARNING: core memory transaction failed for address 0x" << std::hex << addr << std::dec << std::endl; if (cmd == tlm::TLM_READ_COMMAND) raise_trap(EXC_LOAD_PAGE_FAULT, addr); else if (cmd == tlm::TLM_WRITE_COMMAND) raise_trap(EXC_STORE_AMO_PAGE_FAULT, addr); else throw std::runtime_error("TLM command must be read or write"); } } template inline T _raw_load_data(uint64_t addr) { // NOTE: a DMI load will not context switch (SystemC) and not modify the memory, hence should be able to // postpone the lock after the dmi access bus_lock->wait_for_access_rights(iss.get_hart_id()); for (auto &e : dmi_ranges) { if (e.contains(addr)) { quantum_keeper.inc(dmi_access_delay); return e.load(addr); } } T ans; _do_transaction(tlm::TLM_READ_COMMAND, addr, (uint8_t *)&ans, sizeof(T)); return ans; } template inline void _raw_store_data(uint64_t addr, T value) { bus_lock->wait_for_access_rights(iss.get_hart_id()); bool done = false; for (auto &e : dmi_ranges) { if (e.contains(addr)) { quantum_keeper.inc(dmi_access_delay); e.store(addr, value); done = true; } } if (!done) _do_transaction(tlm::TLM_WRITE_COMMAND, addr, (uint8_t *)&value, sizeof(T)); atomic_unlock(); } template inline T _load_data(uint64_t addr) { return _raw_load_data(v2p(addr, LOAD)); } template inline void _store_data(uint64_t addr, T value) { _raw_store_data(v2p(addr, STORE), value); } uint64_t mmu_load_pte64(uint64_t addr) override { return _raw_load_data(addr); } uint64_t mmu_load_pte32(uint64_t addr) override { return _raw_load_data(addr); } void mmu_store_pte32(uint64_t addr, uint32_t value) override { _raw_store_data(addr, value); } void flush_tlb() override { mmu->flush_tlb(); } uint32_t load_instr(uint64_t addr) override { return _raw_load_data(v2p(addr, FETCH)); } int64_t load_double(uint64_t addr) override { return _load_data(addr); } int32_t load_word(uint64_t addr) override { return _load_data(addr); } int32_t load_half(uint64_t addr) override { return _load_data(addr); } int32_t load_byte(uint64_t addr) override { return _load_data(addr); } uint32_t load_uhalf(uint64_t addr) override { return _load_data(addr); } uint32_t load_ubyte(uint64_t addr) override { return _load_data(addr); } void store_double(uint64_t addr, uint64_t value) override { _store_data(addr, value); } void store_word(uint64_t addr, uint32_t value) override { _store_data(addr, value); } void store_half(uint64_t addr, uint16_t value) override { _store_data(addr, value); } void store_byte(uint64_t addr, uint8_t value) override { _store_data(addr, value); } virtual int32_t atomic_load_word(uint64_t addr) override { bus_lock->lock(iss.get_hart_id()); return load_word(addr); } virtual void atomic_store_word(uint64_t addr, uint32_t value) override { assert(bus_lock->is_locked(iss.get_hart_id())); store_word(addr, value); } virtual int32_t atomic_load_reserved_word(uint64_t addr) override { bus_lock->lock(iss.get_hart_id()); lr_addr = addr; return load_word(addr); } virtual bool atomic_store_conditional_word(uint64_t addr, uint32_t value) override { /* According to the RISC-V ISA, an implementation can fail each LR/SC sequence that does not satisfy the forward * progress semantic. * The lock is established by the LR instruction and the lock is kept while forward progress is maintained. */ if (bus_lock->is_locked(iss.get_hart_id())) { if (addr == lr_addr) { store_word(addr, value); return true; } atomic_unlock(); } return false; } virtual void atomic_unlock() override { bus_lock->unlock(iss.get_hart_id()); } }; } // namespace rv32 ================================================ FILE: vp/src/core/rv32/mem_if.h ================================================ #pragma once #include namespace rv32 { struct instr_memory_if { virtual ~instr_memory_if() {} virtual uint32_t load_instr(uint64_t pc) = 0; }; //NOTE: load/store double is used for floating point D extension struct data_memory_if { virtual ~data_memory_if() {} virtual int64_t load_double(uint64_t addr) = 0; virtual int32_t load_word(uint64_t addr) = 0; virtual int32_t load_half(uint64_t addr) = 0; virtual int32_t load_byte(uint64_t addr) = 0; virtual uint32_t load_uhalf(uint64_t addr) = 0; virtual uint32_t load_ubyte(uint64_t addr) = 0; virtual void store_double(uint64_t addr, uint64_t value) = 0; virtual void store_word(uint64_t addr, uint32_t value) = 0; virtual void store_half(uint64_t addr, uint16_t value) = 0; virtual void store_byte(uint64_t addr, uint8_t value) = 0; virtual int32_t atomic_load_word(uint64_t addr) = 0; virtual void atomic_store_word(uint64_t addr, uint32_t value) = 0; virtual int32_t atomic_load_reserved_word(uint64_t addr) = 0; virtual bool atomic_store_conditional_word(uint64_t addr, uint32_t value) = 0; virtual void atomic_unlock() = 0; virtual void flush_tlb() = 0; }; } // namespace rv32 ================================================ FILE: vp/src/core/rv32/mmu.h ================================================ #pragma once #include "iss.h" #include "core/common/mmu.h" namespace rv32 { typedef GenericMMU MMU; } // namespace rv64 ================================================ FILE: vp/src/core/rv32/syscall.cpp ================================================ #include "syscall.h" #include #include #include #include #include #include #include #include using namespace rv32; // see: riscv-gnu-toolchain/riscv-newlib/libgloss/riscv/ // for syscall implementation in the risc-v C lib (many are ignored and just return -1) typedef int32_t rv32_long; typedef int32_t rv32_time_t; struct rv32_timeval { rv32_time_t tv_sec; rv32_time_t tv_usec; }; struct rv32_timespec { rv32_time_t tv_sec; rv32_time_t tv_nsec; }; struct rv32_stat { uint64_t st_dev; uint64_t st_ino; uint32_t st_mode; uint32_t st_nlink; uint32_t st_uid; uint32_t st_gid; uint64_t st_rdev; uint64_t __pad1; int64_t st_size; int32_t st_blksize; int32_t __pad2; int64_t st_blocks; rv32_timespec st_atim; rv32_timespec st_mtim; rv32_timespec st_ctim; int32_t __glibc_reserved[2]; }; void _copy_timespec(rv32_timespec *dst, timespec *src) { dst->tv_sec = src->tv_sec; dst->tv_nsec = src->tv_nsec; } int sys_fstat(SyscallHandler *sys, int fd, rv32_stat *s_addr) { struct stat x; int ans = fstat(fd, &x); if (ans == 0) { rv32_stat *p = (rv32_stat *)sys->guest_to_host_pointer(s_addr); p->st_dev = x.st_dev; p->st_ino = x.st_ino; p->st_mode = x.st_mode; p->st_nlink = x.st_nlink; p->st_uid = x.st_uid; p->st_gid = x.st_gid; p->st_rdev = x.st_rdev; p->st_size = x.st_size; p->st_blksize = x.st_blksize; p->st_blocks = x.st_blocks; _copy_timespec(&p->st_atim, &x.st_atim); _copy_timespec(&p->st_mtim, &x.st_mtim); _copy_timespec(&p->st_ctim, &x.st_ctim); } return ans; } int sys_gettimeofday(SyscallHandler *sys, rv32_timeval *tp, void *tzp) { /* * timeval is using a struct with two long arguments. * The second argument tzp currently is not used by riscv code. */ assert(tzp == 0); struct timeval x; int ans = gettimeofday(&x, 0); rv32_timeval *p = (rv32_timeval *)sys->guest_to_host_pointer(tp); p->tv_sec = x.tv_sec; p->tv_usec = x.tv_usec; return ans; } int sys_time(SyscallHandler *sys, rv32_time_t *tloc) { time_t host_ans = time(0); rv32_time_t guest_ans = boost::lexical_cast(host_ans); if (tloc != 0) { rv32_time_t *p = (rv32_time_t *)sys->guest_to_host_pointer(tloc); *p = guest_ans; } return boost::lexical_cast(guest_ans); } namespace rv_sc { // see: riscv-gnu-toolchain/riscv/riscv32-unknown-elf/include/sys/_default_fcntl.h constexpr uint32_t RDONLY = 0x0000; /* +1 == FREAD */ constexpr uint32_t WRONLY = 0x0001; /* +1 == FWRITE */ constexpr uint32_t RDWR = 0x0002; /* +1 == FREAD|FWRITE */ constexpr uint32_t APPEND = 0x0008; constexpr uint32_t CREAT = 0x0200; constexpr uint32_t TRUNC = 0x0400; } // namespace rv_sc int translateRVFlagsToHost(const int flags) { int ret = 0; ret |= flags & rv_sc::RDONLY ? O_RDONLY : 0; ret |= flags & rv_sc::WRONLY ? O_WRONLY : 0; ret |= flags & rv_sc::RDWR ? O_RDWR : 0; ret |= flags & rv_sc::APPEND ? O_APPEND : 0; ret |= flags & rv_sc::CREAT ? O_CREAT : 0; ret |= flags & rv_sc::TRUNC ? O_TRUNC : 0; if (ret == 0 && flags != 0) { throw std::runtime_error("unsupported flag"); } return ret; } int sys_brk(SyscallHandler *sys, void *addr) { if (addr == 0) { // riscv newlib expects brk to return current heap address when zero is passed in return boost::lexical_cast(sys->hp); } else { // NOTE: can also shrink again auto n = (uintptr_t)addr; sys->hp = n; if (sys->hp > sys->max_heap) sys->max_heap = sys->hp; // same for brk increase/decrease return boost::lexical_cast(n); } } int sys_write(SyscallHandler *sys, int fd, const void *buf, size_t count) { const char *p = (const char *)sys->guest_to_host_pointer((void *)buf); auto ans = write(fd, p, count); if (ans < 0) { std::cout << "WARNING [sys-write error]: " << strerror(errno) << std::endl; std::cout << " fd = " << fd << std::endl; std::cout << " count = " << count << std::endl; assert(false); } return ans; } int sys_read(SyscallHandler *sys, int fd, void *buf, size_t count) { char *p = (char *)sys->guest_to_host_pointer(buf); auto ans = read(fd, p, count); assert(ans >= 0); return ans; } int sys_lseek(int fd, off_t offset, int whence) { auto ans = lseek(fd, offset, whence); return ans; } int sys_open(SyscallHandler *sys, const char *pathname, int flags, mode_t mode) { const char *host_pathname = (char *)sys->guest_to_host_pointer((void *)pathname); auto ans = open(host_pathname, translateRVFlagsToHost(flags), mode); std::cout << "[sys_open] " << host_pathname << ", " << flags << " (translated to " << translateRVFlagsToHost(flags) << "), " << mode << std::endl; return ans; } int sys_close(int fd) { if (fd == STDOUT_FILENO || fd == STDIN_FILENO || fd == STDERR_FILENO) { // ignore closing of std streams, just return success return 0; } else { return close(fd); } } /* * TODO: Some parameters need to be aligned to the hosts word width (mostly 64 bit) * Especially when coming from a 32 bit guest system. */ int SyscallHandler::execute_syscall(uint64_t n, uint64_t _a0, uint64_t _a1, uint64_t _a2, uint64_t) { // NOTE: when linking with CRT, the most basic example only calls *gettimeofday* and finally *exit* switch (n) { case SYS_fstat: return sys_fstat(this, _a0, (rv32_stat *)_a1); case SYS_gettimeofday: return sys_gettimeofday(this, (struct rv32_timeval *)_a0, (void *)_a1); case SYS_brk: return sys_brk(this, (void *)_a0); case SYS_time: return sys_time(this, (rv32_time_t *)_a0); case SYS_write: return sys_write(this, _a0, (void *)_a1, _a2); case SYS_read: return sys_read(this, _a0, (void *)_a1, _a2); case SYS_lseek: return sys_lseek(_a0, _a1, _a2); case SYS_open: return sys_open(this, (const char *)_a0, _a1, _a2); case SYS_close: return sys_close(_a0); case SYS_exit: // If the software requested a non-zero exit code then terminate directly. // Otherwise, stop the SystemC simulation and exit with a zero exit code. if (_a0) exit(_a0); shall_exit = true; return 0; case SYS_host_error: throw std::runtime_error("SYS_host_error"); case SYS_host_test_pass: std::cout << "TEST_PASS" << std::endl; shall_exit = true; return 0; case SYS_host_test_fail: std::cout << "TEST_FAIL (testnum = " << _a0 << ")" << std::endl; shall_exit = true; return 0; } std::cerr << "unsupported syscall '" << n << "'" << std::endl; std::cerr << "is this perhaps a trap ExceptionCode? " << std::endl; throw std::runtime_error("unsupported syscall '" + std::to_string(n) + "'"); } ================================================ FILE: vp/src/core/rv32/syscall.h ================================================ #pragma once #include #include #include #include // see: newlib/libgloss/riscv @ // https://github.com/riscv/riscv-newlib/tree/riscv-newlib-2.5.0/libgloss/riscv #define SYS_exit 93 #define SYS_exit_group 94 #define SYS_getpid 172 #define SYS_kill 129 #define SYS_read 63 #define SYS_write 64 #define SYS_open 1024 #define SYS_openat 56 #define SYS_close 57 #define SYS_lseek 62 #define SYS_brk 214 #define SYS_link 1025 #define SYS_unlink 1026 #define SYS_mkdir 1030 #define SYS_chdir 49 #define SYS_getcwd 17 #define SYS_stat 1038 #define SYS_fstat 80 #define SYS_lstat 1039 #define SYS_fstatat 79 #define SYS_access 1033 #define SYS_faccessat 48 #define SYS_pread 67 #define SYS_pwrite 68 #define SYS_uname 160 #define SYS_getuid 174 #define SYS_geteuid 175 #define SYS_getgid 176 #define SYS_getegid 177 #define SYS_mmap 222 #define SYS_munmap 215 #define SYS_mremap 216 #define SYS_time 1062 #define SYS_getmainvars 2011 #define SYS_rt_sigaction 134 #define SYS_writev 66 #define SYS_gettimeofday 169 #define SYS_times 153 #define SYS_fcntl 25 #define SYS_getdents 61 #define SYS_dup 23 // custom extensions #define SYS_host_error \ 1 // indicate an error, i.e. this instruction should never be reached so something went wrong during exec. #define SYS_host_test_pass 2 // RISC-V test execution successfully completed #define SYS_host_test_fail 3 // RISC-V test execution failed #include #include #include "iss.h" #include "syscall_if.h" namespace rv32 { struct SyscallHandler : public sc_core::sc_module, syscall_emulator_if { tlm_utils::simple_target_socket tsock; std::unordered_map cores; void register_core(ISS *core) { assert(cores.find(core->get_hart_id()) == cores.end()); cores[core->get_hart_id()] = core; } SyscallHandler(sc_core::sc_module_name) { tsock.register_b_transport(this, &SyscallHandler::transport); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { (void)delay; auto addr = trans.get_address(); assert(addr % 4 == 0); assert(trans.get_data_length() == 4); auto hart_id = *((uint32_t *)trans.get_data_ptr()); assert((cores.find(hart_id) != cores.end()) && "core not registered in syscall handler"); execute_syscall(cores[hart_id]); } virtual void execute_syscall(iss_syscall_if *core) override { auto syscall = core->read_register(core->get_syscall_register_index()); auto a3 = core->read_register(RegFile::a3); auto a2 = core->read_register(RegFile::a2); auto a1 = core->read_register(RegFile::a1); auto a0 = core->read_register(RegFile::a0); // printf("a7=%u, a0=%u, a1=%u, a2=%u, a3=%u\n", a7, a0, a1, a2, a3); auto ans = execute_syscall(syscall, a0, a1, a2, a3); core->write_register(RegFile::a0, boost::lexical_cast(ans)); if (shall_exit) core->sys_exit(); } uint8_t *mem = 0; // direct pointer to start of guest memory in host memory uint64_t mem_offset; // start address of the memory as mapped into the // address space uint64_t hp = 0; // heap pointer bool shall_exit = false; bool shall_break = false; // only for memory consumption evaluation uint64_t start_heap = 0; uint64_t max_heap = 0; uint64_t get_max_heap_memory_consumption() { return max_heap - start_heap; } void init(uint8_t *host_memory_pointer, uint64_t mem_start_address, uint64_t heap_pointer_address) { mem = host_memory_pointer; mem_offset = mem_start_address; hp = heap_pointer_address; start_heap = hp; max_heap = hp; } uint8_t *guest_address_to_host_pointer(uintptr_t addr) { assert(mem != nullptr); return mem + (addr - mem_offset); } uint8_t *guest_to_host_pointer(void *p) { return guest_address_to_host_pointer((uintptr_t)p); } /* * Syscalls are implemented to work directly on guest memory (represented in * host as byte array). Note: the data structures on the host system might * not be binary compatible with those on the guest system. */ int execute_syscall(uint64_t n, uint64_t _a0, uint64_t _a1, uint64_t _a2, uint64_t _a3); }; } // namespace rv32 ================================================ FILE: vp/src/core/rv32/syscall_if.h ================================================ #pragma once #include namespace rv32 { /* The syscall handler is using this interface to access and control the ISS. */ struct iss_syscall_if { virtual ~iss_syscall_if() {} virtual void sys_exit() = 0; // virtual void sys_break() = 0; virtual unsigned get_syscall_register_index() = 0; virtual uint64_t read_register(unsigned idx) = 0; virtual void write_register(unsigned idx, uint64_t value) = 0; // virtual uint32_t get_hart_id() = 0; }; /* Using this interface, the ISS supports to intercept and delegate syscalls. */ struct syscall_emulator_if { virtual ~syscall_emulator_if() {} virtual void execute_syscall(iss_syscall_if *core) = 0; }; } // namespace rv32 ================================================ FILE: vp/src/core/rv32/timing/timing_external.h ================================================ #pragma once #include "../iss.h" #include #include #include std::string RISCV_TIMING_SIM_LIB = "riscv-timing-sim.so"; std::string RISCV_TIMING_DB = "riscv-timing-db.xml"; // NOTE: the interface inside the library has to match this one exactly, don't // forget the *virtual* attribute struct SimTimingInterface { virtual uint64_t get_cycles_for_instruction(uint64_t pc); // only to detect errors in loading the shared library virtual uint64_t get_magic_number(); }; struct ExternalTimingDecorator : public timing_if { SimTimingInterface *timing_sim = 0; void *lib_handle = 0; SimTimingInterface *(*create)(const char *) = 0; void (*destroy)(SimTimingInterface *) = 0; void initialize() { lib_handle = dlopen(RISCV_TIMING_SIM_LIB.c_str(), RTLD_LAZY); if (!lib_handle) throw std::runtime_error("unable to open shared library '" + RISCV_TIMING_SIM_LIB + "'"); create = (SimTimingInterface * (*)(const char *)) dlsym(lib_handle, "create_riscv_vp_timing_interface"); if (!create) throw std::runtime_error("unable to load 'create_riscv_vp_timing_interface' function"); destroy = (void (*)(SimTimingInterface *))dlsym(lib_handle, "destroy_riscv_vp_timing_interface"); if (!destroy) throw std::runtime_error("unable to load 'destroy_riscv_vp_timing_interface' function"); timing_sim = (SimTimingInterface *)create(RISCV_TIMING_DB.c_str()); } ExternalTimingDecorator() { initialize(); } ~ExternalTimingDecorator() { assert(timing_sim != 0); destroy(timing_sim); assert(lib_handle != 0); dlclose(lib_handle); } void on_begin_exec_step(Instruction instr, Opcode::mapping op, ISS &iss) override { uint64_t cycles = timing_sim->get_cycles_for_instruction(iss.last_pc); assert(timing_sim->get_magic_number() == 0x5E5E5E5E5E5E5E5E); sc_core::sc_time delay = iss.cycle_time * cycles; iss.quantum_keeper.inc(delay); } }; ================================================ FILE: vp/src/core/rv32/timing/timing_simple.h ================================================ #pragma once #include "../iss.h" struct SimpleTimingDecorator : public timing_if { std::array instr_cycles; sc_core::sc_time cycle_time = sc_core::sc_time(10, sc_core::SC_NS); SimpleTimingDecorator() { for (int i = 0; i < Opcode::NUMBER_OF_INSTRUCTIONS; ++i) instr_cycles[i] = cycle_time; const sc_core::sc_time memory_access_cycles = 4 * cycle_time; const sc_core::sc_time mul_div_cycles = 8 * cycle_time; instr_cycles[Opcode::LB] = memory_access_cycles; instr_cycles[Opcode::LBU] = memory_access_cycles; instr_cycles[Opcode::LH] = memory_access_cycles; instr_cycles[Opcode::LHU] = memory_access_cycles; instr_cycles[Opcode::LW] = memory_access_cycles; instr_cycles[Opcode::SB] = memory_access_cycles; instr_cycles[Opcode::SH] = memory_access_cycles; instr_cycles[Opcode::SW] = memory_access_cycles; instr_cycles[Opcode::MUL] = mul_div_cycles; instr_cycles[Opcode::MULH] = mul_div_cycles; instr_cycles[Opcode::MULHU] = mul_div_cycles; instr_cycles[Opcode::MULHSU] = mul_div_cycles; instr_cycles[Opcode::DIV] = mul_div_cycles; instr_cycles[Opcode::DIVU] = mul_div_cycles; instr_cycles[Opcode::REM] = mul_div_cycles; instr_cycles[Opcode::REMU] = mul_div_cycles; } void on_begin_exec_step(Instruction instr, Opcode::mapping op, ISS &iss) override { auto new_cycles = instr_cycles[op]; iss.quantum_keeper.inc(new_cycles); } }; ================================================ FILE: vp/src/core/rv64/CMakeLists.txt ================================================ file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) add_library(rv64 iss.cpp syscall.cpp ${HEADERS}) target_link_libraries(rv64 systemc core-common softfloat) if(COLOR_THEME STREQUAL "LIGHT") message("> using color theme LIGHT") target_compile_definitions(rv64 PRIVATE COLOR_THEME_LIGHT) elseif(COLOR_THEME STREQUAL "DARK") message("> using color theme DARK") target_compile_definitions(rv64 PRIVATE COLOR_THEME_DARK) endif() target_include_directories(rv64 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) ================================================ FILE: vp/src/core/rv64/csr.h ================================================ #pragma once #include #include #include #include #include "core/common/trap.h" #include "util/common.h" namespace rv64 { constexpr unsigned FS_OFF = 0b00; constexpr unsigned FS_INITIAL = 0b01; constexpr unsigned FS_CLEAN = 0b10; constexpr unsigned FS_DIRTY = 0b11; inline bool is_valid_privilege_level(PrivilegeLevel mode) { return mode == MachineMode || mode == SupervisorMode || mode == UserMode; } struct csr_64 { uint64_t reg = 0; }; struct csr_misa { csr_misa() { init(); } union { uint64_t reg = 0; struct { unsigned extensions : 26; unsigned long wiri : 36; unsigned mxl : 2; } fields; }; bool has_C_extension() { return fields.extensions & C; } bool has_user_mode_extension() { return fields.extensions & U; } bool has_supervisor_mode_extension() { return fields.extensions & S; } enum { A = 1, C = 1 << 2, D = 1 << 3, E = 1 << 4, F = 1 << 5, I = 1 << 8, M = 1 << 12, N = 1 << 13, S = 1 << 18, U = 1 << 20, }; void init() { fields.extensions = I | M | A | F | D | C | N | U | S; // IMACFD + NUS fields.mxl = 2; // RV64 } }; struct csr_mvendorid { union { uint64_t reg = 0; struct { unsigned offset : 7; unsigned bank : 25; unsigned _unused : 32; } fields; }; }; struct csr_mstatus { csr_mstatus() { // hardwire to 64 bit mode for now fields.sxl = 2; fields.uxl = 2; } union { uint64_t reg = 0; struct { unsigned uie : 1; unsigned sie : 1; unsigned wpri1 : 1; unsigned mie : 1; unsigned upie : 1; unsigned spie : 1; unsigned wpri2 : 1; unsigned mpie : 1; unsigned spp : 1; unsigned wpri3 : 2; unsigned mpp : 2; unsigned fs : 2; unsigned xs : 2; unsigned mprv : 1; unsigned sum : 1; unsigned mxr : 1; unsigned tvm : 1; unsigned tw : 1; unsigned tsr : 1; unsigned wpri4 : 9; unsigned uxl : 2; unsigned sxl : 2; unsigned wpri5 : 27; unsigned sd : 1; } fields; }; }; struct csr_mtvec { union { uint64_t reg = 0; struct { unsigned mode : 2; // WARL unsigned long base : 62; // WARL } fields; }; uint64_t get_base_address() { return fields.base << 2; } enum Mode { Direct = 0, Vectored = 1 }; void checked_write(uint64_t val) { reg = val; if (fields.mode >= 1) fields.mode = 0; } }; struct csr_mie { union { uint64_t reg = 0; struct { unsigned usie : 1; unsigned ssie : 1; unsigned wpri1 : 1; unsigned msie : 1; unsigned utie : 1; unsigned stie : 1; unsigned wpri2 : 1; unsigned mtie : 1; unsigned ueie : 1; unsigned seie : 1; unsigned wpri3 : 1; unsigned meie : 1; unsigned long wpri4 : 52; } fields; }; }; struct csr_mip { union { uint64_t reg = 0; struct { unsigned usip : 1; unsigned ssip : 1; unsigned wiri1 : 1; unsigned msip : 1; unsigned utip : 1; unsigned stip : 1; unsigned wiri2 : 1; unsigned mtip : 1; unsigned ueip : 1; unsigned seip : 1; unsigned wiri3 : 1; unsigned meip : 1; unsigned long wiri4 : 52; } fields; }; }; struct csr_mepc { union { uint64_t reg = 0; }; }; struct csr_mcause { union { uint64_t reg = 0; struct { unsigned long exception_code : 63; // WLRL unsigned interrupt : 1; } fields; }; }; struct csr_mcounteren { union { uint64_t reg = 0; struct { unsigned CY : 1; unsigned TM : 1; unsigned IR : 1; unsigned long reserved : 61; } fields; }; }; struct csr_mcountinhibit { union { uint64_t reg = 0; struct { unsigned CY : 1; unsigned zero : 1; unsigned IR : 1; unsigned long reserved : 61; } fields; }; }; struct csr_pmpcfg { union { uint64_t reg = 0; }; }; struct csr_pmpaddr { union { uint64_t reg = 0; struct { unsigned long address : 54; unsigned zero : 10; } fields; }; unsigned get_address() { return fields.address << 2; } }; struct csr_satp { union { uint64_t reg = 0; struct { unsigned long ppn : 44; // WARL unsigned asid : 16; // WARL unsigned mode : 4; // WARL } fields; }; }; /* Actually 32 bit large, but use 64 value for consistency and simply set the read/write mask accordingly. */ struct csr_fcsr { union { uint64_t reg = 0; struct { unsigned fflags : 5; unsigned frm : 3; unsigned reserved : 24; unsigned _ : 32; } fields; struct { unsigned NX : 1; // invalid operation unsigned UF : 1; // divide by zero unsigned OF : 1; // overflow unsigned DZ : 1; // underflow unsigned NV : 1; // inexact } fflags; }; }; namespace csr { template inline bool is_bitset(T &csr, unsigned bitpos) { return csr.reg & (1 << bitpos); } constexpr uint64_t MIE_MASK = 0b101110111011; constexpr uint64_t SIE_MASK = 0b001100110011; constexpr uint64_t UIE_MASK = 0b000100010001; constexpr uint64_t MIP_WRITE_MASK = 0b001100110011; constexpr uint64_t MIP_READ_MASK = MIE_MASK; constexpr uint64_t SIP_MASK = 0b11; constexpr uint64_t UIP_MASK = 0b1; constexpr uint64_t MEDELEG_MASK = 0b1011101111111111; constexpr uint64_t MIDELEG_MASK = MIE_MASK; constexpr uint64_t MTVEC_MASK = ~2; constexpr uint64_t MCOUNTEREN_MASK = 0b111; constexpr uint64_t MCOUNTINHIBIT_MASK = 0b101; constexpr uint64_t SEDELEG_MASK = 0b1011000111111111; constexpr uint64_t SIDELEG_MASK = MIDELEG_MASK; constexpr uint64_t MSTATUS_WRITE_MASK = 0b1000000000000000000000000000000000000000011111111111100110111011; constexpr uint64_t MSTATUS_READ_MASK = 0b1000000000000000000000000000111100000000011111111111100110111011; constexpr uint64_t SSTATUS_WRITE_MASK = 0b1000000000000000000000000000000000000000000011011110000100110011; constexpr uint64_t SSTATUS_READ_MASK = 0b1000000000000000000000000000001100000000000011011110000100110011; constexpr uint64_t USTATUS_MASK = 0b0000000000000000000000000000000000000000000000000000000000010001; constexpr uint64_t PMPADDR_MASK = 0b0000000000111111111111111111111111111111111111111111111111111111; constexpr uint64_t SATP_MASK = 0b1111000000000000000011111111111111111111111111111111111111111111; constexpr uint64_t SATP_MODE = 0b1111000000000000000000000000000000000000000000000000000000000000; constexpr uint64_t FCSR_MASK = 0b11111111; // 64 bit timer csrs constexpr unsigned CYCLE_ADDR = 0xC00; constexpr unsigned TIME_ADDR = 0xC01; constexpr unsigned INSTRET_ADDR = 0xC02; // shadows for the above CSRs constexpr unsigned MCYCLE_ADDR = 0xB00; constexpr unsigned MTIME_ADDR = 0xB01; constexpr unsigned MINSTRET_ADDR = 0xB02; // 32 bit machine CSRs constexpr unsigned MVENDORID_ADDR = 0xF11; constexpr unsigned MARCHID_ADDR = 0xF12; constexpr unsigned MIMPID_ADDR = 0xF13; constexpr unsigned MHARTID_ADDR = 0xF14; constexpr unsigned MSTATUS_ADDR = 0x300; constexpr unsigned MISA_ADDR = 0x301; constexpr unsigned MEDELEG_ADDR = 0x302; constexpr unsigned MIDELEG_ADDR = 0x303; constexpr unsigned MIE_ADDR = 0x304; constexpr unsigned MTVEC_ADDR = 0x305; constexpr unsigned MCOUNTEREN_ADDR = 0x306; constexpr unsigned MCOUNTINHIBIT_ADDR = 0x320; constexpr unsigned MSCRATCH_ADDR = 0x340; constexpr unsigned MEPC_ADDR = 0x341; constexpr unsigned MCAUSE_ADDR = 0x342; constexpr unsigned MTVAL_ADDR = 0x343; constexpr unsigned MIP_ADDR = 0x344; constexpr unsigned PMPCFG0_ADDR = 0x3A0; constexpr unsigned PMPCFG1_ADDR = 0x3A1; constexpr unsigned PMPCFG2_ADDR = 0x3A2; constexpr unsigned PMPCFG3_ADDR = 0x3A3; constexpr unsigned PMPADDR0_ADDR = 0x3B0; constexpr unsigned PMPADDR1_ADDR = 0x3B1; constexpr unsigned PMPADDR2_ADDR = 0x3B2; constexpr unsigned PMPADDR3_ADDR = 0x3B3; constexpr unsigned PMPADDR4_ADDR = 0x3B4; constexpr unsigned PMPADDR5_ADDR = 0x3B5; constexpr unsigned PMPADDR6_ADDR = 0x3B6; constexpr unsigned PMPADDR7_ADDR = 0x3B7; constexpr unsigned PMPADDR8_ADDR = 0x3B8; constexpr unsigned PMPADDR9_ADDR = 0x3B9; constexpr unsigned PMPADDR10_ADDR = 0x3BA; constexpr unsigned PMPADDR11_ADDR = 0x3BB; constexpr unsigned PMPADDR12_ADDR = 0x3BC; constexpr unsigned PMPADDR13_ADDR = 0x3BD; constexpr unsigned PMPADDR14_ADDR = 0x3BE; constexpr unsigned PMPADDR15_ADDR = 0x3BF; // 32 bit supervisor CSRs constexpr unsigned SSTATUS_ADDR = 0x100; constexpr unsigned SEDELEG_ADDR = 0x102; constexpr unsigned SIDELEG_ADDR = 0x103; constexpr unsigned SIE_ADDR = 0x104; constexpr unsigned STVEC_ADDR = 0x105; constexpr unsigned SCOUNTEREN_ADDR = 0x106; constexpr unsigned SSCRATCH_ADDR = 0x140; constexpr unsigned SEPC_ADDR = 0x141; constexpr unsigned SCAUSE_ADDR = 0x142; constexpr unsigned STVAL_ADDR = 0x143; constexpr unsigned SIP_ADDR = 0x144; constexpr unsigned SATP_ADDR = 0x180; // 32 bit user CSRs constexpr unsigned USTATUS_ADDR = 0x000; constexpr unsigned UIE_ADDR = 0x004; constexpr unsigned UTVEC_ADDR = 0x005; constexpr unsigned USCRATCH_ADDR = 0x040; constexpr unsigned UEPC_ADDR = 0x041; constexpr unsigned UCAUSE_ADDR = 0x042; constexpr unsigned UTVAL_ADDR = 0x043; constexpr unsigned UIP_ADDR = 0x044; // floating point CSRs constexpr unsigned FFLAGS_ADDR = 0x001; constexpr unsigned FRM_ADDR = 0x002; constexpr unsigned FCSR_ADDR = 0x003; // performance counters constexpr unsigned HPMCOUNTER3_ADDR = 0xC03; constexpr unsigned HPMCOUNTER4_ADDR = 0xC04; constexpr unsigned HPMCOUNTER5_ADDR = 0xC05; constexpr unsigned HPMCOUNTER6_ADDR = 0xC06; constexpr unsigned HPMCOUNTER7_ADDR = 0xC07; constexpr unsigned HPMCOUNTER8_ADDR = 0xC08; constexpr unsigned HPMCOUNTER9_ADDR = 0xC09; constexpr unsigned HPMCOUNTER10_ADDR = 0xC0A; constexpr unsigned HPMCOUNTER11_ADDR = 0xC0B; constexpr unsigned HPMCOUNTER12_ADDR = 0xC0C; constexpr unsigned HPMCOUNTER13_ADDR = 0xC0D; constexpr unsigned HPMCOUNTER14_ADDR = 0xC0E; constexpr unsigned HPMCOUNTER15_ADDR = 0xC0F; constexpr unsigned HPMCOUNTER16_ADDR = 0xC10; constexpr unsigned HPMCOUNTER17_ADDR = 0xC11; constexpr unsigned HPMCOUNTER18_ADDR = 0xC12; constexpr unsigned HPMCOUNTER19_ADDR = 0xC13; constexpr unsigned HPMCOUNTER20_ADDR = 0xC14; constexpr unsigned HPMCOUNTER21_ADDR = 0xC15; constexpr unsigned HPMCOUNTER22_ADDR = 0xC16; constexpr unsigned HPMCOUNTER23_ADDR = 0xC17; constexpr unsigned HPMCOUNTER24_ADDR = 0xC18; constexpr unsigned HPMCOUNTER25_ADDR = 0xC19; constexpr unsigned HPMCOUNTER26_ADDR = 0xC1A; constexpr unsigned HPMCOUNTER27_ADDR = 0xC1B; constexpr unsigned HPMCOUNTER28_ADDR = 0xC1C; constexpr unsigned HPMCOUNTER29_ADDR = 0xC1D; constexpr unsigned HPMCOUNTER30_ADDR = 0xC1E; constexpr unsigned HPMCOUNTER31_ADDR = 0xC1F; constexpr unsigned HPMCOUNTER3H_ADDR = 0xC83; constexpr unsigned HPMCOUNTER4H_ADDR = 0xC84; constexpr unsigned HPMCOUNTER5H_ADDR = 0xC85; constexpr unsigned HPMCOUNTER6H_ADDR = 0xC86; constexpr unsigned HPMCOUNTER7H_ADDR = 0xC87; constexpr unsigned HPMCOUNTER8H_ADDR = 0xC88; constexpr unsigned HPMCOUNTER9H_ADDR = 0xC89; constexpr unsigned HPMCOUNTER10H_ADDR = 0xC8A; constexpr unsigned HPMCOUNTER11H_ADDR = 0xC8B; constexpr unsigned HPMCOUNTER12H_ADDR = 0xC8C; constexpr unsigned HPMCOUNTER13H_ADDR = 0xC8D; constexpr unsigned HPMCOUNTER14H_ADDR = 0xC8E; constexpr unsigned HPMCOUNTER15H_ADDR = 0xC8F; constexpr unsigned HPMCOUNTER16H_ADDR = 0xC90; constexpr unsigned HPMCOUNTER17H_ADDR = 0xC91; constexpr unsigned HPMCOUNTER18H_ADDR = 0xC92; constexpr unsigned HPMCOUNTER19H_ADDR = 0xC93; constexpr unsigned HPMCOUNTER20H_ADDR = 0xC94; constexpr unsigned HPMCOUNTER21H_ADDR = 0xC95; constexpr unsigned HPMCOUNTER22H_ADDR = 0xC96; constexpr unsigned HPMCOUNTER23H_ADDR = 0xC97; constexpr unsigned HPMCOUNTER24H_ADDR = 0xC98; constexpr unsigned HPMCOUNTER25H_ADDR = 0xC99; constexpr unsigned HPMCOUNTER26H_ADDR = 0xC9A; constexpr unsigned HPMCOUNTER27H_ADDR = 0xC9B; constexpr unsigned HPMCOUNTER28H_ADDR = 0xC9C; constexpr unsigned HPMCOUNTER29H_ADDR = 0xC9D; constexpr unsigned HPMCOUNTER30H_ADDR = 0xC9E; constexpr unsigned HPMCOUNTER31H_ADDR = 0xC9F; constexpr unsigned MHPMCOUNTER3_ADDR = 0xB03; constexpr unsigned MHPMCOUNTER4_ADDR = 0xB04; constexpr unsigned MHPMCOUNTER5_ADDR = 0xB05; constexpr unsigned MHPMCOUNTER6_ADDR = 0xB06; constexpr unsigned MHPMCOUNTER7_ADDR = 0xB07; constexpr unsigned MHPMCOUNTER8_ADDR = 0xB08; constexpr unsigned MHPMCOUNTER9_ADDR = 0xB09; constexpr unsigned MHPMCOUNTER10_ADDR = 0xB0A; constexpr unsigned MHPMCOUNTER11_ADDR = 0xB0B; constexpr unsigned MHPMCOUNTER12_ADDR = 0xB0C; constexpr unsigned MHPMCOUNTER13_ADDR = 0xB0D; constexpr unsigned MHPMCOUNTER14_ADDR = 0xB0E; constexpr unsigned MHPMCOUNTER15_ADDR = 0xB0F; constexpr unsigned MHPMCOUNTER16_ADDR = 0xB10; constexpr unsigned MHPMCOUNTER17_ADDR = 0xB11; constexpr unsigned MHPMCOUNTER18_ADDR = 0xB12; constexpr unsigned MHPMCOUNTER19_ADDR = 0xB13; constexpr unsigned MHPMCOUNTER20_ADDR = 0xB14; constexpr unsigned MHPMCOUNTER21_ADDR = 0xB15; constexpr unsigned MHPMCOUNTER22_ADDR = 0xB16; constexpr unsigned MHPMCOUNTER23_ADDR = 0xB17; constexpr unsigned MHPMCOUNTER24_ADDR = 0xB18; constexpr unsigned MHPMCOUNTER25_ADDR = 0xB19; constexpr unsigned MHPMCOUNTER26_ADDR = 0xB1A; constexpr unsigned MHPMCOUNTER27_ADDR = 0xB1B; constexpr unsigned MHPMCOUNTER28_ADDR = 0xB1C; constexpr unsigned MHPMCOUNTER29_ADDR = 0xB1D; constexpr unsigned MHPMCOUNTER30_ADDR = 0xB1E; constexpr unsigned MHPMCOUNTER31_ADDR = 0xB1F; constexpr unsigned MHPMCOUNTER3H_ADDR = 0xB83; constexpr unsigned MHPMCOUNTER4H_ADDR = 0xB84; constexpr unsigned MHPMCOUNTER5H_ADDR = 0xB85; constexpr unsigned MHPMCOUNTER6H_ADDR = 0xB86; constexpr unsigned MHPMCOUNTER7H_ADDR = 0xB87; constexpr unsigned MHPMCOUNTER8H_ADDR = 0xB88; constexpr unsigned MHPMCOUNTER9H_ADDR = 0xB89; constexpr unsigned MHPMCOUNTER10H_ADDR = 0xB8A; constexpr unsigned MHPMCOUNTER11H_ADDR = 0xB8B; constexpr unsigned MHPMCOUNTER12H_ADDR = 0xB8C; constexpr unsigned MHPMCOUNTER13H_ADDR = 0xB8D; constexpr unsigned MHPMCOUNTER14H_ADDR = 0xB8E; constexpr unsigned MHPMCOUNTER15H_ADDR = 0xB8F; constexpr unsigned MHPMCOUNTER16H_ADDR = 0xB90; constexpr unsigned MHPMCOUNTER17H_ADDR = 0xB91; constexpr unsigned MHPMCOUNTER18H_ADDR = 0xB92; constexpr unsigned MHPMCOUNTER19H_ADDR = 0xB93; constexpr unsigned MHPMCOUNTER20H_ADDR = 0xB94; constexpr unsigned MHPMCOUNTER21H_ADDR = 0xB95; constexpr unsigned MHPMCOUNTER22H_ADDR = 0xB96; constexpr unsigned MHPMCOUNTER23H_ADDR = 0xB97; constexpr unsigned MHPMCOUNTER24H_ADDR = 0xB98; constexpr unsigned MHPMCOUNTER25H_ADDR = 0xB99; constexpr unsigned MHPMCOUNTER26H_ADDR = 0xB9A; constexpr unsigned MHPMCOUNTER27H_ADDR = 0xB9B; constexpr unsigned MHPMCOUNTER28H_ADDR = 0xB9C; constexpr unsigned MHPMCOUNTER29H_ADDR = 0xB9D; constexpr unsigned MHPMCOUNTER30H_ADDR = 0xB9E; constexpr unsigned MHPMCOUNTER31H_ADDR = 0xB9F; constexpr unsigned MHPMEVENT3_ADDR = 0x323; constexpr unsigned MHPMEVENT4_ADDR = 0x324; constexpr unsigned MHPMEVENT5_ADDR = 0x325; constexpr unsigned MHPMEVENT6_ADDR = 0x326; constexpr unsigned MHPMEVENT7_ADDR = 0x327; constexpr unsigned MHPMEVENT8_ADDR = 0x328; constexpr unsigned MHPMEVENT9_ADDR = 0x329; constexpr unsigned MHPMEVENT10_ADDR = 0x32A; constexpr unsigned MHPMEVENT11_ADDR = 0x32B; constexpr unsigned MHPMEVENT12_ADDR = 0x32C; constexpr unsigned MHPMEVENT13_ADDR = 0x32D; constexpr unsigned MHPMEVENT14_ADDR = 0x32E; constexpr unsigned MHPMEVENT15_ADDR = 0x32F; constexpr unsigned MHPMEVENT16_ADDR = 0x330; constexpr unsigned MHPMEVENT17_ADDR = 0x331; constexpr unsigned MHPMEVENT18_ADDR = 0x332; constexpr unsigned MHPMEVENT19_ADDR = 0x333; constexpr unsigned MHPMEVENT20_ADDR = 0x334; constexpr unsigned MHPMEVENT21_ADDR = 0x335; constexpr unsigned MHPMEVENT22_ADDR = 0x336; constexpr unsigned MHPMEVENT23_ADDR = 0x337; constexpr unsigned MHPMEVENT24_ADDR = 0x338; constexpr unsigned MHPMEVENT25_ADDR = 0x339; constexpr unsigned MHPMEVENT26_ADDR = 0x33A; constexpr unsigned MHPMEVENT27_ADDR = 0x33B; constexpr unsigned MHPMEVENT28_ADDR = 0x33C; constexpr unsigned MHPMEVENT29_ADDR = 0x33D; constexpr unsigned MHPMEVENT30_ADDR = 0x33E; constexpr unsigned MHPMEVENT31_ADDR = 0x33F; }; // namespace csr struct csr_table { csr_64 cycle; csr_64 time; csr_64 instret; csr_mvendorid mvendorid; csr_64 marchid; csr_64 mimpid; csr_64 mhartid; csr_mstatus mstatus; csr_misa misa; csr_64 medeleg; csr_64 mideleg; csr_mie mie; csr_mtvec mtvec; csr_mcounteren mcounteren; csr_mcountinhibit mcountinhibit; csr_64 mscratch; csr_mepc mepc; csr_mcause mcause; csr_64 mtval; csr_mip mip; // pmp configuration std::array pmpaddr; std::array pmpcfg; // supervisor csrs (please note: some are already covered by the machine mode csrs, i.e. sstatus, sie and sip, and // some are required but have the same fields, hence the machine mode classes are used) csr_64 sedeleg; csr_64 sideleg; csr_mtvec stvec; csr_mcounteren scounteren; csr_64 sscratch; csr_mepc sepc; csr_mcause scause; csr_64 stval; csr_satp satp; // user csrs (see above comment) csr_mtvec utvec; csr_64 uscratch; csr_mepc uepc; csr_mcause ucause; csr_64 utval; csr_fcsr fcsr; std::unordered_map register_mapping; csr_table() { using namespace csr; register_mapping[CYCLE_ADDR] = &cycle.reg; register_mapping[TIME_ADDR] = &time.reg; register_mapping[INSTRET_ADDR] = &instret.reg; register_mapping[MCYCLE_ADDR] = &cycle.reg; register_mapping[MTIME_ADDR] = &time.reg; register_mapping[MINSTRET_ADDR] = &instret.reg; register_mapping[MVENDORID_ADDR] = &mvendorid.reg; register_mapping[MARCHID_ADDR] = &marchid.reg; register_mapping[MIMPID_ADDR] = &mimpid.reg; register_mapping[MHARTID_ADDR] = &mhartid.reg; register_mapping[MSTATUS_ADDR] = &mstatus.reg; register_mapping[MISA_ADDR] = &misa.reg; register_mapping[MEDELEG_ADDR] = &medeleg.reg; register_mapping[MIDELEG_ADDR] = &mideleg.reg; register_mapping[MIE_ADDR] = &mie.reg; register_mapping[MTVEC_ADDR] = &mtvec.reg; register_mapping[MCOUNTEREN_ADDR] = &mcounteren.reg; register_mapping[MCOUNTINHIBIT_ADDR] = &mcountinhibit.reg; register_mapping[MSCRATCH_ADDR] = &mscratch.reg; register_mapping[MEPC_ADDR] = &mepc.reg; register_mapping[MCAUSE_ADDR] = &mcause.reg; register_mapping[MTVAL_ADDR] = &mtval.reg; register_mapping[MIP_ADDR] = &mip.reg; for (unsigned i = 0; i < 16; ++i) register_mapping[PMPADDR0_ADDR + i] = &pmpaddr[i].reg; for (unsigned i = 0; i < 4; ++i) register_mapping[PMPCFG0_ADDR + i] = &pmpcfg[i].reg; register_mapping[SEDELEG_ADDR] = &sedeleg.reg; register_mapping[SIDELEG_ADDR] = &sideleg.reg; register_mapping[STVEC_ADDR] = &stvec.reg; register_mapping[SCOUNTEREN_ADDR] = &scounteren.reg; register_mapping[SSCRATCH_ADDR] = &sscratch.reg; register_mapping[SEPC_ADDR] = &sepc.reg; register_mapping[SCAUSE_ADDR] = &scause.reg; register_mapping[STVAL_ADDR] = &stval.reg; register_mapping[SATP_ADDR] = &satp.reg; register_mapping[UTVEC_ADDR] = &utvec.reg; register_mapping[USCRATCH_ADDR] = &uscratch.reg; register_mapping[UEPC_ADDR] = &uepc.reg; register_mapping[UCAUSE_ADDR] = &ucause.reg; register_mapping[UTVAL_ADDR] = &utval.reg; register_mapping[FCSR_ADDR] = &fcsr.reg; } bool is_valid_csr64_addr(unsigned addr) { return register_mapping.find(addr) != register_mapping.end(); } void default_write64(unsigned addr, uint64_t value) { auto it = register_mapping.find(addr); ensure((it != register_mapping.end()) && "validate address before calling this function"); *it->second = value; } uint64_t default_read64(unsigned addr) { auto it = register_mapping.find(addr); ensure((it != register_mapping.end()) && "validate address before calling this function"); return *it->second; } }; #define SWITCH_CASE_MATCH_ANY_HPMCOUNTER_RV64 \ case HPMCOUNTER3_ADDR: \ case HPMCOUNTER4_ADDR: \ case HPMCOUNTER5_ADDR: \ case HPMCOUNTER6_ADDR: \ case HPMCOUNTER7_ADDR: \ case HPMCOUNTER8_ADDR: \ case HPMCOUNTER9_ADDR: \ case HPMCOUNTER10_ADDR: \ case HPMCOUNTER11_ADDR: \ case HPMCOUNTER12_ADDR: \ case HPMCOUNTER13_ADDR: \ case HPMCOUNTER14_ADDR: \ case HPMCOUNTER15_ADDR: \ case HPMCOUNTER16_ADDR: \ case HPMCOUNTER17_ADDR: \ case HPMCOUNTER18_ADDR: \ case HPMCOUNTER19_ADDR: \ case HPMCOUNTER20_ADDR: \ case HPMCOUNTER21_ADDR: \ case HPMCOUNTER22_ADDR: \ case HPMCOUNTER23_ADDR: \ case HPMCOUNTER24_ADDR: \ case HPMCOUNTER25_ADDR: \ case HPMCOUNTER26_ADDR: \ case HPMCOUNTER27_ADDR: \ case HPMCOUNTER28_ADDR: \ case HPMCOUNTER29_ADDR: \ case HPMCOUNTER30_ADDR: \ case HPMCOUNTER31_ADDR: \ case MHPMCOUNTER3_ADDR: \ case MHPMCOUNTER4_ADDR: \ case MHPMCOUNTER5_ADDR: \ case MHPMCOUNTER6_ADDR: \ case MHPMCOUNTER7_ADDR: \ case MHPMCOUNTER8_ADDR: \ case MHPMCOUNTER9_ADDR: \ case MHPMCOUNTER10_ADDR: \ case MHPMCOUNTER11_ADDR: \ case MHPMCOUNTER12_ADDR: \ case MHPMCOUNTER13_ADDR: \ case MHPMCOUNTER14_ADDR: \ case MHPMCOUNTER15_ADDR: \ case MHPMCOUNTER16_ADDR: \ case MHPMCOUNTER17_ADDR: \ case MHPMCOUNTER18_ADDR: \ case MHPMCOUNTER19_ADDR: \ case MHPMCOUNTER20_ADDR: \ case MHPMCOUNTER21_ADDR: \ case MHPMCOUNTER22_ADDR: \ case MHPMCOUNTER23_ADDR: \ case MHPMCOUNTER24_ADDR: \ case MHPMCOUNTER25_ADDR: \ case MHPMCOUNTER26_ADDR: \ case MHPMCOUNTER27_ADDR: \ case MHPMCOUNTER28_ADDR: \ case MHPMCOUNTER29_ADDR: \ case MHPMCOUNTER30_ADDR: \ case MHPMCOUNTER31_ADDR: \ case MHPMEVENT3_ADDR: \ case MHPMEVENT4_ADDR: \ case MHPMEVENT5_ADDR: \ case MHPMEVENT6_ADDR: \ case MHPMEVENT7_ADDR: \ case MHPMEVENT8_ADDR: \ case MHPMEVENT9_ADDR: \ case MHPMEVENT10_ADDR: \ case MHPMEVENT11_ADDR: \ case MHPMEVENT12_ADDR: \ case MHPMEVENT13_ADDR: \ case MHPMEVENT14_ADDR: \ case MHPMEVENT15_ADDR: \ case MHPMEVENT16_ADDR: \ case MHPMEVENT17_ADDR: \ case MHPMEVENT18_ADDR: \ case MHPMEVENT19_ADDR: \ case MHPMEVENT20_ADDR: \ case MHPMEVENT21_ADDR: \ case MHPMEVENT22_ADDR: \ case MHPMEVENT23_ADDR: \ case MHPMEVENT24_ADDR: \ case MHPMEVENT25_ADDR: \ case MHPMEVENT26_ADDR: \ case MHPMEVENT27_ADDR: \ case MHPMEVENT28_ADDR: \ case MHPMEVENT29_ADDR: \ case MHPMEVENT30_ADDR: \ case MHPMEVENT31_ADDR } // namespace rv64 ================================================ FILE: vp/src/core/rv64/elf_loader.h ================================================ #pragma once #include "core/common/elf_loader.h" namespace rv64 { // see: "ELF-64 Object File Format" document for ELF64 type definitions typedef uint64_t Elf64_Addr; typedef uint64_t Elf64_Off; typedef uint16_t Elf64_Half; typedef uint32_t Elf64_Word; typedef int32_t Elf64_Sword; typedef uint64_t Elf64_Xword; typedef int64_t Elf64_Sxword; constexpr unsigned ELF_NIDENT = 16; typedef struct { unsigned char e_ident[ELF_NIDENT]; /* ELF identification */ Elf64_Half e_type; /* Object file type */ Elf64_Half e_machine; /* Machine type */ Elf64_Word e_version; /* Object file version */ Elf64_Addr e_entry; /* Entry point address */ Elf64_Off e_phoff; /* Program header offset */ Elf64_Off e_shoff; /* Section header offset */ Elf64_Word e_flags; /* Processor-specific flags */ Elf64_Half e_ehsize; /* ELF header size */ Elf64_Half e_phentsize; /* Size of program header entry */ Elf64_Half e_phnum; /* Number of program header entries */ Elf64_Half e_shentsize; /* Size of section header entry */ Elf64_Half e_shnum; /* Number of section header entries */ Elf64_Half e_shstrndx; /* Section name string table index */ } Elf64_Ehdr; typedef struct { Elf64_Word sh_name; /* Section name */ Elf64_Word sh_type; /* Section type */ Elf64_Xword sh_flags; /* Section attributes */ Elf64_Addr sh_addr; /* Virtual address in memory */ Elf64_Off sh_offset; /* Offset in file */ Elf64_Xword sh_size; /* Size of section */ Elf64_Word sh_link; /* Link to other section */ Elf64_Word sh_info; /* Miscellaneous information */ Elf64_Xword sh_addralign; /* Address alignment boundary */ Elf64_Xword sh_entsize; /* Size of entries, if section has table */ } Elf64_Shdr; typedef struct { Elf64_Word st_name; /* Symbol name */ unsigned char st_info; /* Type and Binding attributes */ unsigned char st_other; /* Reserved */ Elf64_Half st_shndx; /* Section table index */ Elf64_Addr st_value; /* Symbol value */ Elf64_Xword st_size; /* Size of object (e.g., common) */ } Elf64_Sym; typedef struct { Elf64_Word p_type; /* Type of segment */ Elf64_Word p_flags; /* Segment attributes */ Elf64_Off p_offset; /* Offset in file */ Elf64_Addr p_vaddr; /* Virtual address in memory */ Elf64_Addr p_paddr; /* Reserved */ Elf64_Xword p_filesz; /* Size of segment in file */ Elf64_Xword p_memsz; /* Size of segment in memory */ Elf64_Xword p_align; /* Alignment of segment */ } Elf64_Phdr; enum Elf64_PhdrType { PT_NULL = 0, PT_LOAD = 1, PT_DYNAMIC = 2, PT_INTERP = 3, PT_NOTE = 4, PT_SHLIB = 5, PT_PHDR = 6 }; struct Elf64Types { typedef uint64_t addr_t; typedef Elf64_Ehdr Elf_Ehdr; typedef Elf64_Phdr Elf_Phdr; typedef Elf64_Shdr Elf_Shdr; typedef Elf64_Sym Elf_Sym; static constexpr unsigned PT_LOAD = Elf64_PhdrType::PT_LOAD; }; typedef GenericElfLoader ELFLoader; } // namespace rv64 ================================================ FILE: vp/src/core/rv64/iss.cpp ================================================ #include "iss.h" // to save *cout* format setting, see *ISS::show* #include #include // for safe down-cast #include using namespace rv64; // GCC and clang support these types on x64 machines // perhaps use boost::multiprecision::int128_t instead // see: https://stackoverflow.com/questions/18439520/is-there-a-128-bit-integer-in-c typedef __int128_t int128_t; typedef __uint128_t uint128_t; #define RAISE_ILLEGAL_INSTRUCTION() raise_trap(EXC_ILLEGAL_INSTR, instr.data()); #define RD instr.rd() #define RS1 instr.rs1() #define RS2 instr.rs2() #define RS3 instr.rs3() const char *regnames[] = { "zero (x0)", "ra (x1)", "sp (x2)", "gp (x3)", "tp (x4)", "t0 (x5)", "t1 (x6)", "t2 (x7)", "s0/fp(x8)", "s1 (x9)", "a0 (x10)", "a1 (x11)", "a2 (x12)", "a3 (x13)", "a4 (x14)", "a5 (x15)", "a6 (x16)", "a7 (x17)", "s2 (x18)", "s3 (x19)", "s4 (x20)", "s5 (x21)", "s6 (x22)", "s7 (x23)", "s8 (x24)", "s9 (x25)", "s10 (x26)", "s11 (x27)", "t3 (x28)", "t4 (x29)", "t5 (x30)", "t6 (x31)", }; int regcolors[] = { #if defined(COLOR_THEME_DARK) 0, 1, 2, 3, 4, 5, 6, 52, 8, 9, 53, 54, 55, 56, 57, 58, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, #elif defined(COLOR_THEME_LIGHT) 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 153, 154, 155, 156, 157, 158, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, #else 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, #endif }; RegFile::RegFile() { memset(regs, 0, sizeof(regs)); } RegFile::RegFile(const RegFile &other) { memcpy(regs, other.regs, sizeof(regs)); } void RegFile::write(uint64_t index, int64_t value) { assert(index <= x31); assert(index != x0); regs[index] = value; } int64_t RegFile::read(uint64_t index) { if (index > x31) throw std::out_of_range("out-of-range register access"); return regs[index]; } uint64_t RegFile::shamt_w(uint64_t index) { assert(index <= x31); return BIT_RANGE(regs[index], 4, 0); } uint64_t RegFile::shamt(uint64_t index) { assert(index <= x31); return BIT_RANGE(regs[index], 5, 0); } int64_t &RegFile::operator[](const uint64_t idx) { return regs[idx]; } #if defined(COLOR_THEME_LIGHT) || defined(COLOR_THEME_DARK) #define COLORFRMT "\e[38;5;%um%s\e[39m" #define COLORPRINT(fmt, data) fmt, data #else #define COLORFRMT "%s" #define COLORPRINT(fmt, data) data #endif void RegFile::show() { for (unsigned i = 0; i < NUM_REGS; ++i) { printf(COLORFRMT " = %16lx\n", COLORPRINT(regcolors[i], regnames[i]), regs[i]); } } ISS::ISS(uint64_t hart_id) : systemc_name("Core-" + std::to_string(hart_id)) { csrs.mhartid.reg = hart_id; op = Opcode::Mapping::UNDEF; sc_core::sc_time qt = tlm::tlm_global_quantum::instance().get(); cycle_time = sc_core::sc_time(10, sc_core::SC_NS); assert(qt >= cycle_time); assert(qt % cycle_time == sc_core::SC_ZERO_TIME); for (int i = 0; i < Opcode::NUMBER_OF_INSTRUCTIONS; ++i) instr_cycles[i] = cycle_time; const sc_core::sc_time memory_access_cycles = 4 * cycle_time; const sc_core::sc_time mul_div_cycles = 8 * cycle_time; instr_cycles[Opcode::LB] = memory_access_cycles; instr_cycles[Opcode::LBU] = memory_access_cycles; instr_cycles[Opcode::LH] = memory_access_cycles; instr_cycles[Opcode::LHU] = memory_access_cycles; instr_cycles[Opcode::LW] = memory_access_cycles; instr_cycles[Opcode::SB] = memory_access_cycles; instr_cycles[Opcode::SH] = memory_access_cycles; instr_cycles[Opcode::SW] = memory_access_cycles; instr_cycles[Opcode::MUL] = mul_div_cycles; instr_cycles[Opcode::MULH] = mul_div_cycles; instr_cycles[Opcode::MULHU] = mul_div_cycles; instr_cycles[Opcode::MULHSU] = mul_div_cycles; instr_cycles[Opcode::DIV] = mul_div_cycles; instr_cycles[Opcode::DIVU] = mul_div_cycles; instr_cycles[Opcode::REM] = mul_div_cycles; instr_cycles[Opcode::REMU] = mul_div_cycles; } void ISS::exec_step() { assert(((pc & ~pc_alignment_mask()) == 0) && "misaligned instruction"); uint32_t mem_word; try { mem_word = instr_mem->load_instr(pc); instr = Instruction(mem_word); } catch (SimulationTrap &e) { op = Opcode::UNDEF; instr = Instruction(0); throw; } if (instr.is_compressed()) { op = instr.decode_and_expand_compressed(RV64); pc += 2; } else { op = instr.decode_normal(RV64); pc += 4; } if (trace) { printf("core %2lu: prv %1x: pc %16lx (%8x): %s ", csrs.mhartid.reg, prv, last_pc, mem_word, Opcode::mappingStr.at(op)); switch (Opcode::getType(op)) { case Opcode::Type::R: printf(COLORFRMT ", " COLORFRMT ", " COLORFRMT, COLORPRINT(regcolors[instr.rd()], regnames[instr.rd()]), COLORPRINT(regcolors[instr.rs1()], regnames[instr.rs1()]), COLORPRINT(regcolors[instr.rs2()], regnames[instr.rs2()])); break; case Opcode::Type::R4: printf(COLORFRMT ", " COLORFRMT ", " COLORFRMT ", " COLORFRMT, COLORPRINT(regcolors[instr.rd()], regnames[instr.rd()]), COLORPRINT(regcolors[instr.rs1()], regnames[instr.rs1()]), COLORPRINT(regcolors[instr.rs2()], regnames[instr.rs2()]), COLORPRINT(regcolors[instr.rs3()], regnames[instr.rs3()])); break; case Opcode::Type::I: printf(COLORFRMT ", " COLORFRMT ", 0x%x", COLORPRINT(regcolors[instr.rd()], regnames[instr.rd()]), COLORPRINT(regcolors[instr.rs1()], regnames[instr.rs1()]), instr.I_imm()); break; case Opcode::Type::S: printf(COLORFRMT ", " COLORFRMT ", 0x%x", COLORPRINT(regcolors[instr.rs1()], regnames[instr.rs1()]), COLORPRINT(regcolors[instr.rs2()], regnames[instr.rs2()]), instr.S_imm()); break; case Opcode::Type::B: printf(COLORFRMT ", " COLORFRMT ", 0x%x", COLORPRINT(regcolors[instr.rs1()], regnames[instr.rs1()]), COLORPRINT(regcolors[instr.rs2()], regnames[instr.rs2()]), instr.B_imm()); break; case Opcode::Type::U: printf(COLORFRMT ", 0x%x", COLORPRINT(regcolors[instr.rd()], regnames[instr.rd()]), instr.U_imm()); break; case Opcode::Type::J: printf(COLORFRMT ", 0x%x", COLORPRINT(regcolors[instr.rd()], regnames[instr.rd()]), instr.J_imm()); break; default:; } puts(""); } switch (op) { case Opcode::UNDEF: if (trace) std::cout << "WARNING: unknown instruction '" << std::to_string(instr.data()) << "' at address '" << std::to_string(last_pc) << "'" << std::endl; raise_trap(EXC_ILLEGAL_INSTR, instr.data()); break; case Opcode::ADDI: regs[instr.rd()] = regs[instr.rs1()] + instr.I_imm(); break; case Opcode::SLTI: regs[instr.rd()] = regs[instr.rs1()] < instr.I_imm(); break; case Opcode::SLTIU: regs[instr.rd()] = ((uint64_t)regs[instr.rs1()]) < ((uint64_t)instr.I_imm()); break; case Opcode::XORI: regs[instr.rd()] = regs[instr.rs1()] ^ instr.I_imm(); break; case Opcode::ORI: regs[instr.rd()] = regs[instr.rs1()] | instr.I_imm(); break; case Opcode::ANDI: regs[instr.rd()] = regs[instr.rs1()] & instr.I_imm(); break; case Opcode::ADD: regs[instr.rd()] = regs[instr.rs1()] + regs[instr.rs2()]; break; case Opcode::SUB: regs[instr.rd()] = regs[instr.rs1()] - regs[instr.rs2()]; break; case Opcode::SLL: regs[instr.rd()] = regs[instr.rs1()] << regs.shamt(instr.rs2()); break; case Opcode::SLT: regs[instr.rd()] = regs[instr.rs1()] < regs[instr.rs2()]; break; case Opcode::SLTU: regs[instr.rd()] = ((uint64_t)regs[instr.rs1()]) < ((uint64_t)regs[instr.rs2()]); break; case Opcode::SRL: regs[instr.rd()] = ((uint64_t)regs[instr.rs1()]) >> regs.shamt(instr.rs2()); break; case Opcode::SRA: regs[instr.rd()] = regs[instr.rs1()] >> regs.shamt(instr.rs2()); break; case Opcode::XOR: regs[instr.rd()] = regs[instr.rs1()] ^ regs[instr.rs2()]; break; case Opcode::OR: regs[instr.rd()] = regs[instr.rs1()] | regs[instr.rs2()]; break; case Opcode::AND: regs[instr.rd()] = regs[instr.rs1()] & regs[instr.rs2()]; break; case Opcode::SLLI: regs[instr.rd()] = regs[instr.rs1()] << instr.shamt(); break; case Opcode::SRLI: regs[instr.rd()] = ((uint64_t)regs[instr.rs1()]) >> instr.shamt(); break; case Opcode::SRAI: regs[instr.rd()] = regs[instr.rs1()] >> instr.shamt(); break; case Opcode::LUI: regs[instr.rd()] = instr.U_imm(); break; case Opcode::AUIPC: regs[instr.rd()] = last_pc + instr.U_imm(); break; case Opcode::JAL: { auto link = pc; pc = last_pc + instr.J_imm(); trap_check_pc_alignment(); regs[instr.rd()] = link; } break; case Opcode::JALR: { auto link = pc; pc = (regs[instr.rs1()] + instr.I_imm()) & ~1; trap_check_pc_alignment(); regs[instr.rd()] = link; } break; case Opcode::SB: { uint64_t addr = regs[instr.rs1()] + instr.S_imm(); mem->store_byte(addr, regs[instr.rs2()]); } break; case Opcode::SH: { uint64_t addr = regs[instr.rs1()] + instr.S_imm(); trap_check_addr_alignment<2, false>(addr); mem->store_half(addr, regs[instr.rs2()]); } break; case Opcode::SW: { uint64_t addr = regs[instr.rs1()] + instr.S_imm(); trap_check_addr_alignment<4, false>(addr); mem->store_word(addr, regs[instr.rs2()]); } break; case Opcode::SD: { uint64_t addr = regs[instr.rs1()] + instr.S_imm(); trap_check_addr_alignment<8, false>(addr); mem->store_double(addr, regs[instr.rs2()]); } break; case Opcode::LB: { uint64_t addr = regs[instr.rs1()] + instr.I_imm(); regs[instr.rd()] = mem->load_byte(addr); } break; case Opcode::LH: { uint64_t addr = regs[instr.rs1()] + instr.I_imm(); trap_check_addr_alignment<2, true>(addr); regs[instr.rd()] = mem->load_half(addr); } break; case Opcode::LW: { uint64_t addr = regs[instr.rs1()] + instr.I_imm(); trap_check_addr_alignment<4, true>(addr); regs[instr.rd()] = mem->load_word(addr); } break; case Opcode::LD: { uint64_t addr = regs[instr.rs1()] + instr.I_imm(); trap_check_addr_alignment<8, true>(addr); regs[instr.rd()] = mem->load_double(addr); } break; case Opcode::LBU: { uint64_t addr = regs[instr.rs1()] + instr.I_imm(); regs[instr.rd()] = mem->load_ubyte(addr); } break; case Opcode::LHU: { uint64_t addr = regs[instr.rs1()] + instr.I_imm(); trap_check_addr_alignment<2, true>(addr); regs[instr.rd()] = mem->load_uhalf(addr); } break; case Opcode::LWU: { uint64_t addr = regs[instr.rs1()] + instr.I_imm(); trap_check_addr_alignment<4, true>(addr); regs[instr.rd()] = mem->load_uword(addr); } break; case Opcode::BEQ: if (regs[instr.rs1()] == regs[instr.rs2()]) { pc = last_pc + instr.B_imm(); trap_check_pc_alignment(); } break; case Opcode::BNE: if (regs[instr.rs1()] != regs[instr.rs2()]) { pc = last_pc + instr.B_imm(); trap_check_pc_alignment(); } break; case Opcode::BLT: if (regs[instr.rs1()] < regs[instr.rs2()]) { pc = last_pc + instr.B_imm(); trap_check_pc_alignment(); } break; case Opcode::BGE: if (regs[instr.rs1()] >= regs[instr.rs2()]) { pc = last_pc + instr.B_imm(); trap_check_pc_alignment(); } break; case Opcode::BLTU: if ((uint64_t)regs[instr.rs1()] < (uint64_t)regs[instr.rs2()]) { pc = last_pc + instr.B_imm(); trap_check_pc_alignment(); } break; case Opcode::BGEU: if ((uint64_t)regs[instr.rs1()] >= (uint64_t)regs[instr.rs2()]) { pc = last_pc + instr.B_imm(); trap_check_pc_alignment(); } break; case Opcode::ADDIW: regs[instr.rd()] = (int32_t)regs[instr.rs1()] + (int32_t)instr.I_imm(); break; case Opcode::SLLIW: regs[instr.rd()] = (int32_t)((uint32_t)regs[instr.rs1()] << instr.shamt_w()); break; case Opcode::SRLIW: regs[instr.rd()] = (int32_t)(((uint32_t)regs[instr.rs1()]) >> instr.shamt_w()); break; case Opcode::SRAIW: regs[instr.rd()] = (int32_t)((int32_t)regs[instr.rs1()] >> instr.shamt_w()); break; case Opcode::ADDW: regs[instr.rd()] = (int32_t)regs[instr.rs1()] + (int32_t)regs[instr.rs2()]; break; case Opcode::SUBW: regs[instr.rd()] = (int32_t)regs[instr.rs1()] - (int32_t)regs[instr.rs2()]; break; case Opcode::SLLW: regs[instr.rd()] = (int32_t)((uint32_t)regs[instr.rs1()] << regs.shamt_w(instr.rs2())); break; case Opcode::SRLW: regs[instr.rd()] = (int32_t)(((uint32_t)regs[instr.rs1()]) >> regs.shamt_w(instr.rs2())); break; case Opcode::SRAW: regs[instr.rd()] = (int32_t)((int32_t)regs[instr.rs1()] >> regs.shamt_w(instr.rs2())); break; case Opcode::FENCE: case Opcode::FENCE_I: { // not using out of order execution/caches so can be ignored } break; case Opcode::ECALL: { if (sys) { sys->execute_syscall(this); } else { switch (prv) { case MachineMode: raise_trap(EXC_ECALL_M_MODE, last_pc); break; case SupervisorMode: raise_trap(EXC_ECALL_S_MODE, last_pc); break; case UserMode: raise_trap(EXC_ECALL_U_MODE, last_pc); break; default: throw std::runtime_error("unknown privilege level " + std::to_string(prv)); } } } break; case Opcode::EBREAK: { // TODO: also raise trap and let the SW deal with it? status = CoreExecStatus::HitBreakpoint; } break; case Opcode::CSRRW: { auto addr = instr.csr(); if (is_invalid_csr_access(addr, true)) { raise_trap(EXC_ILLEGAL_INSTR, instr.data()); } else { auto rd = instr.rd(); auto rs1_val = regs[instr.rs1()]; if (rd != RegFile::zero) { regs[instr.rd()] = get_csr_value(addr); } set_csr_value(addr, rs1_val); } } break; case Opcode::CSRRS: { auto addr = instr.csr(); auto rs1 = instr.rs1(); auto write = rs1 != RegFile::zero; if (is_invalid_csr_access(addr, write)) { raise_trap(EXC_ILLEGAL_INSTR, instr.data()); } else { auto rd = instr.rd(); auto rs1_val = regs[rs1]; auto csr_val = get_csr_value(addr); if (rd != RegFile::zero) regs[rd] = csr_val; if (write) set_csr_value(addr, csr_val | rs1_val); } } break; case Opcode::CSRRC: { auto addr = instr.csr(); auto rs1 = instr.rs1(); auto write = rs1 != RegFile::zero; if (is_invalid_csr_access(addr, write)) { raise_trap(EXC_ILLEGAL_INSTR, instr.data()); } else { auto rd = instr.rd(); auto rs1_val = regs[rs1]; auto csr_val = get_csr_value(addr); if (rd != RegFile::zero) regs[rd] = csr_val; if (write) set_csr_value(addr, csr_val & ~rs1_val); } } break; case Opcode::CSRRWI: { auto addr = instr.csr(); if (is_invalid_csr_access(addr, true)) { raise_trap(EXC_ILLEGAL_INSTR, instr.data()); } else { auto rd = instr.rd(); if (rd != RegFile::zero) { regs[rd] = get_csr_value(addr); } set_csr_value(addr, instr.zimm()); } } break; case Opcode::CSRRSI: { auto addr = instr.csr(); auto zimm = instr.zimm(); auto write = zimm != 0; if (is_invalid_csr_access(addr, write)) { raise_trap(EXC_ILLEGAL_INSTR, instr.data()); } else { auto csr_val = get_csr_value(addr); auto rd = instr.rd(); if (rd != RegFile::zero) regs[rd] = csr_val; if (write) set_csr_value(addr, csr_val | zimm); } } break; case Opcode::CSRRCI: { auto addr = instr.csr(); auto zimm = instr.zimm(); auto write = zimm != 0; if (is_invalid_csr_access(addr, write)) { raise_trap(EXC_ILLEGAL_INSTR, instr.data()); } else { auto csr_val = get_csr_value(addr); auto rd = instr.rd(); if (rd != RegFile::zero) regs[rd] = csr_val; if (write) set_csr_value(addr, csr_val & ~zimm); } } break; case Opcode::MUL: { int128_t ans = (int128_t)regs[instr.rs1()] * (int128_t)regs[instr.rs2()]; regs[instr.rd()] = (int64_t)ans; } break; case Opcode::MULH: { int128_t ans = (int128_t)regs[instr.rs1()] * (int128_t)regs[instr.rs2()]; regs[instr.rd()] = ans >> 64; } break; case Opcode::MULHU: { int128_t ans = ((uint128_t)(uint64_t)regs[instr.rs1()]) * (uint128_t)((uint64_t)regs[instr.rs2()]); regs[instr.rd()] = ans >> 64; } break; case Opcode::MULHSU: { int128_t ans = (int128_t)regs[instr.rs1()] * (uint128_t)((uint64_t)regs[instr.rs2()]); regs[instr.rd()] = ans >> 64; } break; case Opcode::DIV: { auto a = regs[instr.rs1()]; auto b = regs[instr.rs2()]; if (b == 0) { regs[instr.rd()] = -1; } else if (a == REG_MIN && b == -1) { regs[instr.rd()] = a; } else { regs[instr.rd()] = a / b; } } break; case Opcode::DIVU: { auto a = regs[instr.rs1()]; auto b = regs[instr.rs2()]; if (b == 0) { regs[instr.rd()] = -1; } else { regs[instr.rd()] = (uint64_t)a / (uint64_t)b; } } break; case Opcode::REM: { auto a = regs[instr.rs1()]; auto b = regs[instr.rs2()]; if (b == 0) { regs[instr.rd()] = a; } else if (a == REG_MIN && b == -1) { regs[instr.rd()] = 0; } else { regs[instr.rd()] = a % b; } } break; case Opcode::REMU: { auto a = regs[instr.rs1()]; auto b = regs[instr.rs2()]; if (b == 0) { regs[instr.rd()] = a; } else { regs[instr.rd()] = (uint64_t)a % (uint64_t)b; } } break; case Opcode::MULW: { regs[instr.rd()] = (int32_t)(regs[instr.rs1()] * regs[instr.rs2()]); } break; case Opcode::DIVW: { int32_t a = regs[instr.rs1()]; int32_t b = regs[instr.rs2()]; if (b == 0) { regs[instr.rd()] = -1; } else if (a == REG32_MIN && b == -1) { regs[instr.rd()] = a; } else { regs[instr.rd()] = a / b; } } break; case Opcode::DIVUW: { int32_t a = regs[instr.rs1()]; int32_t b = regs[instr.rs2()]; if (b == 0) { regs[instr.rd()] = -1; } else { regs[instr.rd()] = (int32_t)((uint32_t)a / (uint32_t)b); } } break; case Opcode::REMW: { int32_t a = regs[instr.rs1()]; int32_t b = regs[instr.rs2()]; if (b == 0) { regs[instr.rd()] = a; } else if (a == REG32_MIN && b == -1) { regs[instr.rd()] = 0; } else { regs[instr.rd()] = a % b; } } break; case Opcode::REMUW: { int32_t a = regs[instr.rs1()]; int32_t b = regs[instr.rs2()]; if (b == 0) { regs[instr.rd()] = a; } else { regs[instr.rd()] = (int32_t)((uint32_t)a % (uint32_t)b); } } break; case Opcode::LR_W: { uint64_t addr = regs[instr.rs1()]; trap_check_addr_alignment<4, true>(addr); regs[instr.rd()] = mem->atomic_load_reserved_word(addr); if (lr_sc_counter == 0) lr_sc_counter = 17; // this instruction + 16 additional ones, (an over-approximation) to cover the RISC-V forward progress property } break; case Opcode::SC_W: { uint64_t addr = regs[instr.rs1()]; trap_check_addr_alignment<4, false>(addr); int32_t val = regs[instr.rs2()]; regs[instr.rd()] = 1; // failure by default (in case a trap is thrown) regs[instr.rd()] = mem->atomic_store_conditional_word(addr, val) ? 0 : 1; // overwrite result (in case no trap is thrown) lr_sc_counter = 0; } break; case Opcode::AMOSWAP_W: { execute_amo_w(instr, [](int32_t a, int32_t b) { (void)a; return b; }); } break; case Opcode::AMOADD_W: { execute_amo_w(instr, [](int32_t a, int32_t b) { return a + b; }); } break; case Opcode::AMOXOR_W: { execute_amo_w(instr, [](int32_t a, int32_t b) { return a ^ b; }); } break; case Opcode::AMOAND_W: { execute_amo_w(instr, [](int32_t a, int32_t b) { return a & b; }); } break; case Opcode::AMOOR_W: { execute_amo_w(instr, [](int32_t a, int32_t b) { return a | b; }); } break; case Opcode::AMOMIN_W: { execute_amo_w(instr, [](int32_t a, int32_t b) { return std::min(a, b); }); } break; case Opcode::AMOMINU_W: { execute_amo_w(instr, [](int32_t a, int32_t b) { return std::min((uint32_t)a, (uint32_t)b); }); } break; case Opcode::AMOMAX_W: { execute_amo_w(instr, [](int32_t a, int32_t b) { return std::max(a, b); }); } break; case Opcode::AMOMAXU_W: { execute_amo_w(instr, [](int32_t a, int32_t b) { return std::max((uint32_t)a, (uint32_t)b); }); } break; case Opcode::LR_D: { uint64_t addr = regs[instr.rs1()]; trap_check_addr_alignment<8, true>(addr); regs[instr.rd()] = mem->atomic_load_reserved_double(addr); if (lr_sc_counter == 0) lr_sc_counter = 17; // this instruction + 16 additional ones, (an over-approximation) to cover the RISC-V forward progress property } break; case Opcode::SC_D: { uint64_t addr = regs[instr.rs1()]; trap_check_addr_alignment<8, false>(addr); uint64_t val = regs[instr.rs2()]; regs[instr.rd()] = 1; // failure by default (in case a trap is thrown) regs[instr.rd()] = mem->atomic_store_conditional_double(addr, val) ? 0 : 1; // overwrite result (in case no trap is thrown) lr_sc_counter = 0; } break; case Opcode::AMOSWAP_D: { execute_amo_d(instr, [](int64_t a, int64_t b) { (void)a; return b; }); } break; case Opcode::AMOADD_D: { execute_amo_d(instr, [](int64_t a, int64_t b) { return a + b; }); } break; case Opcode::AMOXOR_D: { execute_amo_d(instr, [](int64_t a, int64_t b) { return a ^ b; }); } break; case Opcode::AMOAND_D: { execute_amo_d(instr, [](int64_t a, int64_t b) { return a & b; }); } break; case Opcode::AMOOR_D: { execute_amo_d(instr, [](int64_t a, int64_t b) { return a | b; }); } break; case Opcode::AMOMIN_D: { execute_amo_d(instr, [](int64_t a, int64_t b) { return std::min(a, b); }); } break; case Opcode::AMOMINU_D: { execute_amo_d(instr, [](int64_t a, int64_t b) { return std::min((uint64_t)a, (uint64_t)b); }); } break; case Opcode::AMOMAX_D: { execute_amo_d(instr, [](int64_t a, int64_t b) { return std::max(a, b); }); } break; case Opcode::AMOMAXU_D: { execute_amo_d(instr, [](int64_t a, int64_t b) { return std::max((uint64_t)a, (uint64_t)b); }); } break; // RV64 F/D extension case Opcode::FLW: { uint64_t addr = regs[instr.rs1()] + instr.I_imm(); trap_check_addr_alignment<4, true>(addr); fp_regs.write(RD, float32_t{(uint32_t)mem->load_uword(addr)}); } break; case Opcode::FSW: { uint64_t addr = regs[instr.rs1()] + instr.S_imm(); trap_check_addr_alignment<4, false>(addr); mem->store_word(addr, fp_regs.u32(RS2)); } break; case Opcode::FADD_S: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_add(fp_regs.f32(RS1), fp_regs.f32(RS2))); fp_finish_instr(); } break; case Opcode::FSUB_S: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_sub(fp_regs.f32(RS1), fp_regs.f32(RS2))); fp_finish_instr(); } break; case Opcode::FMUL_S: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_mul(fp_regs.f32(RS1), fp_regs.f32(RS2))); fp_finish_instr(); } break; case Opcode::FDIV_S: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_div(fp_regs.f32(RS1), fp_regs.f32(RS2))); fp_finish_instr(); } break; case Opcode::FSQRT_S: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_sqrt(fp_regs.f32(RS1))); fp_finish_instr(); } break; case Opcode::FMIN_S: { fp_prepare_instr(); bool rs1_smaller = f32_lt_quiet(fp_regs.f32(RS1), fp_regs.f32(RS2)) || (f32_eq(fp_regs.f32(RS1), fp_regs.f32(RS2)) && f32_isNegative(fp_regs.f32(RS1))); if (f32_isNaN(fp_regs.f32(RS1)) && f32_isNaN(fp_regs.f32(RS2))) { fp_regs.write(RD, f32_defaultNaN); } else { if (rs1_smaller) fp_regs.write(RD, fp_regs.f32(RS1)); else fp_regs.write(RD, fp_regs.f32(RS2)); } fp_finish_instr(); } break; case Opcode::FMAX_S: { fp_prepare_instr(); bool rs1_greater = f32_lt_quiet(fp_regs.f32(RS2), fp_regs.f32(RS1)) || (f32_eq(fp_regs.f32(RS2), fp_regs.f32(RS1)) && f32_isNegative(fp_regs.f32(RS2))); if (f32_isNaN(fp_regs.f32(RS1)) && f32_isNaN(fp_regs.f32(RS2))) { fp_regs.write(RD, f32_defaultNaN); } else { if (rs1_greater) fp_regs.write(RD, fp_regs.f32(RS1)); else fp_regs.write(RD, fp_regs.f32(RS2)); } fp_finish_instr(); } break; case Opcode::FMADD_S: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_mulAdd(fp_regs.f32(RS1), fp_regs.f32(RS2), fp_regs.f32(RS3))); fp_finish_instr(); } break; case Opcode::FMSUB_S: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_mulAdd(fp_regs.f32(RS1), fp_regs.f32(RS2), f32_neg(fp_regs.f32(RS3)))); fp_finish_instr(); } break; case Opcode::FNMADD_S: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_mulAdd(f32_neg(fp_regs.f32(RS1)), fp_regs.f32(RS2), f32_neg(fp_regs.f32(RS3)))); fp_finish_instr(); } break; case Opcode::FNMSUB_S: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_mulAdd(f32_neg(fp_regs.f32(RS1)), fp_regs.f32(RS2), fp_regs.f32(RS3))); fp_finish_instr(); } break; case Opcode::FCVT_W_S: { fp_prepare_instr(); fp_setup_rm(); regs[RD] = f32_to_i32(fp_regs.f32(RS1), softfloat_roundingMode, true); fp_finish_instr(); } break; case Opcode::FCVT_WU_S: { fp_prepare_instr(); fp_setup_rm(); regs[RD] = (int32_t)f32_to_ui32(fp_regs.f32(RS1), softfloat_roundingMode, true); fp_finish_instr(); } break; case Opcode::FCVT_S_W: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, i32_to_f32((int32_t)regs[RS1])); fp_finish_instr(); } break; case Opcode::FCVT_S_WU: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, ui32_to_f32((int32_t)regs[RS1])); fp_finish_instr(); } break; case Opcode::FSGNJ_S: { fp_prepare_instr(); auto f1 = fp_regs.f32(RS1); auto f2 = fp_regs.f32(RS2); fp_regs.write(RD, float32_t{(f1.v & ~F32_SIGN_BIT) | (f2.v & F32_SIGN_BIT)}); fp_set_dirty(); } break; case Opcode::FSGNJN_S: { fp_prepare_instr(); auto f1 = fp_regs.f32(RS1); auto f2 = fp_regs.f32(RS2); fp_regs.write(RD, float32_t{(f1.v & ~F32_SIGN_BIT) | (~f2.v & F32_SIGN_BIT)}); fp_set_dirty(); } break; case Opcode::FSGNJX_S: { fp_prepare_instr(); auto f1 = fp_regs.f32(RS1); auto f2 = fp_regs.f32(RS2); fp_regs.write(RD, float32_t{f1.v ^ (f2.v & F32_SIGN_BIT)}); fp_set_dirty(); } break; case Opcode::FMV_W_X: { fp_prepare_instr(); fp_regs.write(RD, float32_t{(uint32_t)((int32_t)regs[RS1])}); fp_set_dirty(); } break; case Opcode::FMV_X_W: { fp_prepare_instr(); regs[RD] = (int32_t)fp_regs.u32(RS1); } break; case Opcode::FEQ_S: { fp_prepare_instr(); regs[RD] = f32_eq(fp_regs.f32(RS1), fp_regs.f32(RS2)); fp_update_exception_flags(); } break; case Opcode::FLT_S: { fp_prepare_instr(); regs[RD] = f32_lt(fp_regs.f32(RS1), fp_regs.f32(RS2)); fp_update_exception_flags(); } break; case Opcode::FLE_S: { fp_prepare_instr(); regs[RD] = f32_le(fp_regs.f32(RS1), fp_regs.f32(RS2)); fp_update_exception_flags(); } break; case Opcode::FCLASS_S: { fp_prepare_instr(); regs[RD] = (int32_t)f32_classify(fp_regs.f32(RS1)); } break; case Opcode::FCVT_L_S: { fp_prepare_instr(); fp_setup_rm(); regs[RD] = f32_to_i64(fp_regs.f32(RS1), softfloat_roundingMode, true); fp_finish_instr(); } break; case Opcode::FCVT_LU_S: { fp_prepare_instr(); fp_setup_rm(); regs[RD] = f32_to_ui64(fp_regs.f32(RS1), softfloat_roundingMode, true); fp_finish_instr(); } break; case Opcode::FCVT_S_L: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, i64_to_f32(regs[RS1])); fp_finish_instr(); } break; case Opcode::FCVT_S_LU: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, ui64_to_f32(regs[RS1])); fp_finish_instr(); } break; case Opcode::FLD: { uint64_t addr = regs[instr.rs1()] + instr.I_imm(); trap_check_addr_alignment<8, true>(addr); fp_regs.write(RD, float64_t{(uint64_t)mem->load_double(addr)}); } break; case Opcode::FSD: { uint64_t addr = regs[instr.rs1()] + instr.S_imm(); trap_check_addr_alignment<8, false>(addr); mem->store_double(addr, fp_regs.f64(RS2).v); } break; case Opcode::FADD_D: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_add(fp_regs.f64(RS1), fp_regs.f64(RS2))); fp_finish_instr(); } break; case Opcode::FSUB_D: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_sub(fp_regs.f64(RS1), fp_regs.f64(RS2))); fp_finish_instr(); } break; case Opcode::FMUL_D: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_mul(fp_regs.f64(RS1), fp_regs.f64(RS2))); fp_finish_instr(); } break; case Opcode::FDIV_D: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_div(fp_regs.f64(RS1), fp_regs.f64(RS2))); fp_finish_instr(); } break; case Opcode::FSQRT_D: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_sqrt(fp_regs.f64(RS1))); fp_finish_instr(); } break; case Opcode::FMIN_D: { fp_prepare_instr(); bool rs1_smaller = f64_lt_quiet(fp_regs.f64(RS1), fp_regs.f64(RS2)) || (f64_eq(fp_regs.f64(RS1), fp_regs.f64(RS2)) && f64_isNegative(fp_regs.f64(RS1))); if (f64_isNaN(fp_regs.f64(RS1)) && f64_isNaN(fp_regs.f64(RS2))) { fp_regs.write(RD, f64_defaultNaN); } else { if (rs1_smaller) fp_regs.write(RD, fp_regs.f64(RS1)); else fp_regs.write(RD, fp_regs.f64(RS2)); } fp_finish_instr(); } break; case Opcode::FMAX_D: { fp_prepare_instr(); bool rs1_greater = f64_lt_quiet(fp_regs.f64(RS2), fp_regs.f64(RS1)) || (f64_eq(fp_regs.f64(RS2), fp_regs.f64(RS1)) && f64_isNegative(fp_regs.f64(RS2))); if (f64_isNaN(fp_regs.f64(RS1)) && f64_isNaN(fp_regs.f64(RS2))) { fp_regs.write(RD, f64_defaultNaN); } else { if (rs1_greater) fp_regs.write(RD, fp_regs.f64(RS1)); else fp_regs.write(RD, fp_regs.f64(RS2)); } fp_finish_instr(); } break; case Opcode::FMADD_D: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_mulAdd(fp_regs.f64(RS1), fp_regs.f64(RS2), fp_regs.f64(RS3))); fp_finish_instr(); } break; case Opcode::FMSUB_D: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_mulAdd(fp_regs.f64(RS1), fp_regs.f64(RS2), f64_neg(fp_regs.f64(RS3)))); fp_finish_instr(); } break; case Opcode::FNMADD_D: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_mulAdd(f64_neg(fp_regs.f64(RS1)), fp_regs.f64(RS2), f64_neg(fp_regs.f64(RS3)))); fp_finish_instr(); } break; case Opcode::FNMSUB_D: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_mulAdd(f64_neg(fp_regs.f64(RS1)), fp_regs.f64(RS2), fp_regs.f64(RS3))); fp_finish_instr(); } break; case Opcode::FSGNJ_D: { fp_prepare_instr(); auto f1 = fp_regs.f64(RS1); auto f2 = fp_regs.f64(RS2); fp_regs.write(RD, float64_t{(f1.v & ~F64_SIGN_BIT) | (f2.v & F64_SIGN_BIT)}); fp_set_dirty(); } break; case Opcode::FSGNJN_D: { fp_prepare_instr(); auto f1 = fp_regs.f64(RS1); auto f2 = fp_regs.f64(RS2); fp_regs.write(RD, float64_t{(f1.v & ~F64_SIGN_BIT) | (~f2.v & F64_SIGN_BIT)}); fp_set_dirty(); } break; case Opcode::FSGNJX_D: { fp_prepare_instr(); auto f1 = fp_regs.f64(RS1); auto f2 = fp_regs.f64(RS2); fp_regs.write(RD, float64_t{f1.v ^ (f2.v & F64_SIGN_BIT)}); fp_set_dirty(); } break; case Opcode::FEQ_D: { fp_prepare_instr(); regs[RD] = f64_eq(fp_regs.f64(RS1), fp_regs.f64(RS2)); fp_update_exception_flags(); } break; case Opcode::FLT_D: { fp_prepare_instr(); regs[RD] = f64_lt(fp_regs.f64(RS1), fp_regs.f64(RS2)); fp_update_exception_flags(); } break; case Opcode::FLE_D: { fp_prepare_instr(); regs[RD] = f64_le(fp_regs.f64(RS1), fp_regs.f64(RS2)); fp_update_exception_flags(); } break; case Opcode::FCLASS_D: { fp_prepare_instr(); regs[RD] = (int64_t)f64_classify(fp_regs.f64(RS1)); } break; case Opcode::FMV_D_X: { fp_prepare_instr(); fp_regs.write(RD, float64_t{(uint64_t)regs[RS1]}); fp_set_dirty(); } break; case Opcode::FMV_X_D: { fp_prepare_instr(); regs[RD] = fp_regs.f64(RS1).v; } break; case Opcode::FCVT_W_D: { fp_prepare_instr(); fp_setup_rm(); regs[RD] = f64_to_i32(fp_regs.f64(RS1), softfloat_roundingMode, true); fp_finish_instr(); } break; case Opcode::FCVT_WU_D: { fp_prepare_instr(); fp_setup_rm(); regs[RD] = (int32_t)f64_to_ui32(fp_regs.f64(RS1), softfloat_roundingMode, true); fp_finish_instr(); } break; case Opcode::FCVT_D_W: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, i32_to_f64((int32_t)regs[RS1])); fp_finish_instr(); } break; case Opcode::FCVT_D_WU: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, ui32_to_f64((int32_t)regs[RS1])); fp_finish_instr(); } break; case Opcode::FCVT_S_D: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f64_to_f32(fp_regs.f64(RS1))); fp_finish_instr(); } break; case Opcode::FCVT_D_S: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, f32_to_f64(fp_regs.f32(RS1))); fp_finish_instr(); } break; case Opcode::FCVT_L_D: { fp_prepare_instr(); fp_setup_rm(); regs[RD] = f64_to_i64(fp_regs.f64(RS1), softfloat_roundingMode, true); fp_finish_instr(); } break; case Opcode::FCVT_LU_D: { fp_prepare_instr(); fp_setup_rm(); regs[RD] = f64_to_ui64(fp_regs.f64(RS1), softfloat_roundingMode, true); fp_finish_instr(); } break; case Opcode::FCVT_D_L: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, i64_to_f64(regs[RS1])); fp_finish_instr(); } break; case Opcode::FCVT_D_LU: { fp_prepare_instr(); fp_setup_rm(); fp_regs.write(RD, ui64_to_f64(regs[RS1])); fp_finish_instr(); } break; // privileged instructions case Opcode::WFI: // NOTE: only a hint, can be implemented as NOP // std::cout << "[sim:wfi] CSR mstatus.fields.mie " << csrs.mstatus->mie << std::endl; release_lr_sc_reservation(); if (s_mode() && csrs.mstatus.fields.tw) raise_trap(EXC_ILLEGAL_INSTR, instr.data()); if (u_mode() && csrs.misa.has_supervisor_mode_extension()) raise_trap(EXC_ILLEGAL_INSTR, instr.data()); if (!ignore_wfi && !has_local_pending_enabled_interrupts()) sc_core::wait(wfi_event); break; case Opcode::SFENCE_VMA: if (s_mode() && csrs.mstatus.fields.tvm) raise_trap(EXC_ILLEGAL_INSTR, instr.data()); mem->flush_tlb(); break; case Opcode::URET: if (!csrs.misa.has_user_mode_extension()) raise_trap(EXC_ILLEGAL_INSTR, instr.data()); return_from_trap_handler(UserMode); break; case Opcode::SRET: if (!csrs.misa.has_supervisor_mode_extension() || (s_mode() && csrs.mstatus.fields.tsr)) raise_trap(EXC_ILLEGAL_INSTR, instr.data()); return_from_trap_handler(SupervisorMode); break; case Opcode::MRET: return_from_trap_handler(MachineMode); break; default: throw std::runtime_error("unknown opcode"); } } uint64_t ISS::_compute_and_get_current_cycles() { assert(cycle_counter % cycle_time == sc_core::SC_ZERO_TIME); assert(cycle_counter.value() % cycle_time.value() == 0); uint64_t num_cycles = cycle_counter.value() / cycle_time.value(); return num_cycles; } void ISS::validate_csr_counter_read_access_rights(uint64_t addr) { // match against counter CSR addresses, see RISC-V privileged spec for the address definitions if ((addr >= 0xC00 && addr <= 0xC1F)) { auto cnt = addr & 0x1F; // 32 counter in total, naturally aligned with the mcounteren and scounteren CSRs if (s_mode() && !csr::is_bitset(csrs.mcounteren, cnt)) RAISE_ILLEGAL_INSTRUCTION(); if (u_mode() && (!csr::is_bitset(csrs.mcounteren, cnt) || !csr::is_bitset(csrs.scounteren, cnt))) RAISE_ILLEGAL_INSTRUCTION(); } } uint64_t ISS::get_csr_value(uint64_t addr) { validate_csr_counter_read_access_rights(addr); auto read = [=](auto &x, uint64_t mask) { return x.reg & mask; }; using namespace csr; switch (addr) { case TIME_ADDR: case MTIME_ADDR: { uint64_t mtime = clint->update_and_get_mtime(); csrs.time.reg = mtime; return csrs.time.reg; } case MCYCLE_ADDR: csrs.cycle.reg = _compute_and_get_current_cycles(); return csrs.cycle.reg; case MINSTRET_ADDR: return csrs.instret.reg; SWITCH_CASE_MATCH_ANY_HPMCOUNTER_RV64: // not implemented return 0; // TODO: SD should be updated as SD=XS|FS and SD should be read-only -> update mask case MSTATUS_ADDR: return read(csrs.mstatus, MSTATUS_READ_MASK); case SSTATUS_ADDR: return read(csrs.mstatus, SSTATUS_READ_MASK); case USTATUS_ADDR: return read(csrs.mstatus, USTATUS_MASK); case MIP_ADDR: return read(csrs.mip, MIP_READ_MASK); case SIP_ADDR: return read(csrs.mip, SIP_MASK); case UIP_ADDR: return read(csrs.mip, UIP_MASK); case MIE_ADDR: return read(csrs.mie, MIE_MASK); case SIE_ADDR: return read(csrs.mie, SIE_MASK); case UIE_ADDR: return read(csrs.mie, UIE_MASK); case SATP_ADDR: if (csrs.mstatus.fields.tvm) RAISE_ILLEGAL_INSTRUCTION(); break; case FCSR_ADDR: return read(csrs.fcsr, FCSR_MASK); case FFLAGS_ADDR: return csrs.fcsr.fields.fflags; case FRM_ADDR: return csrs.fcsr.fields.frm; } if (!csrs.is_valid_csr64_addr(addr)) RAISE_ILLEGAL_INSTRUCTION(); return csrs.default_read64(addr); } void ISS::set_csr_value(uint64_t addr, uint64_t value) { auto write = [=](auto &x, uint64_t mask) { x.reg = (x.reg & ~mask) | (value & mask); }; using namespace csr; switch (addr) { case MISA_ADDR: // currently, read-only, thus cannot be changed at runtime SWITCH_CASE_MATCH_ANY_HPMCOUNTER_RV64: // not implemented break; case SATP_ADDR: { if (csrs.mstatus.fields.tvm) RAISE_ILLEGAL_INSTRUCTION(); auto mode = csrs.satp.fields.mode; write(csrs.satp, SATP_MASK); if (csrs.satp.fields.mode != SATP_MODE_BARE && csrs.satp.fields.mode != SATP_MODE_SV39 && csrs.satp.fields.mode != SATP_MODE_SV48) csrs.satp.fields.mode = mode; // std::cout << "[iss] satp=" << boost::format("%x") % csrs.satp.fields.reg << std::endl; } break; case MTVEC_ADDR: write(csrs.mtvec, MTVEC_MASK); break; case STVEC_ADDR: write(csrs.stvec, MTVEC_MASK); break; case UTVEC_ADDR: write(csrs.utvec, MTVEC_MASK); break; case MEPC_ADDR: write(csrs.mepc, pc_alignment_mask()); break; case SEPC_ADDR: write(csrs.sepc, pc_alignment_mask()); break; case UEPC_ADDR: write(csrs.uepc, pc_alignment_mask()); break; case MSTATUS_ADDR: write(csrs.mstatus, MSTATUS_WRITE_MASK); break; case SSTATUS_ADDR: write(csrs.mstatus, SSTATUS_WRITE_MASK); break; case USTATUS_ADDR: write(csrs.mstatus, USTATUS_MASK); break; case MIP_ADDR: write(csrs.mip, MIP_WRITE_MASK); break; case SIP_ADDR: write(csrs.mip, SIP_MASK); break; case UIP_ADDR: write(csrs.mip, UIP_MASK); break; case MIE_ADDR: write(csrs.mie, MIE_MASK); break; case SIE_ADDR: write(csrs.mie, SIE_MASK); break; case UIE_ADDR: write(csrs.mie, UIE_MASK); break; case MIDELEG_ADDR: write(csrs.mideleg, MIDELEG_MASK); break; case MEDELEG_ADDR: write(csrs.medeleg, MEDELEG_MASK); break; case SIDELEG_ADDR: write(csrs.sideleg, SIDELEG_MASK); break; case SEDELEG_ADDR: write(csrs.sedeleg, SEDELEG_MASK); break; case MCOUNTEREN_ADDR: write(csrs.mcounteren, MCOUNTEREN_MASK); break; case SCOUNTEREN_ADDR: write(csrs.scounteren, MCOUNTEREN_MASK); break; case MCOUNTINHIBIT_ADDR: write(csrs.mcountinhibit, MCOUNTINHIBIT_MASK); break; case FCSR_ADDR: write(csrs.fcsr, FCSR_MASK); break; case FFLAGS_ADDR: csrs.fcsr.fields.fflags = value; break; case FRM_ADDR: csrs.fcsr.fields.frm = value; break; default: if (!csrs.is_valid_csr64_addr(addr)) RAISE_ILLEGAL_INSTRUCTION(); csrs.default_write64(addr, value); } } void ISS::init(instr_memory_if *instr_mem, data_memory_if *data_mem, clint_if *clint, uint64_t entrypoint, uint64_t sp) { this->instr_mem = instr_mem; this->mem = data_mem; this->clint = clint; regs[RegFile::sp] = sp; pc = entrypoint; } void ISS::sys_exit() { shall_exit = true; } uint64_t ISS::read_register(unsigned idx) { return regs.read(idx); } void ISS::write_register(unsigned idx, uint64_t value) { regs.write(idx, value); } uint64_t ISS::get_progam_counter(void) { return pc; } void ISS::block_on_wfi(bool block) { ignore_wfi = !block; } CoreExecStatus ISS::get_status(void) { return status; } void ISS::set_status(CoreExecStatus s) { status = s; } void ISS::enable_debug(void) { debug_mode = true; } void ISS::insert_breakpoint(uint64_t addr) { breakpoints.insert(addr); } void ISS::remove_breakpoint(uint64_t addr) { breakpoints.erase(addr); } uint64_t ISS::get_hart_id() { return csrs.mhartid.reg; } std::vector ISS::get_registers(void) { std::vector regvals; for (int64_t v : regs.regs) regvals.push_back(v); return regvals; } void ISS::fp_finish_instr() { fp_set_dirty(); fp_update_exception_flags(); } void ISS::fp_prepare_instr() { assert(softfloat_exceptionFlags == 0); fp_require_not_off(); } void ISS::fp_set_dirty() { csrs.mstatus.fields.sd = 1; csrs.mstatus.fields.fs = FS_DIRTY; } void ISS::fp_update_exception_flags() { if (softfloat_exceptionFlags) { fp_set_dirty(); csrs.fcsr.fields.fflags |= softfloat_exceptionFlags; softfloat_exceptionFlags = 0; } } void ISS::fp_setup_rm() { auto rm = instr.frm(); if (rm == FRM_DYN) rm = csrs.fcsr.fields.frm; if (rm >= FRM_RMM) RAISE_ILLEGAL_INSTRUCTION(); softfloat_roundingMode = rm; } void ISS::fp_require_not_off() { if (csrs.mstatus.fields.fs == FS_OFF) RAISE_ILLEGAL_INSTRUCTION(); } void ISS::return_from_trap_handler(PrivilegeLevel return_mode) { switch (return_mode) { case MachineMode: prv = csrs.mstatus.fields.mpp; csrs.mstatus.fields.mie = csrs.mstatus.fields.mpie; csrs.mstatus.fields.mpie = 1; pc = csrs.mepc.reg; if (csrs.misa.has_user_mode_extension()) csrs.mstatus.fields.mpp = UserMode; else csrs.mstatus.fields.mpp = MachineMode; break; case SupervisorMode: prv = csrs.mstatus.fields.spp; csrs.mstatus.fields.sie = csrs.mstatus.fields.spie; csrs.mstatus.fields.spie = 1; pc = csrs.sepc.reg; if (csrs.misa.has_user_mode_extension()) csrs.mstatus.fields.spp = UserMode; else csrs.mstatus.fields.spp = SupervisorMode; break; case UserMode: prv = UserMode; csrs.mstatus.fields.uie = csrs.mstatus.fields.upie; csrs.mstatus.fields.upie = 1; pc = csrs.uepc.reg; break; default: throw std::runtime_error("unknown privilege level " + std::to_string(return_mode)); } if (trace) printf("[vp::iss] return from trap handler, time %s, pc %16lx, prv %1x\n", quantum_keeper.get_current_time().to_string().c_str(), pc, prv); } void ISS::trigger_external_interrupt(PrivilegeLevel level) { if (trace) std::cout << "[vp::iss] trigger external interrupt, " << sc_core::sc_time_stamp() << std::endl; switch (level) { case UserMode: csrs.mip.fields.ueip = true; break; case SupervisorMode: csrs.mip.fields.seip = true; break; case MachineMode: csrs.mip.fields.meip = true; break; } wfi_event.notify(sc_core::SC_ZERO_TIME); } void ISS::clear_external_interrupt(PrivilegeLevel level) { if (trace) std::cout << "[vp::iss] clear external interrupt, " << sc_core::sc_time_stamp() << std::endl; switch (level) { case UserMode: csrs.mip.fields.ueip = false; break; case SupervisorMode: csrs.mip.fields.seip = false; break; case MachineMode: csrs.mip.fields.meip = false; break; } } void ISS::trigger_timer_interrupt(bool status) { if (trace) std::cout << "[vp::iss] trigger timer interrupt=" << status << ", " << sc_core::sc_time_stamp() << std::endl; csrs.mip.fields.mtip = status; wfi_event.notify(sc_core::SC_ZERO_TIME); } void ISS::trigger_software_interrupt(bool status) { if (trace) std::cout << "[vp::iss] trigger software interrupt=" << status << ", " << sc_core::sc_time_stamp() << std::endl; csrs.mip.fields.msip = status; wfi_event.notify(sc_core::SC_ZERO_TIME); } PrivilegeLevel ISS::prepare_trap(SimulationTrap &e) { // undo any potential pc update (for traps the pc should point to the originating instruction and not it's // successor) pc = last_pc; unsigned exc_bit = (1 << e.reason); // 1) machine mode execution takes any traps, independent of delegation setting // 2) non-delegated traps are processed in machine mode, independent of current execution mode if (prv == MachineMode || !(exc_bit & csrs.medeleg.reg)) { csrs.mcause.fields.interrupt = 0; csrs.mcause.fields.exception_code = e.reason; csrs.mtval.reg = e.mtval; return MachineMode; } // see above machine mode comment if (prv == SupervisorMode || !(exc_bit & csrs.sedeleg.reg)) { csrs.scause.fields.interrupt = 0; csrs.scause.fields.exception_code = e.reason; csrs.stval.reg = e.mtval; return SupervisorMode; } assert(prv == UserMode && (exc_bit & csrs.medeleg.reg) && (exc_bit & csrs.sedeleg.reg)); csrs.ucause.fields.interrupt = 0; csrs.ucause.fields.exception_code = e.reason; csrs.utval.reg = e.mtval; return UserMode; } void ISS::prepare_interrupt(const PendingInterrupts &e) { if (trace) { std::cout << "[vp::iss] prepare interrupt, pending=" << e.pending << ", target-mode=" << e.target_mode << std::endl; } csr_mip x{e.pending}; ExceptionCode exc; if (x.fields.meip) exc = EXC_M_EXTERNAL_INTERRUPT; else if (x.fields.msip) exc = EXC_M_SOFTWARE_INTERRUPT; else if (x.fields.mtip) exc = EXC_M_TIMER_INTERRUPT; else if (x.fields.seip) exc = EXC_S_EXTERNAL_INTERRUPT; else if (x.fields.ssip) exc = EXC_S_SOFTWARE_INTERRUPT; else if (x.fields.stip) exc = EXC_S_TIMER_INTERRUPT; else if (x.fields.ueip) exc = EXC_U_EXTERNAL_INTERRUPT; else if (x.fields.usip) exc = EXC_U_SOFTWARE_INTERRUPT; else if (x.fields.utip) exc = EXC_U_TIMER_INTERRUPT; else throw std::runtime_error("some pending interrupt must be available here"); switch (e.target_mode) { case MachineMode: csrs.mcause.fields.exception_code = exc; csrs.mcause.fields.interrupt = 1; break; case SupervisorMode: csrs.scause.fields.exception_code = exc; csrs.scause.fields.interrupt = 1; break; case UserMode: csrs.ucause.fields.exception_code = exc; csrs.ucause.fields.interrupt = 1; break; default: throw std::runtime_error("unknown privilege level " + std::to_string(e.target_mode)); } } PendingInterrupts ISS::compute_pending_interrupts() { uint64_t pending = csrs.mie.reg & csrs.mip.reg; if (!pending) return {NoneMode, 0}; auto m_pending = pending & ~csrs.mideleg.reg; if (m_pending && (prv < MachineMode || (prv == MachineMode && csrs.mstatus.fields.mie))) { return {MachineMode, m_pending}; } pending = pending & csrs.mideleg.reg; auto s_pending = pending & ~csrs.sideleg.reg; if (s_pending && (prv < SupervisorMode || (prv == SupervisorMode && csrs.mstatus.fields.sie))) { return {SupervisorMode, s_pending}; } auto u_pending = pending & csrs.sideleg.reg; if (u_pending && (prv == UserMode && csrs.mstatus.fields.uie)) { return {UserMode, u_pending}; } return {NoneMode, 0}; } void ISS::switch_to_trap_handler(PrivilegeLevel target_mode) { if (trace) { printf("[vp::iss] switch to trap handler, time %s, last_pc %16lx, pc %16lx, irq %u, t-prv %1x\n", quantum_keeper.get_current_time().to_string().c_str(), last_pc, pc, csrs.mcause.fields.interrupt, target_mode); } // free any potential LR/SC bus lock before processing a trap/interrupt release_lr_sc_reservation(); auto pp = prv; prv = target_mode; switch (target_mode) { case MachineMode: csrs.mepc.reg = pc; csrs.mstatus.fields.mpie = csrs.mstatus.fields.mie; csrs.mstatus.fields.mie = 0; csrs.mstatus.fields.mpp = pp; pc = csrs.mtvec.get_base_address(); if (csrs.mcause.fields.interrupt && csrs.mtvec.fields.mode == csr_mtvec::Mode::Vectored) pc += 4 * csrs.mcause.fields.exception_code; break; case SupervisorMode: assert(prv == SupervisorMode || prv == UserMode); csrs.sepc.reg = pc; csrs.mstatus.fields.spie = csrs.mstatus.fields.sie; csrs.mstatus.fields.sie = 0; csrs.mstatus.fields.spp = pp; pc = csrs.stvec.get_base_address(); if (csrs.scause.fields.interrupt && csrs.stvec.fields.mode == csr_mtvec::Mode::Vectored) pc += 4 * csrs.scause.fields.exception_code; break; case UserMode: assert(prv == UserMode); csrs.uepc.reg = pc; csrs.mstatus.fields.upie = csrs.mstatus.fields.uie; csrs.mstatus.fields.uie = 0; pc = csrs.utvec.get_base_address(); if (csrs.ucause.fields.interrupt && csrs.utvec.fields.mode == csr_mtvec::Mode::Vectored) pc += 4 * csrs.ucause.fields.exception_code; break; default: throw std::runtime_error("unknown privilege level " + std::to_string(target_mode)); } } void ISS::performance_and_sync_update(Opcode::Mapping executed_op) { if (!csrs.mcountinhibit.fields.IR) ++csrs.instret.reg; if (lr_sc_counter != 0) { --lr_sc_counter; assert (lr_sc_counter >= 0); if (lr_sc_counter == 0) release_lr_sc_reservation(); } auto new_cycles = instr_cycles[executed_op]; if (!csrs.mcountinhibit.fields.CY) cycle_counter += new_cycles; quantum_keeper.inc(new_cycles); if (quantum_keeper.need_sync()) { if (lr_sc_counter == 0) // match SystemC sync with bus unlocking in a tight LR_W/SC_W loop quantum_keeper.sync(); } } void ISS::run_step() { assert(regs.read(0) == 0); // speeds up the execution performance (non debug mode) significantly by // checking the additional flag first if (debug_mode && (breakpoints.find(pc) != breakpoints.end())) { status = CoreExecStatus::HitBreakpoint; return; } last_pc = pc; try { exec_step(); auto x = compute_pending_interrupts(); if (x.target_mode != NoneMode) { prepare_interrupt(x); switch_to_trap_handler(x.target_mode); } } catch (SimulationTrap &e) { if (trace) std::cout << "take trap " << e.reason << ", mtval=" << boost::format("%x") % e.mtval << ", pc=" << boost::format("%x") % last_pc << std::endl; auto target_mode = prepare_trap(e); switch_to_trap_handler(target_mode); } // NOTE: writes to zero register are supposedly allowed but must be ignored // (reset it after every instruction, instead of checking *rd != zero* // before every register write) regs.regs[regs.zero] = 0; // Do not use a check *pc == last_pc* here. The reason is that due to // interrupts *pc* can be set to *last_pc* accidentally (when jumping back // to *mepc*). if (shall_exit) status = CoreExecStatus::Terminated; performance_and_sync_update(op); } void ISS::run() { // run a single step until either a breakpoint is hit or the execution terminates do { run_step(); } while (status == CoreExecStatus::Runnable); // force sync to make sure that no action is missed quantum_keeper.sync(); } void ISS::show() { boost::io::ios_flags_saver ifs(std::cout); std::cout << "=[ core : " << csrs.mhartid.reg << " ]===========================" << std::endl; std::cout << "simulation time: " << sc_core::sc_time_stamp() << std::endl; regs.show(); std::cout << "pc = " << std::hex << pc << std::endl; std::cout << "num-instr = " << std::dec << csrs.instret.reg << std::endl; } ================================================ FILE: vp/src/core/rv64/iss.h ================================================ #pragma once #include "core/common/bus_lock_if.h" #include "core/common/clint_if.h" #include "core/common/core_defs.h" #include "core/common/instr.h" #include "core/common/irq_if.h" #include "core/common/trap.h" #include "csr.h" #include "fp.h" #include "mem_if.h" #include "syscall_if.h" #include "util/common.h" #include "debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace rv64 { struct RegFile { static constexpr unsigned NUM_REGS = 32; int64_t regs[NUM_REGS]; RegFile(); RegFile(const RegFile &other); void write(uint64_t index, int64_t value); int64_t read(uint64_t index); uint64_t shamt_w(uint64_t index); uint64_t shamt(uint64_t index); int64_t &operator[](const uint64_t idx); void show(); enum e { x0 = 0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, zero = x0, ra = x1, sp = x2, gp = x3, tp = x4, t0 = x5, t1 = x6, t2 = x7, s0 = x8, fp = x8, s1 = x9, a0 = x10, a1 = x11, a2 = x12, a3 = x13, a4 = x14, a5 = x15, a6 = x16, a7 = x17, s2 = x18, s3 = x19, s4 = x20, s5 = x21, s6 = x22, s7 = x23, s8 = x24, s9 = x25, s10 = x26, s11 = x27, t3 = x28, t4 = x29, t5 = x30, t6 = x31, }; }; // NOTE: on this branch, currently the *simple-timing* model is still directly // integrated in the ISS. Merge the *timedb* branch to use the timing_if. struct ISS; struct timing_if { virtual ~timing_if() {} virtual void update_timing(Instruction instr, Opcode::Mapping op, ISS &iss) = 0; }; struct PendingInterrupts { PrivilegeLevel target_mode; uint64_t pending; }; struct ISS : public external_interrupt_target, public clint_interrupt_target, public debug_target_if, public iss_syscall_if { clint_if *clint = nullptr; instr_memory_if *instr_mem = nullptr; data_memory_if *mem = nullptr; syscall_emulator_if *sys = nullptr; // optional, if provided, the iss will intercept and handle syscalls directly RegFile regs; FpRegs fp_regs; uint64_t pc = 0; uint64_t last_pc = 0; bool trace = false; bool shall_exit = false; bool ignore_wfi = false; csr_table csrs; PrivilegeLevel prv = MachineMode; int64_t lr_sc_counter = 0; // last decoded and executed instruction and opcode Instruction instr; Opcode::Mapping op; CoreExecStatus status = CoreExecStatus::Runnable; std::unordered_set breakpoints; bool debug_mode = false; sc_core::sc_event wfi_event; std::string systemc_name; tlm_utils::tlm_quantumkeeper quantum_keeper; sc_core::sc_time cycle_time; sc_core::sc_time cycle_counter; // use a separate cycle counter, since cycle count can be inhibited std::array instr_cycles; static constexpr int64_t REG_MIN = INT64_MIN; static constexpr int64_t REG32_MIN = INT32_MIN; static constexpr unsigned xlen = 64; ISS(uint64_t hart_id); Architecture get_architecture(void) override { return RV64; } uint64_t get_progam_counter(void) override; void enable_debug(void) override; CoreExecStatus get_status(void) override; void set_status(CoreExecStatus) override; void block_on_wfi(bool) override; void insert_breakpoint(uint64_t) override; void remove_breakpoint(uint64_t) override; void exec_step(); uint64_t _compute_and_get_current_cycles(); void init(instr_memory_if *instr_mem, data_memory_if *data_mem, clint_if *clint, uint64_t entrypoint, uint64_t sp); void trigger_external_interrupt(PrivilegeLevel level) override; void clear_external_interrupt(PrivilegeLevel level) override; void trigger_timer_interrupt(bool status) override; void trigger_software_interrupt(bool status) override; void sys_exit() override; uint64_t read_register(unsigned idx) override; void write_register(unsigned idx, uint64_t value) override; uint64_t get_hart_id() override; std::vector get_registers(void) override; void release_lr_sc_reservation() { lr_sc_counter = 0; mem->atomic_unlock(); } void fp_prepare_instr(); void fp_finish_instr(); void fp_set_dirty(); void fp_update_exception_flags(); void fp_setup_rm(); void fp_require_not_off(); uint64_t get_csr_value(uint64_t addr); void set_csr_value(uint64_t addr, uint64_t value); inline bool is_invalid_csr_access(uint64_t csr_addr, bool is_write) { PrivilegeLevel csr_prv = (0x300 & csr_addr) >> 8; bool csr_readonly = ((0xC00 & csr_addr) >> 10) == 3; return (is_write && csr_readonly) || (prv < csr_prv); } void validate_csr_counter_read_access_rights(uint64_t addr); uint64_t pc_alignment_mask() { if (csrs.misa.has_C_extension()) return ~uint64_t(0x1); else return ~uint64_t(0x3); } inline void trap_check_pc_alignment() { assert(!(pc & 0x1) && "not possible due to immediate formats and jump execution"); if (unlikely((pc & 0x3) && (!csrs.misa.has_C_extension()))) { // NOTE: misaligned instruction address not possible on machines supporting compressed instructions raise_trap(EXC_INSTR_ADDR_MISALIGNED, pc); } } template inline void trap_check_addr_alignment(uint64_t addr) { if (unlikely(addr % Alignment)) { raise_trap(isLoad ? EXC_LOAD_ADDR_MISALIGNED : EXC_STORE_AMO_ADDR_MISALIGNED, addr); } } inline void execute_amo_w(Instruction &instr, std::function operation) { uint64_t addr = regs[instr.rs1()]; trap_check_addr_alignment<4, false>(addr); int32_t data; try { data = mem->atomic_load_word(addr); } catch (SimulationTrap &e) { if (e.reason == EXC_LOAD_ACCESS_FAULT) e.reason = EXC_STORE_AMO_ACCESS_FAULT; throw e; } int32_t val = operation(data, (int32_t)regs[instr.rs2()]); mem->atomic_store_word(addr, val); regs[instr.rd()] = data; } inline void execute_amo_d(Instruction &instr, std::function operation) { uint64_t addr = regs[instr.rs1()]; trap_check_addr_alignment<8, false>(addr); uint64_t data; try { data = mem->atomic_load_double(addr); } catch (SimulationTrap &e) { if (e.reason == EXC_LOAD_ACCESS_FAULT) e.reason = EXC_STORE_AMO_ACCESS_FAULT; throw e; } uint64_t val = operation(data, regs[instr.rs2()]); mem->atomic_store_double(addr, val); regs[instr.rd()] = data; } inline bool m_mode() { return prv == MachineMode; } inline bool s_mode() { return prv == SupervisorMode; } inline bool u_mode() { return prv == UserMode; } PrivilegeLevel prepare_trap(SimulationTrap &e); void prepare_interrupt(const PendingInterrupts &x); PendingInterrupts compute_pending_interrupts(); bool has_pending_enabled_interrupts() { return compute_pending_interrupts().target_mode != NoneMode; } bool has_local_pending_enabled_interrupts() { return csrs.mie.reg & csrs.mip.reg; } void return_from_trap_handler(PrivilegeLevel return_mode); void switch_to_trap_handler(PrivilegeLevel target_mode); void performance_and_sync_update(Opcode::Mapping executed_op); void run_step() override; void run() override; void show(); }; /* Do not call the run function of the ISS directly but use one of the Runner * wrappers. */ struct DirectCoreRunner : public sc_core::sc_module { ISS &core; std::string thread_name; SC_HAS_PROCESS(DirectCoreRunner); DirectCoreRunner(ISS &core) : sc_module(sc_core::sc_module_name(core.systemc_name.c_str())), core(core) { thread_name = "run" + std::to_string(core.get_hart_id()); SC_NAMED_THREAD(run, thread_name.c_str()); } void run() { core.run(); if (core.status == CoreExecStatus::HitBreakpoint) { throw std::runtime_error( "Breakpoints are not supported in the direct runner, use the debug " "runner instead."); } assert(core.status == CoreExecStatus::Terminated); sc_core::sc_stop(); } }; } // namespace rv64 ================================================ FILE: vp/src/core/rv64/mem.h ================================================ #pragma once #include "core/common/dmi.h" #include "iss.h" #include "mmu.h" namespace rv64 { /* For optimization, use DMI to fetch instructions */ struct InstrMemoryProxy : public instr_memory_if { MemoryDMI dmi; ISS &core; tlm_utils::tlm_quantumkeeper &quantum_keeper; sc_core::sc_time clock_cycle = sc_core::sc_time(10, sc_core::SC_NS); sc_core::sc_time access_delay = clock_cycle * 2; InstrMemoryProxy(const MemoryDMI &dmi, ISS &owner) : dmi(dmi), core(owner), quantum_keeper(owner.quantum_keeper) {} virtual uint32_t load_instr(uint64_t pc) override { assert((core.csrs.satp.fields.mode == SATP_MODE_BARE) && "InstrMemoryProxy does not support virtual memory"); quantum_keeper.inc(access_delay); return *(dmi.get_mem_ptr_to_global_addr(pc)); } }; struct CombinedMemoryInterface : public sc_core::sc_module, public instr_memory_if, public data_memory_if, public mmu_memory_if { ISS &iss; std::shared_ptr bus_lock; uint64_t lr_addr = 0; tlm_utils::simple_initiator_socket isock; tlm_utils::tlm_quantumkeeper &quantum_keeper; // optionally add DMI ranges for optimization sc_core::sc_time clock_cycle = sc_core::sc_time(10, sc_core::SC_NS); sc_core::sc_time dmi_access_delay = clock_cycle * 4; std::vector dmi_ranges; MMU &mmu; CombinedMemoryInterface(sc_core::sc_module_name, ISS &owner, MMU &mmu) : iss(owner), quantum_keeper(iss.quantum_keeper), mmu(mmu) {} uint64_t v2p(uint64_t vaddr, MemoryAccessType type) override { return mmu.translate_virtual_to_physical_addr(vaddr, type); } inline void _do_transaction(tlm::tlm_command cmd, uint64_t addr, uint8_t *data, unsigned num_bytes) { tlm::tlm_generic_payload trans; trans.set_command(cmd); trans.set_address(addr); trans.set_data_ptr(data); trans.set_data_length(num_bytes); trans.set_response_status(tlm::TLM_OK_RESPONSE); sc_core::sc_time local_delay = quantum_keeper.get_local_time(); isock->b_transport(trans, local_delay); assert(local_delay >= quantum_keeper.get_local_time()); quantum_keeper.set(local_delay); if (trans.is_response_error()) { if (iss.trace) std::cout << "WARNING: core memory transaction failed for address 0x" << std::hex << addr << std::dec << " -> raise trap" << std::endl; if (cmd == tlm::TLM_READ_COMMAND) raise_trap(EXC_LOAD_PAGE_FAULT, addr); else if (cmd == tlm::TLM_WRITE_COMMAND) raise_trap(EXC_STORE_AMO_PAGE_FAULT, addr); else throw std::runtime_error("TLM command must be read or write"); } } template inline T _raw_load_data(uint64_t addr) { // NOTE: a DMI load will not context switch (SystemC) and not modify the memory, hence should be able to // postpone the lock after the dmi access bus_lock->wait_for_access_rights(iss.get_hart_id()); for (auto &e : dmi_ranges) { if (e.contains(addr)) { quantum_keeper.inc(dmi_access_delay); T ans = *(e.get_mem_ptr_to_global_addr(addr)); return ans; } } T ans; _do_transaction(tlm::TLM_READ_COMMAND, addr, (uint8_t *)&ans, sizeof(T)); return ans; } template inline void _raw_store_data(uint64_t addr, T value) { bus_lock->wait_for_access_rights(iss.get_hart_id()); bool done = false; for (auto &e : dmi_ranges) { if (e.contains(addr)) { quantum_keeper.inc(dmi_access_delay); *(e.get_mem_ptr_to_global_addr(addr)) = value; done = true; } } if (!done) _do_transaction(tlm::TLM_WRITE_COMMAND, addr, (uint8_t *)&value, sizeof(T)); atomic_unlock(); } template inline T _load_data(uint64_t addr) { return _raw_load_data(v2p(addr, LOAD)); } template inline void _store_data(uint64_t addr, T value) { _raw_store_data(v2p(addr, STORE), value); } uint64_t mmu_load_pte64(uint64_t addr) override { return _raw_load_data(addr); } uint64_t mmu_load_pte32(uint64_t addr) override { return _raw_load_data(addr); } void mmu_store_pte32(uint64_t addr, uint32_t value) override { _raw_store_data(addr, value); } void flush_tlb() override { mmu.flush_tlb(); } uint32_t load_instr(uint64_t addr) override { return _raw_load_data(v2p(addr, FETCH)); } template T _atomic_load_data(uint64_t addr) { bus_lock->lock(iss.get_hart_id()); return _load_data(addr); } template void _atomic_store_data(uint64_t addr, T value) { assert(bus_lock->is_locked(iss.get_hart_id())); _store_data(addr, value); } template T _atomic_load_reserved_data(uint64_t addr) { bus_lock->lock(iss.get_hart_id()); lr_addr = addr; return _load_data(addr); } template bool _atomic_store_conditional_data(uint64_t addr, T value) { /* According to the RISC-V ISA, an implementation can fail each LR/SC sequence that does not satisfy the forward * progress semantic. * The lock is established by the LR instruction and the lock is kept while forward progress is maintained. */ if (bus_lock->is_locked(iss.get_hart_id())) { if (addr == lr_addr) { _store_data(addr, value); return true; } atomic_unlock(); } return false; } int64_t load_double(uint64_t addr) override { return _load_data(addr); } int64_t load_word(uint64_t addr) override { return _load_data(addr); } int64_t load_half(uint64_t addr) override { return _load_data(addr); } int64_t load_byte(uint64_t addr) override { return _load_data(addr); } uint64_t load_uword(uint64_t addr) override { return _load_data(addr); } uint64_t load_uhalf(uint64_t addr) override { return _load_data(addr); } uint64_t load_ubyte(uint64_t addr) override { return _load_data(addr); } void store_double(uint64_t addr, uint64_t value) override { _store_data(addr, value); } void store_word(uint64_t addr, uint32_t value) override { _store_data(addr, value); } void store_half(uint64_t addr, uint16_t value) override { _store_data(addr, value); } void store_byte(uint64_t addr, uint8_t value) override { _store_data(addr, value); } int64_t atomic_load_word(uint64_t addr) override { return _atomic_load_data(addr); } void atomic_store_word(uint64_t addr, uint32_t value) override { _atomic_store_data(addr, value); } int64_t atomic_load_reserved_word(uint64_t addr) override { return _atomic_load_reserved_data(addr); } bool atomic_store_conditional_word(uint64_t addr, uint32_t value) override { return _atomic_store_conditional_data(addr, value); } int64_t atomic_load_double(uint64_t addr) override { return _atomic_load_data(addr); } void atomic_store_double(uint64_t addr, uint64_t value) override { _atomic_store_data(addr, value); } int64_t atomic_load_reserved_double(uint64_t addr) override { return _atomic_load_reserved_data(addr); } bool atomic_store_conditional_double(uint64_t addr, uint64_t value) override { return _atomic_store_conditional_data(addr, value); } void atomic_unlock() override { bus_lock->unlock(iss.get_hart_id()); } }; } // namespace rv64 ================================================ FILE: vp/src/core/rv64/mem_if.h ================================================ #pragma once #include namespace rv64 { struct instr_memory_if { virtual ~instr_memory_if() {} virtual uint32_t load_instr(uint64_t pc) = 0; }; struct data_memory_if { virtual ~data_memory_if() {} virtual int64_t load_double(uint64_t addr) = 0; virtual int64_t load_word(uint64_t addr) = 0; virtual int64_t load_half(uint64_t addr) = 0; virtual int64_t load_byte(uint64_t addr) = 0; virtual uint64_t load_uword(uint64_t addr) = 0; virtual uint64_t load_uhalf(uint64_t addr) = 0; virtual uint64_t load_ubyte(uint64_t addr) = 0; virtual void store_double(uint64_t addr, uint64_t value) = 0; virtual void store_word(uint64_t addr, uint32_t value) = 0; virtual void store_half(uint64_t addr, uint16_t value) = 0; virtual void store_byte(uint64_t addr, uint8_t value) = 0; virtual int64_t atomic_load_word(uint64_t addr) = 0; virtual void atomic_store_word(uint64_t addr, uint32_t value) = 0; virtual int64_t atomic_load_reserved_word(uint64_t addr) = 0; virtual bool atomic_store_conditional_word(uint64_t addr, uint32_t value) = 0; virtual void atomic_unlock() = 0; virtual int64_t atomic_load_double(uint64_t addr) = 0; virtual void atomic_store_double(uint64_t addr, uint64_t value) = 0; virtual int64_t atomic_load_reserved_double(uint64_t addr) = 0; virtual bool atomic_store_conditional_double(uint64_t addr, uint64_t value) = 0; virtual void flush_tlb() = 0; }; } // namespace rv64 ================================================ FILE: vp/src/core/rv64/mmu.h ================================================ #pragma once #include "iss.h" #include "core/common/mmu.h" namespace rv64 { typedef GenericMMU MMU; } // namespace rv64 ================================================ FILE: vp/src/core/rv64/syscall.cpp ================================================ #include "syscall.h" #include #include #include #include #include #include #include #include using namespace rv64; // see: riscv-gnu-toolchain/riscv-newlib/libgloss/riscv/ // for syscall implementation in the risc-v C lib (many are ignored and just return -1) typedef int64_t rv64_long; typedef int64_t rv64_time_t; struct rv64_timeval { rv64_time_t tv_sec; rv64_time_t tv_usec; }; struct rv64_timespec { rv64_time_t tv_sec; rv64_time_t tv_nsec; }; struct rv64_stat { uint64_t st_dev; uint64_t st_ino; uint32_t st_mode; uint32_t st_nlink; uint32_t st_uid; uint32_t st_gid; uint64_t st_rdev; uint64_t __pad1; int64_t st_size; int32_t st_blksize; int32_t __pad2; int64_t st_blocks; rv64_timespec st_atim; rv64_timespec st_mtim; rv64_timespec st_ctim; int32_t __glibc_reserved[2]; }; void _copy_timespec(rv64_timespec *dst, timespec *src) { dst->tv_sec = src->tv_sec; dst->tv_nsec = src->tv_nsec; } int sys_fstat(SyscallHandler *sys, int fd, rv64_stat *s_addr) { struct stat x; int ans = fstat(fd, &x); if (ans == 0) { rv64_stat *p = (rv64_stat *)sys->guest_to_host_pointer(s_addr); p->st_dev = x.st_dev; p->st_ino = x.st_ino; p->st_mode = x.st_mode; p->st_nlink = x.st_nlink; p->st_uid = x.st_uid; p->st_gid = x.st_gid; p->st_rdev = x.st_rdev; p->st_size = x.st_size; p->st_blksize = x.st_blksize; p->st_blocks = x.st_blocks; _copy_timespec(&p->st_atim, &x.st_atim); _copy_timespec(&p->st_mtim, &x.st_mtim); _copy_timespec(&p->st_ctim, &x.st_ctim); } return ans; } int sys_gettimeofday(SyscallHandler *sys, rv64_timeval *tp, void *tzp) { /* * timeval is using a struct with two long arguments. * The second argument tzp currently is not used by riscv code. */ assert(tzp == 0); struct timeval x; int ans = gettimeofday(&x, 0); rv64_long *p = (rv64_long *)sys->guest_to_host_pointer(tp); p[0] = x.tv_sec; p[1] = x.tv_usec; return ans; } int sys_time(SyscallHandler *sys, rv64_time_t *tloc) { time_t host_ans = time(0); rv64_time_t guest_ans = boost::lexical_cast(host_ans); if (tloc != 0) { rv64_time_t *p = (rv64_time_t *)sys->guest_to_host_pointer(tloc); *p = guest_ans; } return boost::lexical_cast(guest_ans); } namespace rv_sc { // see: riscv-gnu-toolchain/riscv/riscv32-unknown-elf/include/sys/_default_fcntl.h constexpr uint32_t RDONLY = 0x0000; /* +1 == FREAD */ constexpr uint32_t WRONLY = 0x0001; /* +1 == FWRITE */ constexpr uint32_t RDWR = 0x0002; /* +1 == FREAD|FWRITE */ constexpr uint32_t APPEND = 0x0008; constexpr uint32_t CREAT = 0x0200; constexpr uint32_t TRUNC = 0x0400; } // namespace rv_sc int translateRVFlagsToHost(const int flags) { int ret = 0; ret |= flags & rv_sc::RDONLY ? O_RDONLY : 0; ret |= flags & rv_sc::WRONLY ? O_WRONLY : 0; ret |= flags & rv_sc::RDWR ? O_RDWR : 0; ret |= flags & rv_sc::APPEND ? O_APPEND : 0; ret |= flags & rv_sc::CREAT ? O_CREAT : 0; ret |= flags & rv_sc::TRUNC ? O_TRUNC : 0; if (ret == 0 && flags != 0) { throw std::runtime_error("unsupported flag"); } return ret; } int sys_brk(SyscallHandler *sys, void *addr) { if (addr == 0) { // riscv newlib expects brk to return current heap address when zero is passed in return boost::lexical_cast(sys->hp); } else { // NOTE: can also shrink again auto n = (uintptr_t)addr; sys->hp = n; if (sys->hp > sys->max_heap) sys->max_heap = sys->hp; // same for brk increase/decrease return boost::lexical_cast(n); } } int sys_write(SyscallHandler *sys, int fd, const void *buf, size_t count) { const char *p = (const char *)sys->guest_to_host_pointer((void *)buf); auto ans = write(fd, p, count); if (ans < 0) { std::cout << "WARNING [sys-write error]: " << strerror(errno) << std::endl; std::cout << " fd = " << fd << std::endl; std::cout << " count = " << count << std::endl; assert(false); } return ans; } int sys_read(SyscallHandler *sys, int fd, void *buf, size_t count) { char *p = (char *)sys->guest_to_host_pointer(buf); auto ans = read(fd, p, count); assert(ans >= 0); return ans; } int sys_lseek(int fd, off_t offset, int whence) { auto ans = lseek(fd, offset, whence); return ans; } int sys_open(SyscallHandler *sys, const char *pathname, int flags, mode_t mode) { const char *host_pathname = (char *)sys->guest_to_host_pointer((void *)pathname); auto ans = open(host_pathname, translateRVFlagsToHost(flags), mode); std::cout << "[sys_open] " << host_pathname << ", " << flags << " (translated to " << translateRVFlagsToHost(flags) << "), " << mode << std::endl; return ans; } int sys_close(int fd) { if (fd == STDOUT_FILENO || fd == STDIN_FILENO || fd == STDERR_FILENO) { // ignore closing of std streams, just return success return 0; } else { return close(fd); } } // TODO: add support for additional syscalls if necessary int SyscallHandler::execute_syscall(uint64_t n, uint64_t _a0, uint64_t _a1, uint64_t _a2, uint64_t) { // NOTE: when linking with CRT, the most basic example only calls *gettimeofday* and finally *exit* switch (n) { case SYS_fstat: return sys_fstat(this, _a0, (rv64_stat *)_a1); case SYS_gettimeofday: return sys_gettimeofday(this, (rv64_timeval *)_a0, (void *)_a1); case SYS_brk: return sys_brk(this, (void *)_a0); case SYS_time: return sys_time(this, (rv64_time_t *)_a0); case SYS_write: return sys_write(this, _a0, (void *)_a1, _a2); case SYS_read: return sys_read(this, _a0, (void *)_a1, _a2); case SYS_lseek: return sys_lseek(_a0, _a1, _a2); case SYS_open: return sys_open(this, (const char *)_a0, _a1, _a2); case SYS_close: return sys_close(_a0); case SYS_exit: // If the software requested a non-zero exit code then terminate directly. // Otherwise, stop the SystemC simulation and exit with a zero exit code. if (_a0) exit(_a0); shall_exit = true; return 0; case SYS_host_error: throw std::runtime_error("SYS_host_error"); case SYS_host_test_pass: std::cout << "TEST_PASS" << std::endl; shall_exit = true; return 0; case SYS_host_test_fail: std::cout << "TEST_FAIL (testnum = " << _a0 << ")" << std::endl; shall_exit = true; return 0; } std::cerr << "unsupported syscall '" << n << "'" << std::endl; throw std::runtime_error("unsupported syscall '" + std::to_string(n) + "'"); } ================================================ FILE: vp/src/core/rv64/syscall.h ================================================ #pragma once #include #include #include // see: newlib/libgloss/riscv @ // https://github.com/riscv/riscv-newlib/tree/riscv-newlib-2.5.0/libgloss/riscv #define SYS_exit 93 #define SYS_exit_group 94 #define SYS_getpid 172 #define SYS_kill 129 #define SYS_read 63 #define SYS_write 64 #define SYS_open 1024 #define SYS_openat 56 #define SYS_close 57 #define SYS_lseek 62 #define SYS_brk 214 #define SYS_link 1025 #define SYS_unlink 1026 #define SYS_mkdir 1030 #define SYS_chdir 49 #define SYS_getcwd 17 #define SYS_stat 1038 #define SYS_fstat 80 #define SYS_lstat 1039 #define SYS_fstatat 79 #define SYS_access 1033 #define SYS_faccessat 48 #define SYS_pread 67 #define SYS_pwrite 68 #define SYS_uname 160 #define SYS_getuid 174 #define SYS_geteuid 175 #define SYS_getgid 176 #define SYS_getegid 177 #define SYS_mmap 222 #define SYS_munmap 215 #define SYS_mremap 216 #define SYS_time 1062 #define SYS_getmainvars 2011 #define SYS_rt_sigaction 134 #define SYS_writev 66 #define SYS_gettimeofday 169 #define SYS_times 153 #define SYS_fcntl 25 #define SYS_getdents 61 #define SYS_dup 23 // custom extensions #define SYS_host_error \ 1 // indicate an error, i.e. this instruction should never be reached so something went wrong during exec. #define SYS_host_test_pass 2 // RISC-V test execution successfully completed #define SYS_host_test_fail 3 // RISC-V test execution failed #include #include #include "iss.h" #include "syscall_if.h" namespace rv64 { struct SyscallHandler : public sc_core::sc_module, syscall_emulator_if { tlm_utils::simple_target_socket tsock; std::unordered_map cores; void register_core(ISS *core) { assert(cores.find(core->get_hart_id()) == cores.end()); cores[core->get_hart_id()] = core; } SyscallHandler(sc_core::sc_module_name) { tsock.register_b_transport(this, &SyscallHandler::transport); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { (void)delay; auto addr = trans.get_address(); assert(addr % 4 == 0); assert(trans.get_data_length() == 4); auto hart_id = *((uint32_t *)trans.get_data_ptr()); assert((cores.find(hart_id) != cores.end()) && "core not registered in syscall handler"); execute_syscall(cores[hart_id]); } virtual void execute_syscall(iss_syscall_if *core) override { auto a7 = core->read_register(RegFile::a7); auto a3 = core->read_register(RegFile::a3); auto a2 = core->read_register(RegFile::a2); auto a1 = core->read_register(RegFile::a1); auto a0 = core->read_register(RegFile::a0); // printf("a7=%u, a0=%u, a1=%u, a2=%u, a3=%u\n", a7, a0, a1, a2, a3); auto ans = execute_syscall(a7, a0, a1, a2, a3); core->write_register(RegFile::a0, ans); if (shall_exit) core->sys_exit(); } uint8_t *mem = 0; // direct pointer to start of guest memory in host memory uint64_t mem_offset; // start address of the memory as mapped into the // address space uint64_t hp = 0; // heap pointer bool shall_exit = false; bool shall_break = false; // only for memory consumption evaluation uint64_t start_heap = 0; uint64_t max_heap = 0; uint64_t get_max_heap_memory_consumption() { return max_heap - start_heap; } void init(uint8_t *host_memory_pointer, uint64_t mem_start_address, uint64_t heap_pointer_address) { mem = host_memory_pointer; mem_offset = mem_start_address; hp = heap_pointer_address; start_heap = hp; max_heap = hp; } uint8_t *guest_address_to_host_pointer(uintptr_t addr) { assert(mem != nullptr); return mem + (addr - mem_offset); } uint8_t *guest_to_host_pointer(void *p) { return guest_address_to_host_pointer((uintptr_t)p); } /* * Syscalls are implemented to work directly on guest memory (represented in * host as byte array). Note: the data structures on the host system might * not be binary compatible with those on the guest system. */ int execute_syscall(uint64_t n, uint64_t _a0, uint64_t _a1, uint64_t _a2, uint64_t _a3); }; } // namespace rv64 ================================================ FILE: vp/src/core/rv64/syscall_if.h ================================================ #pragma once #include namespace rv64 { /* The syscall handler is using this interface to access and control the ISS. */ struct iss_syscall_if { virtual ~iss_syscall_if() {} virtual void sys_exit() = 0; virtual uint64_t read_register(unsigned idx) = 0; virtual void write_register(unsigned idx, uint64_t value) = 0; }; /* Using this interface, the ISS supports to intercept and delegate syscalls. */ struct syscall_emulator_if { virtual ~syscall_emulator_if() {} virtual void execute_syscall(iss_syscall_if *core) = 0; }; } // namespace rv64 ================================================ FILE: vp/src/platform/CMakeLists.txt ================================================ file(GLOB sources_list LIST_DIRECTORIES true *) foreach(dir ${sources_list}) IF(IS_DIRECTORY ${dir}) add_subdirectory(${dir}) ELSE() CONTINUE() ENDIF() endforeach() ================================================ FILE: vp/src/platform/basic/CMakeLists.txt ================================================ file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) add_library(platform-basic ethernet.cpp display.cpp ${HEADERS}) target_include_directories(platform-basic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(platform-basic systemc) add_executable(riscv-vp main.cpp) target_link_libraries(riscv-vp rv32 platform-basic platform-common gdb-mc ${Boost_LIBRARIES} systemc pthread) INSTALL(TARGETS riscv-vp RUNTIME DESTINATION bin) ================================================ FILE: vp/src/platform/basic/basic_timer.h ================================================ #ifndef RISCV_ISA_BASIC_TIMER_H #define RISCV_ISA_BASIC_TIMER_H #include #include #include "core/common/irq_if.h" struct BasicTimer : public sc_core::sc_module { interrupt_gateway *plic = 0; uint32_t irq_number = 0; SC_HAS_PROCESS(BasicTimer); BasicTimer(sc_core::sc_module_name, uint32_t irq_number) : irq_number(irq_number) { SC_THREAD(run); } void run() { while (true) { sc_core::wait(sc_core::sc_time(1, sc_core::SC_MS)); plic->gateway_trigger_interrupt(irq_number); } } }; #endif // RISCV_ISA_BASIC_TIMER_H ================================================ FILE: vp/src/platform/basic/display.cpp ================================================ /* * display.cpp * * Created on: Sep 11, 2018 * Author: dwd */ #include "display.hpp" #include #include #include #include typedef Framebuffer::Point Point; typedef Framebuffer::PointF PointF; typedef Framebuffer::Color Color; typedef Framebuffer::Frame Frame; Display::Display(sc_module_name) { tsock.register_b_transport(this, &Display::transport); createSM(); memset(frame.raw, 0, sizeof(Framebuffer)); } void Display::createSM() { int shmid; if ((shmid = shmget(SHMKEY, sizeof(Framebuffer), IPC_CREAT | 0666)) < 0) { std::cerr << "Could not get " << sizeof(Framebuffer) << " Byte of shared Memory " << int(SHMKEY) << " for display" << std::endl; perror(NULL); exit(1); } frame.raw = reinterpret_cast(shmat(shmid, nullptr, 0)); if (frame.raw == (uint8_t *)-1) { perror("shmat"); exit(1); } } void Display::transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { tlm::tlm_command cmd = trans.get_command(); unsigned addr = trans.get_address(); auto *ptr = trans.get_data_ptr(); auto len = trans.get_data_length(); assert((addr + len <= sizeof(Framebuffer)) && "Access display out of bounds"); if (cmd == tlm::TLM_WRITE_COMMAND) { if (addr == offsetof(Framebuffer, command) && len == sizeof(Framebuffer::Command)) { // apply command switch (*reinterpret_cast(ptr)) { case Framebuffer::Command::clearAll: memset(frame.raw, 0, sizeof(Framebuffer)); frame.buf->activeFrame++; break; case Framebuffer::Command::fillFrame: fillFrame(frame.buf->parameter.fill.frame, frame.buf->parameter.fill.color); break; case Framebuffer::Command::applyFrame: frame.buf->activeFrame++; memcpy(&frame.buf->getInactiveFrame(), &frame.buf->getActiveFrame(), sizeof(Frame)); break; case Framebuffer::Command::drawLine: drawLine(frame.buf->parameter.line.frame, frame.buf->parameter.line.from, frame.buf->parameter.line.to, frame.buf->parameter.line.color); break; default: cerr << "unknown framebuffer command " << *ptr << endl; sc_assert(false); break; } // reset parameter memset(reinterpret_cast(&frame.buf->parameter), 0, sizeof(Framebuffer::Parameter)); } else if (addr >= offsetof(Framebuffer, parameter) && addr + len < offsetof(Framebuffer, parameter) + sizeof(Framebuffer::Parameter)) { // write the // parameter memcpy(&frame.raw[addr], ptr, len); } else { // Write the actual framebuffer memcpy(&frame.raw[addr], ptr, len); } } else if (cmd == tlm::TLM_READ_COMMAND && addr < sizeof(Framebuffer)) { // read whatever you like memcpy(ptr, &frame.raw[addr], len); } else { sc_assert(false && "unsupported tlm command"); } delay += sc_core::sc_time(len * 5, sc_core::SC_NS); } void Display::fillFrame(Framebuffer::Type type, Color color) { assert(sizeof(Frame) % 8 == 0); assert(8 % sizeof(Color) == 0); uint64_t *rawFrame = reinterpret_cast(&frame.buf->getFrame(type).raw); uint_fast32_t steps = sizeof(Frame) / 8; uint64_t wideColor = 0; for (uint_fast8_t i = 0; i * sizeof(Color) < 8; i++) { reinterpret_cast(&wideColor)[i] = color; } for (uint_fast32_t i = 0; i < steps; i++) { rawFrame[i] = wideColor; } } void Display::drawLine(Framebuffer::Type type, PointF from, PointF to, Color color) { Frame &local = frame.buf->getFrame(type); if (from.x == to.x) { // vertical line if (from.y > to.y) swap(from.y, to.y); uint16_t intFromX = from.x; uint16_t intToY = to.y; for (uint16_t y = from.y; y <= intToY; y++) { local.raw[y][intFromX] = color; } return; } if (from.y == to.y) { // horizontal line, the fastest if (from.x > to.x) swap(from.x, to.x); uint16_t intFromY = from.y; uint16_t intToX = to.x; for (uint16_t x = from.x; x <= intToX; x++) { local.raw[intFromY][x] = color; } return; } // Bresenham's line algorithm const bool steep = (fabs(to.y - from.y) > fabs(to.x - from.x)); if (steep) { swap(from.x, from.y); swap(to.x, to.y); } if (from.x > to.x) { swap(from.x, to.x); swap(from.y, to.y); } const float dx = to.x - from.x; const float dy = fabs(to.y - from.y); float error = dx / 2.0f; const int ystep = (from.y < to.y) ? 1 : -1; int y = (int)from.y; const int maxX = (int)to.x; for (int x = (int)from.x; x < maxX; x++) { if (steep) { local.raw[x][y] = color; } else { local.raw[y][x] = color; } error -= dy; if (error < 0) { y += ystep; error += dx; } } } ================================================ FILE: vp/src/platform/basic/display.hpp ================================================ /* * display.hpp * * Created on: Sep 11, 2018 * Author: dwd */ #pragma once #include #include #include "../../../../env/basic/vp-display/framebuffer.h" using namespace std; using namespace sc_core; using namespace tlm_utils; struct Display : public sc_core::sc_module { static const size_t addressRange = sizeof(Framebuffer); simple_target_socket tsock; union { uint8_t* raw; Framebuffer* buf; } frame; void createSM(); Display(sc_module_name); void transport(tlm::tlm_generic_payload& trans, sc_core::sc_time& delay); // graphics acceleration functions void fillFrame(Framebuffer::Type frame, Framebuffer::Color color); void drawLine(Framebuffer::Type frame, Framebuffer::PointF from, Framebuffer::PointF to, Framebuffer::Color color); }; ================================================ FILE: vp/src/platform/basic/dma.h ================================================ #ifndef RISCV_ISA_DMA_H #define RISCV_ISA_DMA_H #include #include #include #include #include struct SimpleDMA : public sc_core::sc_module { tlm_utils::simple_initiator_socket isock; tlm_utils::simple_target_socket tsock; interrupt_gateway *plic = 0; uint32_t irq_number = 0; std::array buffer; uint32_t src = 0; uint32_t dst = 0; uint32_t len = 0; uint32_t op = 0; uint32_t stat = 0; std::unordered_map addr_to_reg; enum { OP_NOP = 0, OP_MEMCPY = 1, OP_MEMSET = 2, OP_MEMCMP = 3, OP_MEMCHR = 4, OP_MEMMOVE = 5, }; enum { SRC_ADDR = 0, DST_ADDR = 4, LEN_ADDR = 8, OP_ADDR = 12, STAT_ADDR = 16, }; sc_core::sc_event run_event; SC_HAS_PROCESS(SimpleDMA); SimpleDMA(sc_core::sc_module_name, uint32_t irq_number) : irq_number(irq_number) { tsock.register_b_transport(this, &SimpleDMA::transport); SC_THREAD(run); addr_to_reg = { {SRC_ADDR, &src}, {DST_ADDR, &dst}, {LEN_ADDR, &len}, {OP_ADDR, &op}, }; } void _copy_block(uint32_t off, uint32_t n) { do_transaction(tlm::TLM_READ_COMMAND, src + off, &buffer[0], n); do_transaction(tlm::TLM_WRITE_COMMAND, dst + off, &buffer[0], n); } void _perform_memcpy() { auto n = len; uint32_t off = 0; while (n > buffer.size()) { _copy_block(off, buffer.size()); n -= buffer.size(); off += buffer.size(); } _copy_block(off, n); } void run() { while (true) { sc_core::wait(run_event); switch (op) { case OP_NOP: break; case OP_MEMCPY: _perform_memcpy(); break; case OP_MEMSET: assert(false && "not implemented"); break; case OP_MEMCMP: assert(false && "not implemented"); break; case OP_MEMCHR: assert(false && "not implemented"); break; case OP_MEMMOVE: assert(false && "not implemented"); break; default: assert(false && "unknown operation requested by software"); } plic->gateway_trigger_interrupt(irq_number); } } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { auto addr = trans.get_address(); auto cmd = trans.get_command(); auto len = trans.get_data_length(); auto ptr = trans.get_data_ptr(); assert(len == 4); // NOTE: only allow to read/write whole register auto it = addr_to_reg.find(addr); assert(it != addr_to_reg.end()); // access to non-mapped address // actual read/write if (cmd == tlm::TLM_READ_COMMAND) { *((uint32_t *)ptr) = *it->second; } else if (cmd == tlm::TLM_WRITE_COMMAND) { *it->second = *((uint32_t *)ptr); } else { assert(false && "unsupported tlm command for dma access"); } // post read/write actions if ((cmd == tlm::TLM_WRITE_COMMAND) && (addr == OP_ADDR)) { run_event.notify(sc_core::sc_time(10, sc_core::SC_NS)); } (void)delay; // zero delay } void do_transaction(tlm::tlm_command cmd, uint64_t addr, uint8_t *data, unsigned num_bytes) { sc_core::sc_time delay = sc_core::SC_ZERO_TIME; tlm::tlm_generic_payload trans; trans.set_command(cmd); trans.set_address(addr); trans.set_data_ptr(data); trans.set_data_length(num_bytes); isock->b_transport(trans, delay); if (delay != sc_core::SC_ZERO_TIME) sc_core::wait(delay); } }; #endif // RISCV_ISA_DMA_H ================================================ FILE: vp/src/platform/basic/ethernet.cpp ================================================ #include "ethernet.h" #include #include #include #include // for debug #include #include #include #include //#include #include //#include #include #include #include #include #include using namespace std; static const char IF_NAME[] = "tap0"; #define SYS_CHECK(arg, msg) \ if ((arg) < 0) { \ perror(msg); \ throw runtime_error("error"); \ } void printHex(const unsigned char *buf, const uint32_t len) { for (uint8_t i = 0; i < len; i++) { printf("%s%02X", i > 0 ? ":" : "", buf[i]); } } void printDec(const unsigned char *buf, const uint32_t len) { for (uint8_t i = 0; i < len; i++) { printf("%s%d", i > 0 ? "." : "", buf[i]); } } void dump_ethernet_frame(uint8_t *buf, size_t size, bool verbose = false) { uint8_t *readbuf = buf; struct ether_header *eh = (struct ether_header *)readbuf; if (verbose) { cout << "destination MAC: "; printHex(reinterpret_cast(&eh->ether_dhost), 6); cout << endl; cout << "source MAC : "; printHex(reinterpret_cast(&eh->ether_shost), 6); cout << endl; cout << "type : " << ntohs(eh->ether_type) << endl; } readbuf += sizeof(struct ethhdr); switch (ntohs(eh->ether_type)) { case ETH_P_IP: { cout << "IP "; struct in_addr source; struct in_addr dest; struct iphdr *ip = (struct iphdr *)readbuf; memset(&source, 0, sizeof(source)); source.s_addr = ip->saddr; memset(&dest, 0, sizeof(dest)); dest.s_addr = ip->daddr; if (verbose) { cout << endl; cout << "\t|-Version : " << ip->version << endl; cout << "\t|-Internet Header Length: " << ip->ihl << " DWORDS or " << ip->ihl * 4 << " Bytes" << endl; cout << "\t|-Type Of Service : " << (unsigned int)ip->tos << endl; cout << "\t|-Total Length : " << ntohs(ip->tot_len) << " Bytes" << endl; cout << "\t|-Identification : " << ntohs(ip->id) << endl; cout << "\t|-Time To Live : " << (unsigned int)ip->ttl << endl; cout << "\t|-Protocol : " << (unsigned int)ip->protocol << endl; cout << "\t|-Header Checksum : " << ntohs(ip->check) << endl; cout << "\t|-Source IP : " << inet_ntoa(source) << endl; cout << "\t|-Destination IP : " << inet_ntoa(dest) << endl; } readbuf += ip->ihl * 4; switch (ip->protocol) { case IPPROTO_UDP: { cout << "UDP "; struct udphdr *udp = (struct udphdr *)readbuf; if (verbose) { cout << endl; cout << "\t|-Source port : " << ntohs(udp->source) << endl; cout << "\t|-Destination port: " << ntohs(udp->dest) << endl; cout << "\t|-Length : " << ntohs(udp->len) << endl; cout << "\t|-Checksum : " << ntohs(udp->check) << endl; } readbuf += sizeof(udphdr); switch (ntohs(udp->dest)) { case 67: case 68: cout << "DHCP "; switch (readbuf[0]) { case 1: cout << "DISCOVER/REQUEST"; break; case 2: cout << "ACK"; break; default: cout << "UNKNOWN (" << to_string(readbuf[0]) << ")"; goto printHex; } break; default: break; } return; } case IPPROTO_TCP: cout << "TCP "; if (verbose) cout << endl; return; case IPPROTO_ICMP: cout << "ICMP "; switch (readbuf[0]) { case 0: cout << "ECHO REPLY"; break; case 3: cout << "DEST UNREACHABLE"; break; case 8: cout << "ECHO REQUEST"; break; default: cout << "Sonstiges"; } if (verbose) cout << endl; default: return; } break; } case ETH_P_ARP: { cout << "ARP "; struct arp_eth_header *arp = (struct arp_eth_header *)readbuf; if (verbose) { cout << endl; cout << "\t|-Sender MAC: "; printHex((uint8_t *)&arp->sender_mac, 6); cout << endl; cout << "\t|-Sender IP : "; printDec((uint8_t *)&arp->sender_ip, 4); cout << endl; cout << "\t|-DEST MAC : "; printHex((uint8_t *)&arp->target_mac, 6); cout << endl; cout << "\t|-DEST IP : "; printDec((uint8_t *)&arp->target_ip, 4); cout << endl; } cout << "\t|-Operation : " << (ntohs(arp->oper) == 1 ? "REQUEST" : ntohs(arp->oper) == 2 ? "REPLY" : "INVALID"); return; break; } default: cout << "unknown protocol"; return; } printHex: ios_base::fmtflags f(cout.flags()); for (unsigned i = 0; i < size; ++i) { cout << hex << setw(2) << setfill('0') << (int)buf[i] << " "; } cout.flags(f); } EthernetDevice::EthernetDevice(sc_core::sc_module_name, uint32_t irq_number, uint8_t *mem, std::string clonedev) : irq_number(irq_number), mem(mem) { tsock.register_b_transport(this, &EthernetDevice::transport); SC_THREAD(run); router .add_register_bank({ {STATUS_REG_ADDR, &status}, {RECEIVE_SIZE_REG_ADDR, &receive_size}, {RECEIVE_DST_REG_ADDR, &receive_dst}, {SEND_SRC_REG_ADDR, &send_src}, {SEND_SIZE_REG_ADDR, &send_size}, {MAC_HIGH_REG_ADDR, &mac[0]}, {MAC_LOW_REG_ADDR, &mac[1]}, }) .register_handler(this, &EthernetDevice::register_access_callback); disabled = clonedev == string(""); if (!disabled) { init_network(clonedev); } } void EthernetDevice::init_network(std::string clonedev) { struct ifreq ifr; int err; if ((sockfd = open(clonedev.c_str(), O_RDWR)) < 0) { cerr << "Error opening " << clonedev << endl; perror("exiting"); assert(sockfd >= 0); } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, IF_NAME, IFNAMSIZ); if ((err = ioctl(sockfd, TUNSETIFF, (void *)&ifr)) < 0) { perror("ioctl(TUNSETIFF)"); close(sockfd); assert(err >= 0); } /* Get the MAC address of the interface to send on */ struct ifreq ifopts; memset(&ifopts, 0, sizeof(struct ifreq)); strncpy(ifopts.ifr_name, IF_NAME, IFNAMSIZ - 1); if (ioctl(sockfd, SIOCGIFHWADDR, &ifopts) < 0) { perror("SIOCGIFHWADDR"); assert(sockfd >= 0); } // Save own MAC in register memcpy(VIRTUAL_MAC_ADDRESS, ifopts.ifr_hwaddr.sa_data, 6); fcntl(sockfd, F_SETFL, O_NONBLOCK); } void EthernetDevice::send_raw_frame() { uint8_t sendbuf[send_size < 60 ? 60 : send_size]; memcpy(sendbuf, &mem[send_src - 0x80000000], send_size); if (send_size < 60) { memset(&sendbuf[send_size], 0, 60 - send_size); send_size = 60; } cout << "SEND FRAME --->--->--->--->--->---> "; dump_ethernet_frame(sendbuf, send_size, true); cout << endl; struct ether_header *eh = (struct ether_header *)sendbuf; assert(memcmp(eh->ether_shost, VIRTUAL_MAC_ADDRESS, ETH_ALEN) == 0); ssize_t ans = write(sockfd, sendbuf, send_size); if (ans != send_size) { cout << strerror(errno) << endl; } assert(ans == send_size); } bool EthernetDevice::isPacketForUs(uint8_t *packet, ssize_t) { ether_header *eh = reinterpret_cast(packet); bool virtual_match = memcmp(eh->ether_dhost, VIRTUAL_MAC_ADDRESS, ETH_ALEN) == 0; bool broadcast_match = memcmp(eh->ether_dhost, BROADCAST_MAC_ADDRESS, ETH_ALEN) == 0; bool own_packet = memcmp(eh->ether_shost, VIRTUAL_MAC_ADDRESS, ETH_ALEN) == 0; if (!virtual_match && !(broadcast_match && !own_packet)) { return false; } if (ntohs(eh->ether_type) != ETH_P_IP) { if (ntohs(eh->ether_type) != ETH_P_ARP) { // Not ARP // cout << " dumped non-ARP " ; // FIXME change to true if you want other protocols than IP and ARP return false; } arp_eth_header *arp = reinterpret_cast(packet + sizeof(ether_header)); if (memcmp(arp->target_mac, VIRTUAL_MAC_ADDRESS, 6)) { // not to us directly // cout << " dumped ARP not targeted to US "; /** * FIXME comment out if you want to generate arp table automatically * instead of having to request every neighbor explicitly * also to reply to ARP requests */ return true; } } else { // is IP return true; iphdr *ip = reinterpret_cast(packet + sizeof(ether_header)); if (ip->protocol != IPPROTO_UDP) { // not UDP // cout << " dumped non-UDP "; // FIXME change to true if you want to use TCP or ICMP return false; } udphdr *udp = reinterpret_cast(packet + sizeof(ether_header) + sizeof(iphdr)); if (ntohs(udp->dest) != 67 && ntohs(udp->dest) != 68) { // not DHCP // cout << " dumped non-DHCP "; return false; } } return true; } bool EthernetDevice::try_recv_raw_frame() { ssize_t ans; ans = read(sockfd, recv_frame_buf, FRAME_SIZE); assert(ans <= FRAME_SIZE); if (ans == 0) { cerr << "[ethernet] recv socket received zero bytes ... connection " "closed?" << endl; throw runtime_error("read failed"); } else if (ans == -1) { if (errno == EWOULDBLOCK || errno == EAGAIN) { return true; } else throw runtime_error("recvfrom failed"); } assert(ETH_ALEN == 6); if (!isPacketForUs(recv_frame_buf, ans)) { return false; } has_frame = true; receive_size = ans; cout << "RECEIVED FRAME <---<---<---<---<--- "; dump_ethernet_frame(recv_frame_buf, ans); cout << endl; return true; } ================================================ FILE: vp/src/platform/basic/ethernet.h ================================================ #ifndef RISCV_VP_ETHERNET_H #define RISCV_VP_ETHERNET_H #include #include #include #include #include #include #include #include #include #include #include "core/common/irq_if.h" #include "util/tlm_map.h" struct arp_eth_header { uint16_t htype; uint16_t ptype; uint8_t hlen; uint8_t plen; uint16_t oper; uint8_t sender_mac[6]; uint8_t sender_ip[4]; uint8_t target_mac[6]; uint8_t target_ip[4]; }; struct EthernetDevice : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; interrupt_gateway *plic = 0; uint32_t irq_number = 0; sc_core::sc_event run_event; // memory mapped configuration registers uint32_t status = 0; uint32_t receive_size = 0; uint32_t receive_dst = 0; uint32_t send_src = 0; uint32_t send_size = 0; uint32_t mac[2]; uint8_t *VIRTUAL_MAC_ADDRESS = reinterpret_cast(mac); uint8_t BROADCAST_MAC_ADDRESS[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; uint8_t *mem = nullptr; vp::map::LocalRouter router; int sockfd = 0; int interfaceIdx = 0; static const uint16_t MTU_SIZE = 1500; static const uint16_t FRAME_SIZE = MTU_SIZE + 14; uint8_t recv_frame_buf[FRAME_SIZE]; bool has_frame; bool disabled; static const uint16_t STATUS_REG_ADDR = 0x00; static const uint16_t RECEIVE_SIZE_REG_ADDR = STATUS_REG_ADDR + sizeof(uint32_t); static const uint16_t RECEIVE_DST_REG_ADDR = RECEIVE_SIZE_REG_ADDR + sizeof(uint32_t); static const uint16_t SEND_SRC_REG_ADDR = RECEIVE_DST_REG_ADDR + sizeof(uint32_t); static const uint16_t SEND_SIZE_REG_ADDR = SEND_SRC_REG_ADDR + sizeof(uint32_t); static const uint16_t MAC_HIGH_REG_ADDR = SEND_SIZE_REG_ADDR + sizeof(uint32_t); static const uint16_t MAC_LOW_REG_ADDR = MAC_HIGH_REG_ADDR + sizeof(uint32_t); enum : uint16_t { RECV_OPERATION = 1, SEND_OPERATION = 2, }; SC_HAS_PROCESS(EthernetDevice); EthernetDevice(sc_core::sc_module_name, uint32_t irq_number, uint8_t *mem, std::string clonedev); void init_network(std::string clonedev); void add_all_if_ips(); void send_raw_frame(); bool try_recv_raw_frame(); bool isPacketForUs(uint8_t *packet, ssize_t size); void register_access_callback(const vp::map::register_access_t &r) { assert(mem); assert(!disabled && "Tried accessing disabled network device"); r.fn(); if (r.write && r.vptr == &status) { if (r.nv == RECV_OPERATION) { assert(has_frame); memcpy(&mem[receive_dst - 0x80000000], recv_frame_buf, receive_size); has_frame = false; receive_size = 0; } else if (r.nv == SEND_OPERATION) { send_raw_frame(); } else { throw std::runtime_error("unsupported operation"); } } } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { router.transport(trans, delay); } void run() { while (!disabled) { run_event.notify(sc_core::sc_time(10000, sc_core::SC_US)); sc_core::wait(run_event); // 10000 times per second by default // check if data is available on the socket, if yes store it in an // internal buffer if (!has_frame) { while (!try_recv_raw_frame()) ; if (has_frame) plic->gateway_trigger_interrupt(irq_number); } } } }; #endif // RISCV_VP_ETHERNET_H ================================================ FILE: vp/src/platform/basic/flash.h ================================================ #pragma once #include #include #include #include #include //truncate #include //file IO #include #include #include #include "bus.h" using namespace std; using namespace sc_core; using namespace tlm_utils; template struct Blockbuffer { uint8_t buf[width]; uint64_t offs; bool dirty; bool active; int fd; Blockbuffer(int fileDescriptor) : offs(0), dirty(false), active(false), fd(fileDescriptor){}; void setPos(uint64_t blockOffset) { if (blockOffset != offs || !active) { if (dirty && active) { // commit changes writeBlock(offs); } offs = blockOffset; readBlock(blockOffset); active = true; } } void setData(const uint8_t* source, uint16_t pos, uint16_t length) { assert(active); memcpy(&buf[pos], source, length); dirty = true; } void getData(uint8_t* target, uint16_t pos, uint16_t length) { assert(active); memcpy(target, &buf[pos], length); } void writeBlock(uint64_t blockOffset) { if (lseek(fd, blockOffset * width, SEEK_SET) < 0) { cerr << "Could not seek device: " << strerror(errno) << endl; return; } if (write(fd, buf, width) != width) { cerr << "Could not write device: " << strerror(errno) << endl; return; } dirty = false; } void readBlock(uint64_t blockOffset) { if (lseek(fd, blockOffset * width, SEEK_SET) < 0) { cerr << "Could not seek device: " << strerror(errno) << endl; return; } if (read(fd, buf, width) != width) { cerr << "Could not read device: " << strerror(errno) << endl; return; } dirty = false; } void clear() { if (active && dirty) { writeBlock(offs); } active = false; } }; struct Flashcontroller : public sc_core::sc_module { static const unsigned int BLOCKSIZE = 512; static const unsigned int FLASH_ADDR_REG = 0; static const unsigned int FLASH_SIZE_REG = sizeof(uint64_t); static const unsigned int DATA_ADDR = FLASH_SIZE_REG + sizeof(uint64_t); static const unsigned int ADDR_SPACE = DATA_ADDR + BLOCKSIZE; simple_target_socket tsock; uint8_t blockbufRaw[sizeof(Blockbuffer)]; Blockbuffer* blockBuf; union { uint64_t asInt; uint8_t asRaw[8]; } mTargetBlock; union { uint64_t asInt; uint8_t asRaw[8]; } mDeviceNumBlocks; string mFilepath; int mFiledescriptor; Flashcontroller(sc_module_name, string& filepath) : blockBuf(nullptr), mFilepath(filepath), mFiledescriptor(-1) { tsock.register_b_transport(this, &Flashcontroller::transport); if (filepath.length() == 0) { // No file return; } mFiledescriptor = open(mFilepath.c_str(), O_SYNC | O_RDWR); if (mFiledescriptor < 0) { cerr << "Could not open device " << mFilepath << ": " << strerror(errno) << endl; return; } if (ioctl(mFiledescriptor, BLKGETSIZE64, &mDeviceNumBlocks.asInt) < 0) { cerr << "Could not get size of Device " << mFilepath << ": " << strerror(errno) << endl; mDeviceNumBlocks.asInt = lseek(mFiledescriptor, 0, SEEK_END); if (mDeviceNumBlocks.asInt <= 0) { close(mFiledescriptor); mFiledescriptor = -1; return; } cerr << "Could get size of _file_ " << mFilepath << ": " << mDeviceNumBlocks.asInt << endl; mDeviceNumBlocks.asInt /= BLOCKSIZE; } mTargetBlock.asInt = 0; blockBuf = new (blockbufRaw) Blockbuffer(mFiledescriptor); } ~Flashcontroller() { if (blockBuf != nullptr) { blockBuf->clear(); } close(mFiledescriptor); } void transport(tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) { tlm::tlm_command cmd = trans.get_command(); unsigned addr = trans.get_address(); auto* ptr = trans.get_data_ptr(); auto len = trans.get_data_length(); assert((addr < DATA_ADDR + BLOCKSIZE) && "Access flashcontroller out of bounds"); assert(mFiledescriptor >= 0); if (/*addr >= FLASH_ADDR_REG &&*/ addr < FLASH_SIZE_REG) { // Address register if (cmd == tlm::TLM_WRITE_COMMAND) { memcpy(&mTargetBlock.asRaw[addr - FLASH_ADDR_REG], ptr, len); } else if (cmd == tlm::TLM_READ_COMMAND) { memcpy(ptr, &mTargetBlock.asRaw[addr - FLASH_ADDR_REG], len); } else { sc_assert(false && "unsupported tlm command"); } delay += sc_core::sc_time(len * 30, sc_core::SC_NS); } else if (addr >= FLASH_SIZE_REG && addr < DATA_ADDR) { // Size register if (cmd == tlm::TLM_READ_COMMAND) { memcpy(ptr, &mDeviceNumBlocks.asRaw[addr - FLASH_SIZE_REG], len); } else { sc_assert(false && "unsupported tlm command"); } delay += sc_core::sc_time(len * 30, sc_core::SC_NS); } else { // Data region assert(mTargetBlock.asInt < mDeviceNumBlocks.asInt && "Access Flash out of bounds!"); blockBuf->setPos(mTargetBlock.asInt); // Loads Block into buffer if (cmd == tlm::TLM_WRITE_COMMAND) { blockBuf->setData(ptr, addr - DATA_ADDR, len); } else if (cmd == tlm::TLM_READ_COMMAND) { blockBuf->getData(ptr, addr - DATA_ADDR, len); } else { sc_assert(false && "unsupported tlm command"); } // TODO: Add delay based on blockBuf cache delay += sc_core::sc_time(len, sc_core::SC_US); } } }; ================================================ FILE: vp/src/platform/basic/main.cpp ================================================ #include #include #include "basic_timer.h" #include "core/common/clint.h" #include "display.hpp" #include "dma.h" #include "elf_loader.h" #include "ethernet.h" #include "fe310_plic.h" #include "flash.h" #include "debug_memory.h" #include "iss.h" #include "mem.h" #include "memory.h" #include "memory_mapped_file.h" #include "sensor.h" #include "sensor2.h" #include "syscall.h" #include "uart.h" #include "util/options.h" #include "platform/common/options.h" #include "platform/common/terminal.h" #include "gdb-mc/gdb_server.h" #include "gdb-mc/gdb_runner.h" #include #include #include #include using namespace rv32; namespace po = boost::program_options; class BasicOptions : public Options { public: typedef unsigned int addr_t; std::string mram_image; std::string flash_device; std::string network_device; std::string test_signature; addr_t mem_size = 1024 * 1024 * 32; // 32 MB ram, to place it before the CLINT and run the base examples (assume // memory start at zero) without modifications addr_t mem_start_addr = 0x00000000; addr_t mem_end_addr = mem_start_addr + mem_size - 1; addr_t clint_start_addr = 0x02000000; addr_t clint_end_addr = 0x0200ffff; addr_t sys_start_addr = 0x02010000; addr_t sys_end_addr = 0x020103ff; addr_t term_start_addr = 0x20000000; addr_t term_end_addr = term_start_addr + 16; addr_t uart_start_addr = 0x20010000; addr_t uart_end_addr = uart_start_addr + 0xfff; addr_t ethernet_start_addr = 0x30000000; addr_t ethernet_end_addr = ethernet_start_addr + 1500; addr_t plic_start_addr = 0x40000000; addr_t plic_end_addr = 0x41000000; addr_t sensor_start_addr = 0x50000000; addr_t sensor_end_addr = 0x50001000; addr_t sensor2_start_addr = 0x50002000; addr_t sensor2_end_addr = 0x50004000; addr_t mram_start_addr = 0x60000000; addr_t mram_size = 0x10000000; addr_t mram_end_addr = mram_start_addr + mram_size - 1; addr_t dma_start_addr = 0x70000000; addr_t dma_end_addr = 0x70001000; addr_t flash_start_addr = 0x71000000; addr_t flash_end_addr = flash_start_addr + Flashcontroller::ADDR_SPACE; // Usually 528 Byte addr_t display_start_addr = 0x72000000; addr_t display_end_addr = display_start_addr + Display::addressRange; bool quiet = false; bool use_E_base_isa = false; OptionValue entry_point; BasicOptions(void) { // clang-format off add_options() ("quiet", po::bool_switch(&quiet), "do not output register values on exit") ("memory-start", po::value(&mem_start_addr),"set memory start address") ("memory-size", po::value(&mem_size), "set memory size") ("use-E-base-isa", po::bool_switch(&use_E_base_isa), "use the E instead of the I integer base ISA") ("entry-point", po::value(&entry_point.option),"set entry point address (ISS program counter)") ("mram-image", po::value(&mram_image)->default_value(""),"MRAM image file for persistency") ("mram-image-size", po::value(&mram_size), "MRAM image size") ("flash-device", po::value(&flash_device)->default_value(""),"blockdevice for flash emulation") ("network-device", po::value(&network_device)->default_value(""),"name of the tap network adapter, e.g. /dev/tap6") ("signature", po::value(&test_signature)->default_value(""),"output filename for the test execution signature"); // clang-format on }; void printValues(std::ostream& os) const override { os << std::hex; os << "mem_start_addr:\t" << +mem_start_addr << std::endl; os << "mem_end_addr:\t" << +mem_end_addr << std::endl; static_cast ( *this ).printValues(os); } void parse(int argc, char **argv) override { Options::parse(argc, argv); entry_point.finalize(parse_ulong_option); mem_end_addr = mem_start_addr + mem_size - 1; assert((mem_end_addr < clint_start_addr || mem_start_addr > display_end_addr) && "RAM too big, would overlap memory"); mram_end_addr = mram_start_addr + mram_size - 1; assert(mram_end_addr < dma_start_addr && "MRAM too big, would overlap memory"); } }; int sc_main(int argc, char **argv) { BasicOptions opt; opt.parse(argc, argv); std::srand(std::time(nullptr)); // use current time as seed for random generator tlm::tlm_global_quantum::instance().set(sc_core::sc_time(opt.tlm_global_quantum, sc_core::SC_NS)); ISS core(0, opt.use_E_base_isa); SimpleMemory mem("SimpleMemory", opt.mem_size); SimpleTerminal term("SimpleTerminal"); UART uart("Generic_UART", 6); ELFLoader loader(opt.input_program.c_str()); SimpleBus<3, 13> bus("SimpleBus"); CombinedMemoryInterface iss_mem_if("MemoryInterface", core); SyscallHandler sys("SyscallHandler"); FE310_PLIC<1, 64, 96, 32> plic("PLIC"); CLINT<1> clint("CLINT"); SimpleSensor sensor("SimpleSensor", 2); SimpleSensor2 sensor2("SimpleSensor2", 5); BasicTimer timer("BasicTimer", 3); MemoryMappedFile mram("MRAM", opt.mram_image, opt.mram_size); SimpleDMA dma("SimpleDMA", 4); Flashcontroller flashController("Flashcontroller", opt.flash_device); EthernetDevice ethernet("EthernetDevice", 7, mem.data, opt.network_device); Display display("Display"); DebugMemoryInterface dbg_if("DebugMemoryInterface"); MemoryDMI dmi = MemoryDMI::create_start_size_mapping(mem.data, opt.mem_start_addr, mem.size); InstrMemoryProxy instr_mem(dmi, core); std::shared_ptr bus_lock = std::make_shared(); iss_mem_if.bus_lock = bus_lock; instr_memory_if *instr_mem_if = &iss_mem_if; data_memory_if *data_mem_if = &iss_mem_if; if (opt.use_instr_dmi) instr_mem_if = &instr_mem; if (opt.use_data_dmi) { iss_mem_if.dmi_ranges.emplace_back(dmi); } uint64_t entry_point = loader.get_entrypoint(); if (opt.entry_point.available) entry_point = opt.entry_point.value; try { loader.load_executable_image(mem, mem.size, opt.mem_start_addr); } catch(ELFLoader::load_executable_exception& e) { std::cerr << e.what() << std::endl; std::cerr << "Memory map: " << std::endl; opt.printValues(std::cerr); return -1; } /* * The rv32 calling convention defaults to 32 bit, but as this Config is * mainly used together with the syscall handler, this helps for certain floats. * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc */ core.init(instr_mem_if, data_mem_if, &clint, entry_point, rv64_align_address(opt.mem_end_addr)); sys.init(mem.data, opt.mem_start_addr, loader.get_heap_addr()); sys.register_core(&core); if (opt.intercept_syscalls) core.sys = &sys; core.error_on_zero_traphandler = opt.error_on_zero_traphandler; // address mapping { unsigned it = 0; bus.ports[it++] = new PortMapping(opt.mem_start_addr, opt.mem_end_addr); bus.ports[it++] = new PortMapping(opt.clint_start_addr, opt.clint_end_addr); bus.ports[it++] = new PortMapping(opt.plic_start_addr, opt.plic_end_addr); bus.ports[it++] = new PortMapping(opt.term_start_addr, opt.term_end_addr); bus.ports[it++] = new PortMapping(opt.uart_start_addr, opt.uart_end_addr); bus.ports[it++] = new PortMapping(opt.sensor_start_addr, opt.sensor_end_addr); bus.ports[it++] = new PortMapping(opt.dma_start_addr, opt.dma_end_addr); bus.ports[it++] = new PortMapping(opt.sensor2_start_addr, opt.sensor2_end_addr); bus.ports[it++] = new PortMapping(opt.mram_start_addr, opt.mram_end_addr); bus.ports[it++] = new PortMapping(opt.flash_start_addr, opt.flash_end_addr); bus.ports[it++] = new PortMapping(opt.ethernet_start_addr, opt.ethernet_end_addr); bus.ports[it++] = new PortMapping(opt.display_start_addr, opt.display_end_addr); bus.ports[it++] = new PortMapping(opt.sys_start_addr, opt.sys_end_addr); } // connect TLM sockets iss_mem_if.isock.bind(bus.tsocks[0]); dbg_if.isock.bind(bus.tsocks[2]); PeripheralWriteConnector dma_connector("SimpleDMA-Connector"); // to respect ISS bus locking dma_connector.isock.bind(bus.tsocks[1]); dma.isock.bind(dma_connector.tsock); dma_connector.bus_lock = bus_lock; { unsigned it = 0; bus.isocks[it++].bind(mem.tsock); bus.isocks[it++].bind(clint.tsock); bus.isocks[it++].bind(plic.tsock); bus.isocks[it++].bind(term.tsock); bus.isocks[it++].bind(uart.tsock); bus.isocks[it++].bind(sensor.tsock); bus.isocks[it++].bind(dma.tsock); bus.isocks[it++].bind(sensor2.tsock); bus.isocks[it++].bind(mram.tsock); bus.isocks[it++].bind(flashController.tsock); bus.isocks[it++].bind(ethernet.tsock); bus.isocks[it++].bind(display.tsock); bus.isocks[it++].bind(sys.tsock); } // connect interrupt signals/communication plic.target_harts[0] = &core; clint.target_harts[0] = &core; sensor.plic = &plic; dma.plic = &plic; timer.plic = &plic; sensor2.plic = &plic; ethernet.plic = &plic; std::vector threads; threads.push_back(&core); core.trace = opt.trace_mode; // switch for printing instructions if (opt.use_debug_runner) { auto server = new GDBServer("GDBServer", threads, &dbg_if, opt.debug_port); new GDBServerRunner("GDBRunner", server, &core); } else { new DirectCoreRunner(core); } if (opt.quiet) sc_core::sc_report_handler::set_verbosity_level(sc_core::SC_NONE); sc_core::sc_start(); if (!opt.quiet) core.show(); if (opt.test_signature != "") { auto begin_sig = loader.get_begin_signature_address(); auto end_sig = loader.get_end_signature_address(); { boost::io::ios_flags_saver ifs(cout); std::cout << std::hex; std::cout << "begin_signature: " << begin_sig << std::endl; std::cout << "end_signature: " << end_sig << std::endl; std::cout << "signature output file: " << opt.test_signature << std::endl; } assert(end_sig >= begin_sig); assert(begin_sig >= opt.mem_start_addr); auto begin = begin_sig - opt.mem_start_addr; auto end = end_sig - opt.mem_start_addr; ofstream sigfile(opt.test_signature, ios::out); auto n = begin; while (n < end) { sigfile << std::hex << std::setw(2) << std::setfill('0') << (unsigned)mem.data[n]; ++n; } } return 0; } ================================================ FILE: vp/src/platform/basic/random_source.h ================================================ #ifndef RISCV_ISA_RANDOM_SOURCE_H #define RISCV_ISA_RANDOM_SOURCE_H #include #include #include struct RandomSource : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; RandomSource(sc_core::sc_module_name) { tsock.register_b_transport(this, &RandomSource::transport); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { assert(trans.get_command() == tlm::TLM_READ_COMMAND); auto *p = trans.get_data_ptr(); for (unsigned i = 0; i < trans.get_data_length(); ++i) { *(p + i) = rand(); } } }; #endif // RISCV_ISA_RANDOM_SOURCE_H ================================================ FILE: vp/src/platform/basic/sensor.h ================================================ #ifndef RISCV_ISA_SENSOR_H #define RISCV_ISA_SENSOR_H #include #include #include #include #include "core/common/irq_if.h" struct SimpleSensor : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; interrupt_gateway *plic = 0; uint32_t irq_number = 0; sc_core::sc_event run_event; // memory mapped data frame std::array data_frame; // memory mapped configuration registers uint32_t scaler = 25; uint32_t filter = 0; std::unordered_map addr_to_reg; enum { SCALER_REG_ADDR = 0x80, FILTER_REG_ADDR = 0x84, }; SC_HAS_PROCESS(SimpleSensor); SimpleSensor(sc_core::sc_module_name, uint32_t irq_number) : irq_number(irq_number) { tsock.register_b_transport(this, &SimpleSensor::transport); SC_THREAD(run); addr_to_reg = { {SCALER_REG_ADDR, &scaler}, {FILTER_REG_ADDR, &filter}, }; } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { auto addr = trans.get_address(); auto cmd = trans.get_command(); auto len = trans.get_data_length(); auto ptr = trans.get_data_ptr(); if (addr <= 63) { // access data frame assert(cmd == tlm::TLM_READ_COMMAND); assert((addr + len) <= data_frame.size()); // return last generated random data at requested address memcpy(ptr, &data_frame[addr], len); } else { assert(len == 4); // NOTE: only allow to read/write whole register auto it = addr_to_reg.find(addr); assert(it != addr_to_reg.end()); // access to non-mapped address // trigger pre read/write actions if ((cmd == tlm::TLM_WRITE_COMMAND) && (addr == SCALER_REG_ADDR)) { uint32_t value = *((uint32_t *)ptr); if (value < 1 || value > 100) return; // ignore invalid values } // actual read/write if (cmd == tlm::TLM_READ_COMMAND) { *((uint32_t *)ptr) = *it->second; } else if (cmd == tlm::TLM_WRITE_COMMAND) { *it->second = *((uint32_t *)ptr); } else { assert(false && "unsupported tlm command for sensor access"); } // trigger post read/write actions if ((cmd == tlm::TLM_WRITE_COMMAND) && (addr == SCALER_REG_ADDR)) { run_event.cancel(); run_event.notify(sc_core::sc_time(scaler, sc_core::SC_MS)); } } (void)delay; // zero delay } void run() { while (true) { run_event.notify(sc_core::sc_time(scaler, sc_core::SC_MS)); sc_core::wait(run_event); // 40 times per second by default // fill with random data for (auto &n : data_frame) { if (filter == 1) { n = rand() % 10 + 48; } else if (filter == 2) { n = rand() % 26 + 65; } else { // fallback for all other filter values n = rand() % 92 + 32; // random printable char } } plic->gateway_trigger_interrupt(irq_number); } } }; #endif // RISCV_ISA_SENSOR_H ================================================ FILE: vp/src/platform/basic/sensor2.h ================================================ #ifndef RISCV_ISA_SENSOR2_H #define RISCV_ISA_SENSOR2_H #include #include #include "core/common/irq_if.h" #include "util/tlm_map.h" /* * Provides the same functionality as sensor.h but uses the optional modelling * layer provided in util/tlm_map.h. */ struct SimpleSensor2 : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; interrupt_gateway *plic = 0; uint32_t irq_number = 0; sc_core::sc_event run_event; // memory mapped data frame std::array data_frame; // memory mapped configuration registers uint32_t scaler = 25; uint32_t filter = 0; enum { SCALER_REG_ADDR = 0x80, FILTER_REG_ADDR = 0x84, }; vp::map::LocalRouter router; SC_HAS_PROCESS(SimpleSensor2); SimpleSensor2(sc_core::sc_module_name, uint32_t irq_number) : irq_number(irq_number) { tsock.register_b_transport(this, &SimpleSensor2::transport); SC_THREAD(run); router .add_register_bank({ {SCALER_REG_ADDR, &scaler}, {FILTER_REG_ADDR, &filter}, }) .register_handler(this, &SimpleSensor2::register_access_callback); router.add_start_size_mapping(0x00, data_frame.size(), vp::map::read_only) .register_handler(this, &SimpleSensor2::data_frame_access_callback); } void data_frame_access_callback(tlm::tlm_generic_payload &trans, sc_core::sc_time) { // return last generated random data at requested address vp::map::execute_memory_access(trans, data_frame.data()); } void register_access_callback(const vp::map::register_access_t &r) { // trigger pre read/write actions if (r.write && (r.vptr == &scaler)) { if (r.nv < 1 || r.nv > 100) return; } // actual read/write r.fn(); // trigger post read/write actions if (r.write && (r.vptr == &scaler)) { run_event.cancel(); run_event.notify(sc_core::sc_time(scaler, sc_core::SC_MS)); } } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { router.transport(trans, delay); } void run() { while (true) { run_event.notify(sc_core::sc_time(scaler, sc_core::SC_MS)); sc_core::wait(run_event); // 40 times per second by default // fill with random data for (auto &n : data_frame) { if (filter == 1) { n = rand() % 10 + 48; } else if (filter == 2) { n = rand() % 26 + 65; } else { // fallback for all other filter values n = rand(); // random char } } plic->gateway_trigger_interrupt(irq_number); } } }; #endif // RISCV_ISA_SENSOR2_H ================================================ FILE: vp/src/platform/common/CMakeLists.txt ================================================ file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) add_library(platform-common fe310_plic.cpp fu540_plic.cpp uart_if.cpp fd_abstract_uart.cpp slip.cpp uart.cpp options.cpp ${HEADERS}) target_include_directories(platform-common PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(platform-common systemc) ================================================ FILE: vp/src/platform/common/async_event.h ================================================ /***************************************************************************** Licensed to Accellera Systems Initiative Inc. (Accellera) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. Accellera licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ /* * thread_safe_event.h * * Copyright (C) 2017, GreenSocs Ltd. * * Developed by Mark Burton mark@greensocs.com */ #pragma once #include class AsyncEvent : public sc_core::sc_prim_channel { sc_core::sc_time m_delay; sc_core::sc_event m_event; public: AsyncEvent(const char* name = sc_core::sc_gen_unique_name("async_event")) : sc_core::sc_prim_channel(name), m_event((std::string(this->basename()) + "_event").c_str()) { // register this channel as "suspending", to not end the simulation // when we're running out of internal events async_attach_suspending(); } // THREADSAFE METHOD: void notify(sc_core::sc_time delay = sc_core::SC_ZERO_TIME) { m_delay = delay; async_request_update(); } // only allow waiting for the event operator const sc_core::sc_event&() const { return m_event; } protected: void update(void) { // we're in the update phase of the SystemC kernel (thread) m_event.notify(m_delay); } }; ================================================ FILE: vp/src/platform/common/bus.h ================================================ #ifndef RISCV_ISA_BUS_H #define RISCV_ISA_BUS_H #include #include #include #include #include #include struct PortMapping { uint64_t start; uint64_t end; PortMapping(uint64_t start, uint64_t end) : start(start), end(end) { assert(end >= start); } bool contains(uint64_t addr) { return addr >= start && addr <= end; } uint64_t global_to_local(uint64_t addr) { return addr - start; } }; template struct SimpleBus : sc_core::sc_module { std::array, NR_OF_INITIATORS> tsocks; std::array, NR_OF_TARGETS> isocks; std::array ports; SimpleBus(sc_core::sc_module_name) { for (auto &s : tsocks) { s.register_b_transport(this, &SimpleBus::transport); s.register_transport_dbg(this, &SimpleBus::transport_dbg); } } int decode(uint64_t addr) { for (unsigned i = 0; i < NR_OF_TARGETS; ++i) { if (ports[i]->contains(addr)) return i; } return -1; } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { auto addr = trans.get_address(); auto id = decode(addr); if (id < 0) { trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE); return; } trans.set_address(ports[id]->global_to_local(addr)); isocks[id]->b_transport(trans, delay); } unsigned transport_dbg(tlm::tlm_generic_payload &trans) { auto addr = trans.get_address(); auto id = decode(addr); if (id < 0) { trans.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE); return 0; } trans.set_address(ports[id]->global_to_local(addr)); return isocks[id]->transport_dbg(trans); } }; #include "core/common/bus_lock_if.h" /* * Use this adapter to attach peripherals with write access (e.g. DMA) to the bus. * This ensures that those peripherals do not violate the RISC-V LR/SC atomic semantic. */ struct PeripheralWriteConnector : sc_core::sc_module { tlm_utils::simple_target_socket tsock; tlm_utils::simple_initiator_socket isock; std::shared_ptr bus_lock; PeripheralWriteConnector(sc_core::sc_module_name) { tsock.register_b_transport(this, &PeripheralWriteConnector::transport); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { bus_lock->wait_until_unlocked(); isock->b_transport(trans, delay); if (trans.get_response_status() == tlm::TLM_ADDRESS_ERROR_RESPONSE) throw std::runtime_error("unable to find target port for address " + std::to_string(trans.get_address())); } }; class BusLock : public bus_lock_if { bool locked = false; unsigned owner = 0; sc_core::sc_event lock_event; public: virtual void lock(unsigned hart_id) override { if (locked && (hart_id != owner)) { wait_until_unlocked(); } assert(!locked || (hart_id == owner)); locked = true; owner = hart_id; } virtual void unlock(unsigned hart_id) override { if (locked && (owner == hart_id)) { locked = false; lock_event.notify(sc_core::SC_ZERO_TIME); } } virtual bool is_locked() override { return locked; } virtual bool is_locked(unsigned hart_id) override { return locked && (owner == hart_id); } virtual void wait_until_unlocked() override { while (locked) sc_core::wait(lock_event); } }; #endif // RISCV_ISA_BUS_H ================================================ FILE: vp/src/platform/common/fd_abstract_uart.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include "fd_abstract_uart.h" #define stop_fd (stop_pipe[0]) #define newpollfd(FD) \ (struct pollfd){.fd = FD, .events = POLLIN | POLLERR, .revents = 0}; FD_ABSTRACT_UART::FD_ABSTRACT_UART(sc_core::sc_module_name name, uint32_t irqsrc) : UART_IF(name, irqsrc) { stop = false; if (pipe(stop_pipe) == -1) throw std::system_error(errno, std::generic_category()); } FD_ABSTRACT_UART::~FD_ABSTRACT_UART(void) { close(stop_pipe[0]); close(stop_pipe[1]); } void FD_ABSTRACT_UART::start_threads(int fd, bool write_only) { fds[0] = newpollfd(stop_fd); fds[1] = newpollfd(fd); if (!write_only) rcvthr = new std::thread(&FD_ABSTRACT_UART::receive, this); txthr = new std::thread(&FD_ABSTRACT_UART::transmit, this); } void FD_ABSTRACT_UART::stop_threads(void) { stop = true; if (txthr) { spost(&txfull); // unblock transmit thread txthr->join(); delete txthr; } if (rcvthr) { uint8_t byte = 0; if (write(stop_pipe[1], &byte, sizeof(byte)) == -1) // unblock receive thread err(EXIT_FAILURE, "couldn't unblock uart receive thread"); spost(&rxempty); // unblock receive thread rcvthr->join(); delete rcvthr; } } void FD_ABSTRACT_UART::transmit(void) { uint8_t data; while (!stop) { data = txpull(); if(stop) break; asyncEvent.notify(); write_data(data); } } void FD_ABSTRACT_UART::receive(void) { while (!stop) { if (poll(fds, (nfds_t)NFDS, -1) == -1) throw std::system_error(errno, std::generic_category()); /* stop_fd is checked first as it is fds[0] */ for (size_t i = 0; i < NFDS; i++) { int fd = fds[i].fd; short ev = fds[i].revents; if (ev & POLLERR) { throw std::runtime_error("received unexpected POLLERR"); } else if (ev & POLLIN) { if (fd == stop_fd) break; else handle_input(fd); } } } } ================================================ FILE: vp/src/platform/common/fd_abstract_uart.h ================================================ #pragma once #include #include #include #include #include #include "uart_if.h" class FD_ABSTRACT_UART : public UART_IF { public: FD_ABSTRACT_UART(sc_core::sc_module_name, uint32_t); virtual ~FD_ABSTRACT_UART(void); protected: void start_threads(int fd, bool write_only = false); void stop_threads(void); private: virtual void write_data(uint8_t) = 0; virtual void handle_input(int fd) = 0; void transmit(); void receive(); std::thread *rcvthr = NULL, *txthr = NULL; bool stop; int stop_pipe[2]; enum { NFDS = 2, }; struct pollfd fds[NFDS]; }; ================================================ FILE: vp/src/platform/common/fe310_plic.cpp ================================================ #include "fe310_plic.h" ================================================ FILE: vp/src/platform/common/fe310_plic.h ================================================ #pragma once #include #include #include "core/common/irq_if.h" #include "util/memory_map.h" #include "util/tlm_map.h" static constexpr bool trace_mode = false; /** * This class is supposed to implement the PLIC defined in Chapter 10 * of the FE310-G000 manual. Currently, it still has various differences * from the version documented in the manual. */ template struct FE310_PLIC : public sc_core::sc_module, public interrupt_gateway { static_assert(NumberInterrupts <= 4096, "out of bound"); static_assert(NumberCores <= 15360, "out of bound"); static constexpr unsigned WORDS_FOR_INTERRUPT_ENTRIES = (NumberInterruptEntries+(32-1))/32; tlm_utils::simple_target_socket tsock; std::array target_harts{}; // shared for all harts priority 1 is the lowest. Zero means do not interrupt // NOTE: addressing starts at 0x4 because interrupt 0 is reserved, however some example SW still writes to address // 0x0, hence we added it to the address map RegisterRange regs_interrupt_priorities{0x0, sizeof(uint32_t) * (NumberInterrupts + 1)}; ArrayView interrupt_priorities{regs_interrupt_priorities}; RegisterRange regs_pending_interrupts{0x1000, sizeof(uint32_t) * WORDS_FOR_INTERRUPT_ENTRIES}; ArrayView pending_interrupts{regs_pending_interrupts}; struct HartConfig { uint32_t priority_threshold; uint32_t claim_response; }; RegisterRange regs_hart_enabled_interrupts{0x2000, sizeof(uint32_t) * WORDS_FOR_INTERRUPT_ENTRIES * NumberCores}; ArrayView hart_enabled_interrupts{regs_hart_enabled_interrupts}; RegisterRange regs_hart_config{0x200000, sizeof(HartConfig) * NumberCores}; ArrayView hart_config{regs_hart_config}; std::vector register_ranges{®s_interrupt_priorities, ®s_pending_interrupts, ®s_hart_enabled_interrupts, ®s_hart_config }; PrivilegeLevel irq_level; std::array hart_eip{}; sc_core::sc_event e_run; sc_core::sc_time clock_cycle; SC_HAS_PROCESS(FE310_PLIC); FE310_PLIC(sc_core::sc_module_name, PrivilegeLevel level = MachineMode) { clock_cycle = sc_core::sc_time(10, sc_core::SC_NS); tsock.register_b_transport(this, &FE310_PLIC::transport); regs_pending_interrupts.readonly = true; regs_hart_config.alignment = 4; regs_interrupt_priorities.post_write_callback = std::bind(&FE310_PLIC::post_write_interrupt_priorities, this, std::placeholders::_1); regs_hart_config.post_write_callback = std::bind(&FE310_PLIC::post_write_hart_config, this, std::placeholders::_1); regs_hart_config.pre_read_callback = std::bind(&FE310_PLIC::pre_read_hart_config, this, std::placeholders::_1); if (trace_mode) { regs_hart_enabled_interrupts.post_write_callback = [this](RegisterRange::WriteInfo t){ std::cout << "[vp::plic] Wrote enabled_interrupts at offs +" << std::dec << t.addr << " value 0x" << std::hex << *reinterpret_cast(t.trans.get_data_ptr()) << std::dec << std::endl; for (unsigned n = 0; n < NumberCores; ++n) { for (unsigned i = 0; i < WORDS_FOR_INTERRUPT_ENTRIES; ++i) { const uint32_t itr_group = hart_enabled_interrupts(n, i); if(itr_group) { for(unsigned b = 0; b < 32; b++) { if((1 << b) & itr_group) { std::cout << "[vp::plic]\t Hart " << n << " ITR " << i*32 + b << " enabled." << std::dec << std::endl; } } } } } }; } for (unsigned i = 0; i < NumberInterrupts; ++i) { interrupt_priorities[i] = 0; } for (unsigned n = 0; n < NumberCores; ++n) { target_harts[n] = nullptr; hart_eip[n] = false; for (unsigned i = 0; i < WORDS_FOR_INTERRUPT_ENTRIES; ++i) { hart_enabled_interrupts(n, i) = 0; // all interrupts disabled by default } } irq_level = level; SC_THREAD(run); } void gateway_trigger_interrupt(uint32_t irq_id) { // NOTE: can use different techniques for each gateway, in this case a // simple non queued edge trigger assert(irq_id > 0 && irq_id < NumberInterrupts); //std::cout << "[vp::plic] incoming interrupt " << irq_id << std::endl; unsigned idx = irq_id / 32; unsigned off = irq_id % 32; pending_interrupts[idx] |= 1 << off; e_run.notify(clock_cycle); } void clear_pending_interrupt(unsigned irq_id) { assert(irq_id < NumberInterrupts); // NOTE: ignore clear of zero interrupt (zero is not available) if (trace_mode) std::cout << "[vp::plic] clear pending interrupt " << irq_id << std::endl; unsigned idx = irq_id / 32; unsigned off = irq_id % 32; pending_interrupts[idx] &= ~(1 << off); } unsigned hart_get_next_pending_interrupt(unsigned hart_id, bool consider_threshold) { unsigned min_id = 0; unsigned max_priority = 0; for (unsigned i = 1; i < NumberInterrupts; ++i) { unsigned idx = i / 32; unsigned off = i % 32; if (hart_enabled_interrupts(hart_id, idx) & (1 << off)) { if (trace_mode) std::cout << "[vp::plic] hart " << hart_id << " has enabled ITR " << i << std::endl; if (pending_interrupts[idx] & (1 << off)) { auto prio = interrupt_priorities[i]; if (trace_mode) std::cout << "[vp::plic] .. and it is pending with priority " << prio << std::endl; if (prio > 0 && (!consider_threshold || (prio > hart_config[hart_id].priority_threshold))) { if (trace_mode) std::cout << "[vp::plic] .. which is greater than the hart's threshold of " << hart_config[hart_id].priority_threshold << std::endl; if (prio > max_priority) { max_priority = prio; min_id = i; } } } } } return min_id; } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { delay += 4 * clock_cycle; //std::cout << "[vp::plic] Writing at 0x" << trans.get_address() << " value 0x" << *reinterpret_cast(trans.get_data_ptr()) << std::endl; vp::mm::route("FE310_PLIC", register_ranges, trans, delay); } void post_write_interrupt_priorities(RegisterRange::WriteInfo) { if (trace_mode) std::cout << "[vp::plic] wrote ITR priority:" << std::endl; unsigned i = 0; for (auto &x : interrupt_priorities) { x = std::min(x, MaxPriority); if (trace_mode) if(x) std::cout << "[vp::plic]\t Prio for ITR nr. " << i << ": " << x << std::endl; i++; } } bool pre_read_hart_config(RegisterRange::ReadInfo t) { assert(t.addr % 4 == 0); unsigned idx = t.addr / 4; if ((idx % 2) == 1) { // access is directed to claim response register assert(t.size == 4); --idx; unsigned min_id = hart_get_next_pending_interrupt(0, false); hart_config[idx].claim_response = min_id; clear_pending_interrupt(min_id); } return true; } void post_write_hart_config(RegisterRange::WriteInfo t) { assert(t.addr % 4 == 0); unsigned idx = t.addr / 4; if ((idx % 2) == 1) { // access is directed to claim response register assert(t.size == 4); --idx; if (trace_mode) std::cout << "[vp::plic] wrote ITR claim/response" << std::endl; if (hart_has_pending_enabled_interrupts(idx)) { assert(hart_eip[idx]); // trigger again to make this work even if the SW clears the harts interrupt pending bit target_harts[idx]->trigger_external_interrupt(irq_level); } else { hart_eip[idx] = false; target_harts[idx]->clear_external_interrupt(irq_level); if (trace_mode) std::cout << "[vp::plic] clear eip" << std::endl; } } else { if (trace_mode) std::cout << "[vp::plic] wrote ITR priority threshold 0x" << std::hex << *reinterpret_cast(t.trans.get_data_ptr()) << " for hart " << idx/2 << std::dec << std::endl; } } bool hart_has_pending_enabled_interrupts(unsigned hart_id) { return hart_get_next_pending_interrupt(hart_id, true) > 0; } void run() { while (true) { sc_core::wait(e_run); for (unsigned i = 0; i < NumberCores; ++i) { if (!hart_eip[i]) { if (hart_has_pending_enabled_interrupts(i)) { if (trace_mode) std::cout << "[vp::plic] trigger interrupt " << hart_get_next_pending_interrupt(i, true) << std::hex << std::endl; hart_eip[i] = true; target_harts[i]->trigger_external_interrupt(irq_level); } } } } } }; ================================================ FILE: vp/src/platform/common/fu540_plic.cpp ================================================ #include #include #include #include #include #include "core/common/irq_if.h" #include "util/memory_map.h" #include "util/tlm_map.h" #include "fu540_plic.h" inline uint32_t GET_IDX(uint32_t& irq) { return irq / 32; } inline uint32_t GET_OFF(uint32_t& irq) { return 1 << irq % 32; } /** * TODO: Ensure that irq 0 is hardwired to zero * TODO: FE310 raises external interrupt during interrupt completion */ static void assert_addr(size_t start, size_t end, RegisterRange *range) { assert(range->start == start && range->end + 1 == end + sizeof(uint32_t)); } FU540_PLIC::FU540_PLIC(sc_core::sc_module_name, unsigned harts) { target_harts = std::vector(harts, NULL); /* Values copied from FE310_PLIC */ clock_cycle = sc_core::sc_time(10, sc_core::SC_NS); create_registers(); tsock.register_b_transport(this, &FU540_PLIC::transport); SC_THREAD(run); }; void FU540_PLIC::create_registers(void) { regs_interrupt_priorities.post_write_callback = std::bind(&FU540_PLIC::write_irq_prios, this, std::placeholders::_1); /* make pending interrupts read-only */ regs_pending_interrupts.pre_write_callback = [] (RegisterRange::WriteInfo) { return false; }; /* The priorities end address, as documented in the FU540-C000 * manual, is incorrect */ assert_addr(0x4, 0xD4, ®s_interrupt_priorities); assert_addr(0x1000, 0x1004, ®s_pending_interrupts); register_ranges.push_back(®s_interrupt_priorities); register_ranges.push_back(®s_pending_interrupts); /* create IRQ enable and context registers */ create_hart_regs(ENABLE_BASE, ENABLE_PER_HART, enabled_irqs); create_hart_regs(CONTEXT_BASE, CONTEXT_PER_HART, hart_context); /* only supports "naturally aligned 32-bit memory accesses" */ for (size_t i = 0; i < register_ranges.size(); i++) register_ranges[i]->alignment = sizeof(uint32_t); } void FU540_PLIC::create_hart_regs(uint64_t addr, uint64_t inc, hartmap &map) { auto add_reg = [this, addr] (unsigned int h, PrivilegeLevel l, uint64_t a) { RegisterRange *r = new RegisterRange(a, HART_REG_SIZE); if (addr == CONTEXT_BASE) { r->pre_read_callback = std::bind(&FU540_PLIC::read_hartctx, this, std::placeholders::_1, h, l); r->post_write_callback = std::bind(&FU540_PLIC::write_hartctx, this, std::placeholders::_1, h, l); } register_ranges.push_back(r); return r; }; for (size_t i = 0; i < target_harts.size(); i++) { RegisterRange *mreg, *sreg; mreg = add_reg(i, MachineMode, addr); sreg = mreg; /* for hart0 */ if (i != 0) { /* hart 0 only supports m-mode interrupts */ addr += inc; sreg = add_reg(i, SupervisorMode, addr); } map[i] = new HartConfig(*mreg, *sreg); addr += inc; } } void FU540_PLIC::transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { delay += 4 * clock_cycle; /* copied from FE310_PLIC */ vp::mm::route("FU540_PLIC", register_ranges, trans, delay); }; void FU540_PLIC::gateway_trigger_interrupt(uint32_t irq) { if (irq == 0 || irq > NUMIRQ) throw std::invalid_argument("IRQ value is invalid"); pending_interrupts[GET_IDX(irq)] |= GET_OFF(irq); e_run.notify(clock_cycle); }; bool FU540_PLIC::read_hartctx(RegisterRange::ReadInfo t, unsigned int hart, PrivilegeLevel level) { assert(t.addr % sizeof(uint32_t) == 0); assert(t.size == sizeof(uint32_t)); if (is_claim_access(t.addr)) { unsigned int irq = next_pending_irq(hart, level, true); /* if there is no pending irq zero needs to be written * to the claim register. next_pending_irq returns 0 in * this case so no special handling required. */ switch (level) { case MachineMode: hart_context[hart]->m_mode[1] = irq; break; case SupervisorMode: hart_context[hart]->s_mode[1] = irq; break; default: assert(0); break; } /* successful claim also clears the pending bit */ if (irq != 0) clear_pending(irq); } return true; } void FU540_PLIC::write_hartctx(RegisterRange::WriteInfo t, unsigned int hart, PrivilegeLevel level) { assert(t.addr % sizeof(uint32_t) == 0); assert(t.size == sizeof(uint32_t)); if (is_claim_access(t.addr)) { target_harts[hart]->clear_external_interrupt(level); } else { /* access to priority threshold */ uint32_t *thr; switch (level) { case MachineMode: thr = &hart_context[hart]->m_mode[0]; break; case SupervisorMode: thr = &hart_context[hart]->s_mode[0]; break; default: assert(0); break; } *thr = std::min(*thr, uint32_t(MAX_THR)); } } void FU540_PLIC::write_irq_prios(RegisterRange::WriteInfo t) { size_t idx = t.addr / sizeof(uint32_t); assert(idx <= NUMIRQ); auto &elem = interrupt_priorities[idx]; elem = std::min(elem, uint32_t(MAX_PRIO)); } void FU540_PLIC::run(void) { for (;;) { sc_core::wait(e_run); for (size_t i = 0; i < target_harts.size(); i++) { PrivilegeLevel lvl; if (has_pending_irq(i, &lvl)) { target_harts[i]->trigger_external_interrupt(lvl); } } } } /* Returns next enabled pending interrupt with highest priority */ unsigned int FU540_PLIC::next_pending_irq(unsigned int hart, PrivilegeLevel lvl, bool ignth) { assert(!(hart == 0 && lvl == SupervisorMode)); HartConfig *conf = enabled_irqs[hart]; unsigned int selirq = 0, maxpri = 0; for (unsigned irq = 1; irq <= NUMIRQ; irq++) { if (!conf->is_enabled(irq, lvl) || !is_pending(irq)) continue; uint32_t prio = interrupt_priorities[irq - 1]; if (!ignth && prio <= get_threshold(hart, lvl)) continue; if (prio > maxpri) { maxpri = prio; selirq = irq; } } return selirq; } bool FU540_PLIC::has_pending_irq(unsigned int hart, PrivilegeLevel *level) { if (hart != 0 && next_pending_irq(hart, SupervisorMode, false) > 0) { *level = SupervisorMode; return true; } else if (next_pending_irq(hart, MachineMode, false) > 0) { *level = MachineMode; return true; } else { return false; } } uint32_t FU540_PLIC::get_threshold(unsigned int hart, PrivilegeLevel level) { if (hart == 0 && level == SupervisorMode) throw std::invalid_argument("hart0 doesn't support SupervisorMode"); HartConfig *conf = hart_context[hart]; switch (level) { case MachineMode: return conf->m_mode[0]; break; case SupervisorMode: return conf->s_mode[0]; break; default: throw std::invalid_argument("Invalid PrivilegeLevel"); } } void FU540_PLIC::clear_pending(unsigned int irq) { assert(irq > 0 && irq <= NUMIRQ); pending_interrupts[GET_IDX(irq)] &= ~(GET_OFF(irq)); } bool FU540_PLIC::is_pending(unsigned int irq) { assert(irq > 0 && irq <= NUMIRQ); return pending_interrupts[GET_IDX(irq)] & GET_OFF(irq); } bool FU540_PLIC::is_claim_access(uint64_t addr) { unsigned idx = addr / sizeof(uint32_t); return (idx % 2) == 1; } bool FU540_PLIC::HartConfig::is_enabled(unsigned int irq, PrivilegeLevel level) { assert(irq > 0 && irq <= NUMIRQ); unsigned int idx = GET_IDX(irq); unsigned int off = GET_OFF(irq); switch (level) { case MachineMode: return m_mode[idx] & off; case SupervisorMode: return s_mode[idx] & off; default: assert(0); } return false; } ================================================ FILE: vp/src/platform/common/fu540_plic.h ================================================ #pragma once #include #include /** * This class implements a Platform-Level Interrupt Controller (PLIC) as * defined in chapter 10 of the SiFive FU540-C000 manual. */ struct FU540_PLIC : public sc_core::sc_module, public interrupt_gateway { public: static constexpr int NUMIRQ = 53; static constexpr uint32_t MAX_THR = 7; static constexpr uint32_t MAX_PRIO = 7; static constexpr uint32_t ENABLE_BASE = 0x2000; static constexpr uint32_t ENABLE_PER_HART = 0x80; static constexpr uint32_t CONTEXT_BASE = 0x200000; static constexpr uint32_t CONTEXT_PER_HART = 0x1000; static constexpr uint32_t HART_REG_SIZE = 2 * sizeof(uint32_t); tlm_utils::simple_target_socket tsock; std::vector target_harts{}; FU540_PLIC(sc_core::sc_module_name, unsigned harts = 5); void gateway_trigger_interrupt(uint32_t); SC_HAS_PROCESS(FU540_PLIC); private: class HartConfig { public: ArrayView m_mode; ArrayView s_mode; /* same as m_mode for hart0 */ HartConfig(RegisterRange &r1, RegisterRange &r2) : m_mode(r1), s_mode(r2) { return; } bool is_enabled(unsigned int, PrivilegeLevel); }; sc_core::sc_event e_run; sc_core::sc_time clock_cycle; std::vector register_ranges; /* hart_id (0..4) → hart_config */ typedef std::map hartmap; hartmap enabled_irqs; hartmap hart_context; /* See Section 10.3 */ RegisterRange regs_interrupt_priorities{0x4, sizeof(uint32_t) * NUMIRQ}; ArrayView interrupt_priorities{regs_interrupt_priorities}; /* See Section 10.4 */ RegisterRange regs_pending_interrupts{0x1000, sizeof(uint32_t) * 2}; ArrayView pending_interrupts{regs_pending_interrupts}; void create_registers(void); void create_hart_regs(uint64_t, uint64_t, hartmap&); void transport(tlm::tlm_generic_payload&, sc_core::sc_time&); bool read_hartctx(RegisterRange::ReadInfo, unsigned int, PrivilegeLevel); void write_hartctx(RegisterRange::WriteInfo, unsigned int, PrivilegeLevel); void write_irq_prios(RegisterRange::WriteInfo); void run(void); unsigned int next_pending_irq(unsigned int, PrivilegeLevel, bool); bool has_pending_irq(unsigned int, PrivilegeLevel*); uint32_t get_threshold(unsigned int, PrivilegeLevel); void clear_pending(unsigned int); bool is_pending(unsigned int); bool is_claim_access(uint64_t addr); }; ================================================ FILE: vp/src/platform/common/memory.h ================================================ #ifndef RISCV_ISA_MEMORY_H #define RISCV_ISA_MEMORY_H #include #include #include #include "bus.h" #include "load_if.h" #include #include struct SimpleMemory : public sc_core::sc_module, public load_if { tlm_utils::simple_target_socket tsock; uint8_t *data; uint32_t size; bool read_only; SimpleMemory(sc_core::sc_module_name, uint32_t size, bool read_only = false) : data(new uint8_t[size]()), size(size), read_only(read_only) { tsock.register_b_transport(this, &SimpleMemory::transport); tsock.register_get_direct_mem_ptr(this, &SimpleMemory::get_direct_mem_ptr); tsock.register_transport_dbg(this, &SimpleMemory::transport_dbg); } ~SimpleMemory(void) { delete[] data; } void load_data(const char *src, uint64_t dst_addr, size_t n) override { assert(dst_addr + n <= size); memcpy(&data[dst_addr], src, n); } void load_zero(uint64_t dst_addr, size_t n) override { assert(dst_addr + n <= size); memset(&data[dst_addr], 0, n); } void load_binary_file(const std::string &filename, unsigned addr) { boost::iostreams::mapped_file_source f(filename); assert(f.is_open()); write_data(addr, (const uint8_t *)f.data(), f.size()); } void write_data(unsigned addr, const uint8_t *src, unsigned num_bytes) { assert(addr + num_bytes <= size); memcpy(data + addr, src, num_bytes); } void read_data(unsigned addr, uint8_t *dst, unsigned num_bytes) { assert(addr + num_bytes <= size); memcpy(dst, data + addr, num_bytes); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { transport_dbg(trans); delay += sc_core::sc_time(10, sc_core::SC_NS); } unsigned transport_dbg(tlm::tlm_generic_payload &trans) { tlm::tlm_command cmd = trans.get_command(); unsigned addr = trans.get_address(); auto *ptr = trans.get_data_ptr(); auto len = trans.get_data_length(); assert(addr < size); if (cmd == tlm::TLM_WRITE_COMMAND) { write_data(addr, ptr, len); } else if (cmd == tlm::TLM_READ_COMMAND) { read_data(addr, ptr, len); } else { sc_assert(false && "unsupported tlm command"); } return len; } bool get_direct_mem_ptr(tlm::tlm_generic_payload &trans, tlm::tlm_dmi &dmi) { (void)trans; dmi.set_start_address(0); dmi.set_end_address(size); dmi.set_dmi_ptr(data); if (read_only) dmi.allow_read(); else dmi.allow_read_write(); return true; } }; #endif // RISCV_ISA_MEMORY_H ================================================ FILE: vp/src/platform/common/memory_mapped_file.h ================================================ #pragma once #include #include //truncate #include //file IO #include #include #include #include "bus.h" using namespace std; using namespace sc_core; using namespace tlm_utils; struct MemoryMappedFile : public sc_core::sc_module { simple_target_socket tsock; string mFilepath; uint32_t mSize; fstream file; MemoryMappedFile(sc_module_name, string &filepath, uint32_t size) : mFilepath(filepath), mSize(size) { tsock.register_b_transport(this, &MemoryMappedFile::transport); if (filepath.size() == 0 || size == 0) { // no file return; } file.open(mFilepath, ofstream::in | ofstream::out | ofstream::binary); if (!file.is_open() || !file.good()) { // cout << "Failed to open " << mFilepath << ": " << strerror(errno) // << endl; file.open(mFilepath, ofstream::in | ofstream::out | ofstream::binary | ios_base::trunc); } int stat = truncate(mFilepath.c_str(), mSize); assert(stat == 0 && "truncate failed"); assert(file.is_open() && file.good() && "File could not be opened"); } ~MemoryMappedFile() { file.close(); } void write_data(unsigned addr, uint8_t *src, unsigned num_bytes) { assert(addr + num_bytes <= mSize); file.seekg(addr, file.beg); file.write(reinterpret_cast(src), num_bytes); if (!file.is_open() || !file.good()) { cout << "Failed to write " << mFilepath << ": " << strerror(errno) << endl; } } void read_data(unsigned addr, uint8_t *dst, unsigned num_bytes) { assert(addr + num_bytes <= mSize); file.seekg(addr, file.beg); file.read(reinterpret_cast(dst), num_bytes); if (!file.is_open() || !file.good()) { cout << "Failed to read " << mFilepath << ": " << strerror(errno) << endl; } } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { tlm::tlm_command cmd = trans.get_command(); unsigned addr = trans.get_address(); auto *ptr = trans.get_data_ptr(); auto len = trans.get_data_length(); assert(addr < mSize); if (cmd == tlm::TLM_WRITE_COMMAND) { write_data(addr, ptr, len); } else if (cmd == tlm::TLM_READ_COMMAND) { read_data(addr, ptr, len); } else { sc_assert(false && "unsupported tlm command"); } delay += sc_core::sc_time(len * 30, sc_core::SC_NS); } }; ================================================ FILE: vp/src/platform/common/options.cpp ================================================ #include "options.h" #include #include #include namespace po = boost::program_options; Options::Options(void) { // clang-format off add_options() ("help", "produce help message") ("intercept-syscalls", po::bool_switch(&intercept_syscalls), "directly intercept and handle syscalls in the ISS (testing mode)") ("error-on-zero-traphandler", po::value(&error_on_zero_traphandler), "Assume that taking an unset (zero) trap handler in machine mode is an error condition (which it usually is)") ("debug-mode", po::bool_switch(&use_debug_runner), "start execution in debugger (using gdb rsp interface)") ("debug-port", po::value(&debug_port), "select port number to connect with GDB") ("trace-mode", po::bool_switch(&trace_mode), "enable instruction tracing") ("tlm-global-quantum", po::value(&tlm_global_quantum), "set global tlm quantum (in NS)") ("use-instr-dmi", po::bool_switch(&use_instr_dmi), "use dmi to fetch instructions") ("use-data-dmi", po::bool_switch(&use_data_dmi), "use dmi to execute load/store operations") ("use-dmi", po::bool_switch(), "use instr and data dmi") ("input-file", po::value(&input_program)->required(), "input file to use for execution"); // clang-format on pos.add("input-file", 1); } Options::~Options(){}; void Options::parse(int argc, char **argv) { try { auto parser = po::command_line_parser(argc, argv); parser.options(*this).positional(pos); po::store(parser.run(), vm); if (vm.count("help")) { std::cout << *this << std::endl; exit(0); } po::notify(vm); if (vm["use-dmi"].as()) { use_data_dmi = true; use_instr_dmi = true; } if (vm["intercept-syscalls"].as() && vm.count("error-on-zero-traphandler") == 0) { // intercept syscalls active, but no overriding error-on-zero-traphandler switch std::cerr << "[Options] Info: switch 'intercept-syscalls' also activates 'error-on-zero-traphandler' if unset." << std::endl; error_on_zero_traphandler = true; } } catch (po::error &e) { std::cerr << "Error parsing command line options: " << e.what() << std::endl; std::cout << *this << std::endl; exit(1); } } void Options::printValues(std::ostream& os) const { os << std::dec; os << "intercept_syscalls: " << intercept_syscalls << std::endl; os << "error-on-zero-traphandler: " << error_on_zero_traphandler << std::endl; os << "use_debug_runner: " << use_debug_runner << std::endl; os << "debug_port: " << debug_port << std::endl; os << "trace_mode: " << trace_mode << std::endl; os << "tlm_global_quantum: " << tlm_global_quantum << std::endl; os << "use_instr_dmi: " << use_instr_dmi << std::endl; os << "use_data_dmi: " << use_data_dmi << std::endl; } ================================================ FILE: vp/src/platform/common/options.h ================================================ #ifndef RISCV_VP_OPTIONS_H #define RISCV_VP_OPTIONS_H #include #include class Options : public boost::program_options::options_description { public: Options(void); virtual ~Options(); virtual void parse(int argc, char **argv); std::string input_program; bool intercept_syscalls = false; bool error_on_zero_traphandler = false; bool use_debug_runner = false; unsigned int debug_port = 5005; bool trace_mode = false; unsigned int tlm_global_quantum = 10; bool use_instr_dmi = false; bool use_data_dmi = false; virtual void printValues(std::ostream& os = std::cout) const; private: boost::program_options::positional_options_description pos; boost::program_options::variables_map vm; }; #endif ================================================ FILE: vp/src/platform/common/slip.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "slip.h" // SLIP (as defined in RFC 1055) doesn't specify an MTU. We therefore // subsequently allocate memory for the packet buffer using realloc(3). #define SLIP_SNDBUF_STEP 1500 #define SLIP_END 0300 #define SLIP_ESC 0333 #define SLIP_ESC_END 0334 #define SLIP_ESC_ESC 0335 SLIP::SLIP(const sc_core::sc_module_name &name, uint32_t irqsrc, std::string netdev) : FD_ABSTRACT_UART(name, irqsrc) { tunfd = open("/dev/net/tun", O_RDWR); if (tunfd == -1) goto err0; struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* read/write raw IP packets */ strncpy(ifr.ifr_name, netdev.c_str(), IFNAMSIZ); if (ioctl(tunfd, TUNSETIFF, (void *)&ifr) == -1) goto err1; sndsiz = 0; if (!(sndbuf = (uint8_t *)malloc(SLIP_SNDBUF_STEP * sizeof(uint8_t)))) goto err1; rcvsiz = get_mtu(ifr.ifr_name); if (!(rcvbuf = (uint8_t *)malloc(rcvsiz * sizeof(uint8_t)))) goto err2; start_threads(tunfd); return; err2: free(sndbuf); sndbuf = NULL; err1: close(tunfd); err0: std::system_error(errno, std::generic_category()); } SLIP::~SLIP(void) { stop_threads(); if (sndbuf) { free(sndbuf); sndbuf = NULL; } if (rcvbuf) { free(rcvbuf); rcvbuf = NULL; } if (tunfd > 0) close(tunfd); } int SLIP::get_mtu(const char *dev) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, dev, IFNAMSIZ); int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd == -1) throw std::system_error(errno, std::generic_category()); if (ioctl(fd, SIOCGIFMTU, (void *)&ifr) == -1) { close(fd); throw std::system_error(errno, std::generic_category()); } close(fd); return ifr.ifr_mtu; } void SLIP::send_packet(void) { ssize_t ret = write(tunfd, sndbuf, sndsiz); if (ret == -1) { throw std::system_error(errno, std::generic_category()); } else if ((size_t)ret != sndsiz) { throw std::runtime_error("short write"); } if (sndsiz > SLIP_SNDBUF_STEP && !(sndbuf = (uint8_t *)realloc(sndbuf, SLIP_SNDBUF_STEP))) throw std::system_error(errno, std::generic_category()); sndsiz = 0; } void SLIP::handle_input(int fd) { ssize_t ret = read(fd, rcvbuf, rcvsiz); if (ret <= -1) throw std::system_error(errno, std::generic_category()); for (size_t i = 0; i < static_cast(ret); i++) { switch (rcvbuf[i]) { case SLIP_END: rxpush(SLIP_ESC); rxpush(SLIP_ESC_END); break; case SLIP_ESC: rxpush(SLIP_ESC); rxpush(SLIP_ESC_ESC); break; default: rxpush(rcvbuf[i]); break; } } rxpush(SLIP_END); } void SLIP::write_data(uint8_t data) { if (data == SLIP_END) { if (sndsiz > 0) send_packet(); return; } if (sndsiz > 0 && sndbuf[sndsiz - 1] == SLIP_ESC) { switch (data) { case SLIP_ESC_END: sndbuf[sndsiz - 1] = SLIP_END; return; case SLIP_ESC_ESC: sndbuf[sndsiz - 1] = SLIP_ESC; return; } } if (sndsiz && sndsiz % SLIP_SNDBUF_STEP == 0) { size_t newsiz = (sndsiz + SLIP_SNDBUF_STEP) * sizeof(uint8_t); if (!(sndbuf = (uint8_t *)realloc(sndbuf, newsiz))) throw std::system_error(errno, std::generic_category()); } sndbuf[sndsiz++] = data; } ================================================ FILE: vp/src/platform/common/slip.h ================================================ #ifndef RISCV_VP_SLIP_H #define RISCV_VP_SLIP_H #include #include #include class SLIP : public FD_ABSTRACT_UART { public: SLIP(const sc_core::sc_module_name &, uint32_t, std::string); ~SLIP(void); private: int get_mtu(const char *); void send_packet(void); void write_data(uint8_t) override; void handle_input(int fd) override; int tunfd; uint8_t *sndbuf = NULL, *rcvbuf = NULL; size_t sndsiz, rcvsiz; }; #endif // RISCV_VP_SLIP_H ================================================ FILE: vp/src/platform/common/terminal.h ================================================ #ifndef RISCV_ISA_TERMINAL_H #define RISCV_ISA_TERMINAL_H #include #include struct SimpleTerminal : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; SimpleTerminal(sc_core::sc_module_name) { tsock.register_b_transport(this, &SimpleTerminal::transport); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { sc_assert(trans.get_command() == tlm::TLM_WRITE_COMMAND); sc_assert(trans.get_data_length() == 1); std::cout << (char)*trans.get_data_ptr(); delay += (sc_core::sc_time(1, sc_core::sc_time_unit::SC_US)); } }; #endif // RISCV_ISA_TERMINAL_H ================================================ FILE: vp/src/platform/common/uart.cpp ================================================ #include "uart.h" #include "core/common/rawmode.h" #include #include #include #include #include /* character → control key */ #define CTRL(c) ((c) & 0x1f) #define KEY_ESC CTRL('a') /* Ctrl-a (character to enter command mode) */ #define KEY_EXIT 'x' /* x (character to exit in command mode) */ #define KEY_CEXIT CTRL(KEY_EXIT) /* Ctrl-x (character to exit in command mode) */ UART::UART(const sc_core::sc_module_name& name, uint32_t irqsrc) : FD_ABSTRACT_UART(name, irqsrc) { // If stdin isn't a tty, it doesn't make much sense to poll from it. // In this case, we will run the UART in write-only mode. bool write_only = !isatty(STDIN_FILENO); enableRawMode(STDIN_FILENO); start_threads(STDIN_FILENO, write_only); } UART::~UART(void) { stop_threads(); disableRawMode(STDIN_FILENO); } void UART::handle_input(int fd) { uint8_t buf; ssize_t nread; nread = read(fd, &buf, sizeof(buf)); if (nread == -1) throw std::system_error(errno, std::generic_category()); else if (nread != sizeof(buf)) throw std::runtime_error("short read"); switch (state) { case STATE_NORMAL: if(buf != KEY_ESC) // filter out first esc sequence rxpush(buf); break; case STATE_COMMAND: handle_cmd(buf); break; } /* update state of input state machine for next run */ if (buf == KEY_ESC && state != STATE_COMMAND) { state = STATE_COMMAND; } else { state = STATE_NORMAL; } } void UART::handle_cmd(uint8_t cmd) { switch (cmd) { case KEY_ESC: /* double escape */ rxpush(cmd); break; case KEY_EXIT: case KEY_CEXIT: exit(EXIT_SUCCESS); break; default: return; /* unknown command → ignore */ } } void UART::write_data(uint8_t data) { ssize_t nwritten; nwritten = write(STDOUT_FILENO, &data, sizeof(data)); if (nwritten == -1) throw std::system_error(errno, std::generic_category()); else if (nwritten != sizeof(data)) throw std::runtime_error("short write"); } ================================================ FILE: vp/src/platform/common/uart.h ================================================ #ifndef RISCV_VP_UART_H #define RISCV_VP_UART_H #include #include #include class UART : public FD_ABSTRACT_UART { public: UART(const sc_core::sc_module_name&, uint32_t); virtual ~UART(void); private: typedef enum { STATE_COMMAND, STATE_NORMAL, } uart_state; /** * State of the input handling state machine. In normal mode * (STATE_NORMAL) the next input character is forwarded to the * guest. In command mode (STATE_COMMAND) the next input * character is interpreted by ::handle_cmd. */ uart_state state = STATE_NORMAL; void handle_cmd(uint8_t); void handle_input(int fd) override; void write_data(uint8_t) override; }; #endif // RISCV_VP_UART_H ================================================ FILE: vp/src/platform/common/uart16550.h ================================================ #pragma once #include #include #include "util/memory_map.h" #include #include #include struct UART16550 : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; // memory mapped configuration registers RegisterRange mm_regs{0x0, 8}; ArrayView regs{mm_regs}; std::vector register_ranges{&mm_regs}; std::deque rx_fifo; bool initialized = false; static constexpr unsigned QUEUE_ADDR = 0; static constexpr unsigned LINESTAT_ADDR = 5; static constexpr unsigned STATUS_RX = 0x01; static constexpr unsigned STATUS_TX = 0x20; struct termios orig_termios; UART16550(sc_core::sc_module_name) { tsock.register_b_transport(this, &UART16550::transport); int flags = fcntl(0, F_GETFL, 0); fcntl(0, F_SETFL, flags | O_NONBLOCK); tcgetattr(STDIN_FILENO, &orig_termios); struct termios raw = orig_termios; raw.c_lflag &= ~(ICANON); // Bytewise read tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw); mm_regs.pre_read_callback = std::bind(&UART16550::pre_read_regs, this, std::placeholders::_1); mm_regs.post_write_callback = std::bind(&UART16550::post_write_regs, this, std::placeholders::_1); } ~UART16550() { tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios); } void try_receive_char() { if (rx_fifo.empty()) { char c; if (read(0, &c, 1) >= 0) { rx_fifo.push_back(c); } } } uint8_t take_next_char() { try_receive_char(); if (rx_fifo.empty()) return -1; uint8_t ans = rx_fifo.front(); rx_fifo.pop_front(); return ans; } bool pre_read_regs(RegisterRange::ReadInfo t) { if (t.addr == LINESTAT_ADDR) { regs[LINESTAT_ADDR] = 0; regs[LINESTAT_ADDR] |= STATUS_TX; try_receive_char(); if (!rx_fifo.empty()) regs[LINESTAT_ADDR] |= STATUS_RX; } else if (t.addr == QUEUE_ADDR) { regs[QUEUE_ADDR] = take_next_char(); } return true; } void post_write_regs(RegisterRange::WriteInfo t) { if (t.addr == QUEUE_ADDR) { uint8_t data = *t.trans.get_data_ptr(); if (!initialized) { initialized = true; if (data == 0) return; } std::cout << static_cast(data); fflush(stdout); } } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { vp::mm::route("UART16550", register_ranges, trans, delay); } }; ================================================ FILE: vp/src/platform/common/uart_if.cpp ================================================ #include #include #include #include #include #include #include UART_IF::UART_IF(sc_core::sc_module_name, uint32_t irqsrc) : plic(nullptr){ irq = irqsrc; tsock.register_b_transport(this, &UART_IF::transport); router.add_register_bank({ {TXDATA_REG_ADDR, &txdata}, {RXDATA_REG_ADDR, &rxdata}, {TXCTRL_REG_ADDR, &txctrl}, {RXCTRL_REG_ADDR, &rxctrl}, {IE_REG_ADDR, &ie}, {IP_REG_ADDR, &ip}, {DIV_REG_ADDR, &div}, }) .register_handler(this, &UART_IF::register_access_callback); if (sem_init(&txfull, 0, 0)) throw std::system_error(errno, std::generic_category()); if (sem_init(&rxempty, 0, UART_FIFO_DEPTH)) throw std::system_error(errno, std::generic_category()); SC_METHOD(interrupt); sensitive << asyncEvent; dont_initialize(); } UART_IF::~UART_IF(void) { sem_destroy(&txfull); sem_destroy(&rxempty); } void UART_IF::rxpush(uint8_t data) { swait(&rxempty); rcvmtx.lock(); rx_fifo.push(data); rcvmtx.unlock(); asyncEvent.notify(); } uint8_t UART_IF::txpull() { uint8_t data; swait(&txfull); if(tx_fifo.size() == 0) // Other thread will only increase count, not decrease return 0; txmtx.lock(); data = tx_fifo.front(); tx_fifo.pop(); txmtx.unlock(); return data; } void UART_IF::register_access_callback(const vp::map::register_access_t &r) { if (r.read) { if (r.vptr == &txdata) { txmtx.lock(); txdata = (tx_fifo.size() >= UART_FIFO_DEPTH) ? UART_FULL : 0; txmtx.unlock(); } else if (r.vptr == &rxdata) { rcvmtx.lock(); if (rx_fifo.empty()) { rxdata = 1 << 31; } else { rxdata = rx_fifo.front(); rx_fifo.pop(); spost(&rxempty); } rcvmtx.unlock(); } else if (r.vptr == &txctrl) { // std::cout << "TXctl"; } else if (r.vptr == &rxctrl) { // std::cout << "RXctrl"; } else if (r.vptr == &ip) { uint32_t ret = 0; txmtx.lock(); if (tx_fifo.size() < UART_CTRL_CNT(txctrl)) { ret |= UART_TXWM; } txmtx.unlock(); rcvmtx.lock(); if (rx_fifo.size() > UART_CTRL_CNT(rxctrl)) { ret |= UART_RXWM; } rcvmtx.unlock(); ip = ret; } else if (r.vptr == &ie) { // do nothing } else if (r.vptr == &div) { // just return the last set value } else { std::cerr << "invalid offset for UART " << std::endl; } } bool notify = false; if (r.write) { if (r.vptr == &txctrl && UART_CTRL_CNT(r.nv) < UART_CTRL_CNT(txctrl)) notify = true; else if (r.vptr == &rxctrl && UART_CTRL_CNT(r.nv) < UART_CTRL_CNT(rxctrl)) notify = true; } r.fn(); if (notify || (r.write && r.vptr == &ie)) asyncEvent.notify(); if (r.write && r.vptr == &txdata) { // from SoC to remote txmtx.lock(); if (tx_fifo.size() >= UART_FIFO_DEPTH) { txmtx.unlock(); return; /* write is ignored */ } tx_fifo.push(txdata); txmtx.unlock(); spost(&txfull); } } void UART_IF::transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { router.transport(trans, delay); } void UART_IF::interrupt(void) { bool trigger = false; /* XXX: Possible optimization would be to trigger the * interrupt from the background thread. However, * the PLIC methods are very likely not thread safe. */ if (ie & UART_RXWM) { rcvmtx.lock(); if (rx_fifo.size() > UART_CTRL_CNT(rxctrl)) trigger = true; rcvmtx.unlock(); } if (ie & UART_TXWM) { txmtx.lock(); if (tx_fifo.size() < UART_CTRL_CNT(txctrl)) trigger = true; txmtx.unlock(); } if (trigger) plic->gateway_trigger_interrupt(irq); } void UART_IF::swait(sem_t *sem) { if (sem_wait(sem)) throw std::system_error(errno, std::generic_category()); } void UART_IF::spost(sem_t *sem) { if (sem_post(sem)) throw std::system_error(errno, std::generic_category()); } ================================================ FILE: vp/src/platform/common/uart_if.h ================================================ #pragma once #include #include #include #include #include #include #include #include #include #include "core/common/irq_if.h" #include "util/tlm_map.h" #include "platform/common/async_event.h" class UART_IF : public sc_core::sc_module { public: typedef uint32_t Register; static constexpr Register UART_TXWM = 1 << 0; static constexpr Register UART_RXWM = 1 << 1; static constexpr Register UART_FULL = 1 << 31; /* 8-entry transmit and receive FIFO buffers */ static constexpr unsigned UART_FIFO_DEPTH = 8; /* Extracts the interrupt trigger threshold from a control register */ static constexpr Register UART_CTRL_CNT(Register REG){ return REG >> 16;}; static constexpr uint8_t TXDATA_REG_ADDR = 0x0; static constexpr uint8_t RXDATA_REG_ADDR = 0x4; static constexpr uint8_t TXCTRL_REG_ADDR = 0x8; static constexpr uint8_t RXCTRL_REG_ADDR = 0xC; static constexpr uint8_t IE_REG_ADDR = 0x10; static constexpr uint8_t IP_REG_ADDR = 0x14; static constexpr uint8_t DIV_REG_ADDR = 0x18; interrupt_gateway *plic; tlm_utils::simple_target_socket tsock; UART_IF(sc_core::sc_module_name, uint32_t irqsrc); virtual ~UART_IF(void); SC_HAS_PROCESS(UART_IF); // interrupt private: void register_access_callback(const vp::map::register_access_t &); void transport(tlm::tlm_generic_payload &, sc_core::sc_time &); void interrupt(void); uint32_t irq; // memory mapped configuration registers uint32_t txdata = 0; uint32_t rxdata = 0; uint32_t txctrl = 0; uint32_t rxctrl = 0; uint32_t ie = 0; uint32_t ip = 0; uint32_t div = 0; vp::map::LocalRouter router = {"UART"}; protected: std::queue tx_fifo; sem_t txfull; std::queue rx_fifo; sem_t rxempty; std::mutex rcvmtx, txmtx; AsyncEvent asyncEvent; void swait(sem_t *sem); void spost(sem_t *sem); // blocking push into SoC void rxpush(uint8_t data); // blocking pull from SoC to remote uint8_t txpull(); }; ================================================ FILE: vp/src/platform/common/util.h ================================================ #pragma once #include "util/common.h" #include #include /* A simple memory block that provides arbitrary read/write access. */ struct BlankDevice : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; unsigned size; uint8_t *data; BlankDevice(sc_core::sc_module_name, unsigned size) : size(size), data(new uint8_t[size]) { tsock.register_b_transport(this, &BlankDevice::transport); } ~BlankDevice() { delete[] data; data = 0; } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { UNUSED(delay); assert(data); assert(trans.get_address() + trans.get_data_length() <= size); if (trans.get_command() == tlm::TLM_READ_COMMAND) { memcpy(trans.get_data_ptr(), data + trans.get_address(), trans.get_data_length()); } else if (trans.get_command() == tlm::TLM_WRITE_COMMAND) { memcpy(data + trans.get_address(), trans.get_data_ptr(), trans.get_data_length()); } else { throw std::runtime_error("unsupported TLM command"); } } }; /* Ignores all write accesses and always returns zero on any read access. */ struct ZeroDevice : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; ZeroDevice(sc_core::sc_module_name) { tsock.register_b_transport(this, &ZeroDevice::transport); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { UNUSED(delay); if (trans.get_command() == tlm::TLM_READ_COMMAND) { memset(trans.get_data_ptr(), 0, trans.get_data_length()); } } }; /* Simple UART/terminal, e.g. this implementation matches the HiFive1 board write address and is already sufficient to * print characters in Zephyr OS examples. */ struct SimpleUART : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; SimpleUART(sc_core::sc_module_name) { tsock.register_b_transport(this, &SimpleUART::transport); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { UNUSED(delay); if (trans.get_command() == tlm::TLM_WRITE_COMMAND) { if (trans.get_address() == 0x0) { std::cout << static_cast(*trans.get_data_ptr()); fflush(stdout); } } } }; ================================================ FILE: vp/src/platform/hifive/CMakeLists.txt ================================================ add_executable(hifive-vp hifive_main.cpp can.cpp oled/common.cpp oled/oled.cpp gpio.cpp tunnel-uart.cpp ../../util/elegantEnums.cpp #sorry :( ${HEADERS}) add_git_submodule(vbb-protocol) target_link_libraries(hifive-vp virtual-breadboard-server rv32 platform-common gdb-mc ${Boost_LIBRARIES} systemc pthread) INSTALL(TARGETS hifive-vp RUNTIME DESTINATION bin) ================================================ FILE: vp/src/platform/hifive/aon.h ================================================ #ifndef RISCV_VP_AON_H #define RISCV_VP_AON_H #include #include #include "core/common/irq_if.h" #include "util/tlm_map.h" struct AON : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; uint32_t wdogcfg = 0; uint32_t wdogcount = 0; uint32_t wdogfeed = 0; uint32_t wdogkey = 0; uint32_t wdogcmp0 = 0; uint32_t lfrosccfg = 0; uint32_t pmucause = 1 << 8; uint32_t rtccfg = 0; uint32_t rtccountlo = 0; uint32_t rtccounthi = 0; uint32_t rtcs = 0; uint32_t rtccmp0 = 0; uint32_t backup0 = 0; uint32_t backup1 = 0; uint32_t backup2 = 0; uint32_t backup3 = 0; uint32_t backup4 = 0; uint32_t backup5 = 0; uint32_t backup6 = 0; uint32_t backup7 = 0; uint32_t backup8 = 0; uint32_t backup9 = 0; uint32_t backup10 = 0; uint32_t backup11 = 0; uint32_t backup12 = 0; uint32_t backup13 = 0; uint32_t backup14 = 0; uint32_t backup15 = 0; uint32_t backup16 = 0; uint32_t backup17 = 0; uint32_t backup18 = 0; uint32_t backup19 = 0; uint32_t backup20 = 0; uint32_t backup21 = 0; uint32_t backup22 = 0; uint32_t backup23 = 0; uint32_t backup24 = 0; uint32_t backup25 = 0; uint32_t backup26 = 0; uint32_t backup27 = 0; uint32_t backup28 = 0; uint32_t backup29 = 0; uint32_t backup30 = 0; uint32_t backup31 = 0; enum { WDOG_CFG_REG_ADDR = 0x000, WDOG_CNT_REG_ADDR = 0x010, WDOG_FEED_REG_ADDR = 0x018, WDOG_KEY_REG_ADDR = 0x01C, WDOG_CMP0_REG_ADDR = 0x020, RTC_CFG_REG_ADDR = 0x040, RTC_COUNT_LO_REG_ADDR = 0x048, RTC_COUNT_HI_REG_ADDR = 0x04C, RTC_S_REG_ADDR = 0x050, RTC_CMP0 =0x060, LFROSCCFG_REG_ADDR = 0x70, BACKUP0_REG_ADDR = 0x80, BACKUP1_REG_ADDR = 0x84, BACKUP2_REG_ADDR = 0x88, BACKUP3_REG_ADDR = 0x8C, BACKUP4_REG_ADDR = 0x90, BACKUP5_REG_ADDR = 0x94, BACKUP6_REG_ADDR = 0x98, BACKUP7_REG_ADDR = 0x9C, BACKUP8_REG_ADDR = 0xA0, BACKUP9_REG_ADDR = 0xA4, BACKUP10_REG_ADDR = 0xA8, BACKUP11_REG_ADDR = 0xAC, BACKUP12_REG_ADDR = 0xB0, BACKUP13_REG_ADDR = 0xB4, BACKUP14_REG_ADDR = 0xB8, BACKUP15_REG_ADDR = 0xBC, BACKUP16_REG_ADDR = 0xC0, BACKUP17_REG_ADDR = 0xC4, BACKUP18_REG_ADDR = 0xC8, BACKUP19_REG_ADDR = 0xCC, BACKUP20_REG_ADDR = 0xD0, BACKUP21_REG_ADDR = 0xD4, BACKUP22_REG_ADDR = 0xD8, BACKUP23_REG_ADDR = 0xDC, BACKUP24_REG_ADDR = 0xE0, BACKUP25_REG_ADDR = 0xE4, BACKUP26_REG_ADDR = 0xE8, BACKUP27_REG_ADDR = 0xEC, BACKUP28_REG_ADDR = 0xF0, BACKUP29_REG_ADDR = 0xF4, BACKUP30_REG_ADDR = 0xF8, BACKUP31_REG_ADDR = 0xFC, PMUCAUSE_REG_ADDR = 0x144, }; vp::map::LocalRouter router = {"AON"}; AON(sc_core::sc_module_name) { tsock.register_b_transport(this, &AON::transport); router .add_register_bank({ {WDOG_CFG_REG_ADDR, &wdogcfg}, {WDOG_CNT_REG_ADDR, &wdogcount}, {WDOG_FEED_REG_ADDR, &wdogfeed}, {WDOG_KEY_REG_ADDR, &wdogkey}, {WDOG_CMP0_REG_ADDR, &wdogcmp0}, {RTC_CFG_REG_ADDR, &rtccfg}, {RTC_COUNT_LO_REG_ADDR, &rtccountlo}, {RTC_COUNT_HI_REG_ADDR, &rtccounthi}, {RTC_S_REG_ADDR, &rtcs}, {RTC_CMP0, &rtccmp0}, {LFROSCCFG_REG_ADDR, &lfrosccfg}, {PMUCAUSE_REG_ADDR, &pmucause}, {BACKUP0_REG_ADDR, &backup0}, {BACKUP1_REG_ADDR, &backup1}, {BACKUP2_REG_ADDR, &backup2}, {BACKUP3_REG_ADDR, &backup3}, {BACKUP4_REG_ADDR, &backup4}, {BACKUP5_REG_ADDR, &backup5}, {BACKUP6_REG_ADDR, &backup6}, {BACKUP7_REG_ADDR, &backup7}, {BACKUP8_REG_ADDR, &backup8}, {BACKUP9_REG_ADDR, &backup9}, {BACKUP10_REG_ADDR, &backup10}, {BACKUP11_REG_ADDR, &backup11}, {BACKUP12_REG_ADDR, &backup12}, {BACKUP13_REG_ADDR, &backup13}, {BACKUP14_REG_ADDR, &backup14}, {BACKUP15_REG_ADDR, &backup15}, {BACKUP16_REG_ADDR, &backup16}, {BACKUP17_REG_ADDR, &backup17}, {BACKUP18_REG_ADDR, &backup18}, {BACKUP19_REG_ADDR, &backup19}, {BACKUP20_REG_ADDR, &backup20}, {BACKUP21_REG_ADDR, &backup21}, {BACKUP22_REG_ADDR, &backup22}, {BACKUP23_REG_ADDR, &backup23}, {BACKUP24_REG_ADDR, &backup24}, {BACKUP25_REG_ADDR, &backup25}, {BACKUP26_REG_ADDR, &backup26}, {BACKUP27_REG_ADDR, &backup27}, {BACKUP28_REG_ADDR, &backup28}, {BACKUP29_REG_ADDR, &backup29}, {BACKUP30_REG_ADDR, &backup30}, {BACKUP31_REG_ADDR, &backup31}, }) .register_handler(this, &AON::register_access_callback); } void register_access_callback(const vp::map::register_access_t &r) { r.fn(); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { router.transport(trans, delay); } }; #endif // RISCV_VP_AON_H ================================================ FILE: vp/src/platform/hifive/can/90-slcan.rules ================================================ # Lawicel CANUSB module SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{product}=="CANUSB", SYMLINK+="ttyUSB_CAN" ACTION=="add", ATTRS{product}=="CANUSB", RUN+="/usr/local/bin/slcan_add.sh" ACTION=="remove", ATTRS{product}=="CANUSB", RUN+="/usr/local/bin/slcan_remove.sh" ================================================ FILE: vp/src/platform/hifive/can/CAN-Howto.md ================================================ ```bash sudo apt-get install can-utils ``` Check if the kernel modules „can“, „can_raw“ and „slcan“ are already loaded: ```bash lsmod | grep can ``` if not, load them manually: ```bash sudo modprobe can sudo modprobe can_raw sudo modprobe slcan ```` If modprobe says „Module not found“ at this point, your linux distribution is missing the can modules. If modprobe says nothing, the modules exist. To autoload these modules, insert into new file `/etc/modules-load.d/can` following lines: ``` can can_raw slcan ``` (perhaps test by restart, haha) ```bash sudo cp 90-slcan.rules /etc/udev/rules.d/90-slcan.rules sudo cp slcan* /usr/local/bin/ ``` You may plug in the CAN-Controller now. *kiss* - If `ip link` does not show a _slcan0_, execute the `sudo slcan_add.sh` - To see can traffic, run `candump slcan0` ================================================ FILE: vp/src/platform/hifive/can/cantest.cpp ================================================ /* * cantest.cpp * * Created on: 22 Mar 2019 * Author: dwd */ #include #include #include #include #include #include #include #include #include #include using namespace std; int main(int argc, char* argv[]) { int s; struct sockaddr_can addr; struct ifreq ifr; s = socket(PF_CAN, SOCK_RAW, CAN_RAW); if (s < 0) { perror("Could not open socket!"); } memset(&ifr, 0, sizeof(struct ifreq)); strcpy(ifr.ifr_name, "slcan0"); if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { perror("Could not ctl to device"); } addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("Could not bind to can family"); } // while(true) { struct can_frame frame; int nbytes = read(s, &frame, sizeof(struct can_frame)); if (nbytes < 0) { perror("can raw socket read"); return 1; } /* paranoid check ... */ if (nbytes < sizeof(struct can_frame)) { fprintf(stderr, "read: incomplete CAN frame\n"); return 1; } /* do something with the received CAN frame */ cout << "received id " << frame.can_id << " len " << unsigned(frame.can_dlc) << endl; for (uint8_t i = 0; i < frame.can_dlc; i++) { printf("%s%02X", i > 0 ? " " : "", frame.data[i]); } cout << endl; nbytes = write(s, &frame, sizeof(struct can_frame)); } close(s); } ================================================ FILE: vp/src/platform/hifive/can/mcp_can_dfs.h ================================================ /* mcp_can_dfs.h 2012 Copyright (c) Seeed Technology Inc. All right reserved. Author:Loovee (loovee@seeed.cc) 2014-1-16 Contributor: Cory J. Fowler Latonita Woodward1 Mehtajaghvi BykeBlast TheRo0T Tsipizic ralfEdmund Nathancheek BlueAndi Adlerweb Btetz Hurvajs xboxpro1 ttlappalainen The MIT License (MIT) Copyright (c) 2013 Seeed Technology Inc. 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 _MCP2515DFS_H_ #define _MCP2515DFS_H_ // Begin mt #define TIMEOUTVALUE 50 #define MCP_SIDH 0 #define MCP_SIDL 1 #define MCP_EID8 2 #define MCP_EID0 3 #define MCP_TXB_EXIDE_M 0x08 // In TXBnSIDL #define MCP_DLC_MASK 0x0F // 4 LSBits #define MCP_RTR_MASK 0x40 // (1<<6) Bit 6 #define MCP_RXB_RX_ANY 0x60 #define MCP_RXB_RX_EXT 0x40 #define MCP_RXB_RX_STD 0x20 #define MCP_RXB_RX_STDEXT 0x00 #define MCP_RXB_RX_MASK 0x60 #define MCP_RXB_BUKT_MASK (1 << 2) // Bits in the TXBnCTRL registers. #define MCP_TXB_TXBUFE_M 0x80 #define MCP_TXB_ABTF_M 0x40 #define MCP_TXB_MLOA_M 0x20 #define MCP_TXB_TXERR_M 0x10 #define MCP_TXB_TXREQ_M 0x08 #define MCP_TXB_TXIE_M 0x04 #define MCP_TXB_TXP10_M 0x03 #define MCP_TXB_RTR_M 0x40 // In TXBnDLC #define MCP_RXB_IDE_M 0x08 // In RXBnSIDL #define MCP_RXB_RTR_M 0x40 // In RXBnDLC #define MCP_STAT_TX_PENDING_MASK (0x54) #define MCP_STAT_TX0_PENDING (0x04) #define MCP_STAT_TX1_PENDING (0x10) #define MCP_STAT_TX2_PENDING (0x40) #define MCP_STAT_TXIF_MASK (0xA8) #define MCP_STAT_TX0IF (0x08) #define MCP_STAT_TX1IF (0x20) #define MCP_STAT_TX2IF (0x80) #define MCP_STAT_RXIF_MASK (0x03) #define MCP_STAT_RX0IF (1 << 0) #define MCP_STAT_RX1IF (1 << 1) #define MCP_EFLG_RX1OVR (1 << 7) #define MCP_EFLG_RX0OVR (1 << 6) #define MCP_EFLG_TXBO (1 << 5) #define MCP_EFLG_TXEP (1 << 4) #define MCP_EFLG_RXEP (1 << 3) #define MCP_EFLG_TXWAR (1 << 2) #define MCP_EFLG_RXWAR (1 << 1) #define MCP_EFLG_EWARN (1 << 0) #define MCP_EFLG_ERRORMASK (0xF8) // 5 MS-Bits // Define MCP2515 register addresses #define MCP_RXF0SIDH 0x00 #define MCP_RXF0SIDL 0x01 #define MCP_RXF0EID8 0x02 #define MCP_RXF0EID0 0x03 #define MCP_RXF1SIDH 0x04 #define MCP_RXF1SIDL 0x05 #define MCP_RXF1EID8 0x06 #define MCP_RXF1EID0 0x07 #define MCP_RXF2SIDH 0x08 #define MCP_RXF2SIDL 0x09 #define MCP_RXF2EID8 0x0A #define MCP_RXF2EID0 0x0B #define MCP_CANSTAT 0x0E #define MCP_CANCTRL 0x0F #define MCP_RXF3SIDH 0x10 #define MCP_RXF3SIDL 0x11 #define MCP_RXF3EID8 0x12 #define MCP_RXF3EID0 0x13 #define MCP_RXF4SIDH 0x14 #define MCP_RXF4SIDL 0x15 #define MCP_RXF4EID8 0x16 #define MCP_RXF4EID0 0x17 #define MCP_RXF5SIDH 0x18 #define MCP_RXF5SIDL 0x19 #define MCP_RXF5EID8 0x1A #define MCP_RXF5EID0 0x1B #define MCP_TEC 0x1C #define MCP_REC 0x1D #define MCP_RXM0SIDH 0x20 #define MCP_RXM0SIDL 0x21 #define MCP_RXM0EID8 0x22 #define MCP_RXM0EID0 0x23 #define MCP_RXM1SIDH 0x24 #define MCP_RXM1SIDL 0x25 #define MCP_RXM1EID8 0x26 #define MCP_RXM1EID0 0x27 #define MCP_CNF3 0x28 #define MCP_CNF2 0x29 #define MCP_CNF1 0x2A #define MCP_CANINTE 0x2B #define MCP_CANINTF 0x2C #define MCP_EFLG 0x2D #define MCP_TXB0CTRL 0x30 #define MCP_TXB0SIDH 0x31 #define MCP_TXB1CTRL 0x40 #define MCP_TXB1SIDH 0x41 #define MCP_TXB2CTRL 0x50 #define MCP_TXB2SIDH 0x51 #define MCP_RXB0CTRL 0x60 #define MCP_RXB0SIDH 0x61 #define MCP_RXB1CTRL 0x70 #define MCP_RXB1SIDH 0x71 #define MCP_TX_INT 0x1C // Enable all transmit interrup ts #define MCP_TX01_INT 0x0C // Enable TXB0 and TXB1 interru pts #define MCP_RX_INT 0x03 // Enable receive interrupts #define MCP_NO_INT 0x00 // Disable all interrupts #define MCP_TX01_MASK 0x14 #define MCP_TX_MASK 0x54 // Define SPI Instruction Set #define MCP_WRITE 0x02 #define MCP_READ 0x03 #define MCP_BITMOD 0x05 #define MCP_LOAD_TX0 0x40 #define MCP_LOAD_TX1 0x42 #define MCP_LOAD_TX2 0x44 #define MCP_RTS_TX0 0x81 #define MCP_RTS_TX1 0x82 #define MCP_RTS_TX2 0x84 #define MCP_RTS_ALL 0x87 #define MCP_READ_RX0 0x90 #define MCP_READ_RX1 0x94 #define MCP_READ_STATUS 0xA0 #define MCP_RX_STATUS 0xB0 #define MCP_RESET 0xC0 // CANCTRL Register Values #define MODE_NORMAL 0x00 #define MODE_SLEEP 0x20 #define MODE_LOOPBACK 0x40 #define MODE_LISTENONLY 0x60 #define MODE_CONFIG 0x80 #define MODE_POWERUP 0xE0 #define MODE_MASK 0xE0 #define ABORT_TX 0x10 #define MODE_ONESHOT 0x08 #define CLKOUT_ENABLE 0x04 #define CLKOUT_DISABLE 0x00 #define CLKOUT_PS1 0x00 #define CLKOUT_PS2 0x01 #define CLKOUT_PS4 0x02 #define CLKOUT_PS8 0x03 // CNF1 Register Values #define SJW1 0x00 #define SJW2 0x40 #define SJW3 0x80 #define SJW4 0xC0 // CNF2 Register Values #define BTLMODE 0x80 #define SAMPLE_1X 0x00 #define SAMPLE_3X 0x40 // CNF3 Register Values #define SOF_ENABLE 0x80 #define SOF_DISABLE 0x00 #define WAKFIL_ENABLE 0x40 #define WAKFIL_DISABLE 0x00 // CANINTF Register Bits #define MCP_RX0IF 0x01 #define MCP_RX1IF 0x02 #define MCP_TX0IF 0x04 #define MCP_TX1IF 0x08 #define MCP_TX2IF 0x10 #define MCP_ERRIF 0x20 #define MCP_WAKIF 0x40 #define MCP_MERRF 0x80 // clock #define MCP_16MHz 1 #define MCP_8MHz 2 // speed 16M #define MCP_16MHz_1000kBPS_CFG1 (0x00) #define MCP_16MHz_1000kBPS_CFG2 (0xD0) #define MCP_16MHz_1000kBPS_CFG3 (0x82) #define MCP_16MHz_500kBPS_CFG1 (0x00) #define MCP_16MHz_500kBPS_CFG2 (0xF0) #define MCP_16MHz_500kBPS_CFG3 (0x86) #define MCP_16MHz_250kBPS_CFG1 (0x41) #define MCP_16MHz_250kBPS_CFG2 (0xF1) #define MCP_16MHz_250kBPS_CFG3 (0x85) #define MCP_16MHz_200kBPS_CFG1 (0x01) #define MCP_16MHz_200kBPS_CFG2 (0xFA) #define MCP_16MHz_200kBPS_CFG3 (0x87) #define MCP_16MHz_125kBPS_CFG1 (0x03) #define MCP_16MHz_125kBPS_CFG2 (0xF0) #define MCP_16MHz_125kBPS_CFG3 (0x86) #define MCP_16MHz_100kBPS_CFG1 (0x03) #define MCP_16MHz_100kBPS_CFG2 (0xFA) #define MCP_16MHz_100kBPS_CFG3 (0x87) #define MCP_16MHz_95kBPS_CFG1 (0x03) #define MCP_16MHz_95kBPS_CFG2 (0xAD) #define MCP_16MHz_95kBPS_CFG3 (0x07) #define MCP_16MHz_83k3BPS_CFG1 (0x03) #define MCP_16MHz_83k3BPS_CFG2 (0xBE) #define MCP_16MHz_83k3BPS_CFG3 (0x07) #define MCP_16MHz_80kBPS_CFG1 (0x03) #define MCP_16MHz_80kBPS_CFG2 (0xFF) #define MCP_16MHz_80kBPS_CFG3 (0x87) #define MCP_16MHz_50kBPS_CFG1 (0x07) #define MCP_16MHz_50kBPS_CFG2 (0xFA) #define MCP_16MHz_50kBPS_CFG3 (0x87) #define MCP_16MHz_40kBPS_CFG1 (0x07) #define MCP_16MHz_40kBPS_CFG2 (0xFF) #define MCP_16MHz_40kBPS_CFG3 (0x87) #define MCP_16MHz_33kBPS_CFG1 (0x09) #define MCP_16MHz_33kBPS_CFG2 (0xBE) #define MCP_16MHz_33kBPS_CFG3 (0x07) #define MCP_16MHz_31k25BPS_CFG1 (0x0F) #define MCP_16MHz_31k25BPS_CFG2 (0xF1) #define MCP_16MHz_31k25BPS_CFG3 (0x85) #define MCP_16MHz_25kBPS_CFG1 (0X0F) #define MCP_16MHz_25kBPS_CFG2 (0XBA) #define MCP_16MHz_25kBPS_CFG3 (0X07) #define MCP_16MHz_20kBPS_CFG1 (0x0F) #define MCP_16MHz_20kBPS_CFG2 (0xFF) #define MCP_16MHz_20kBPS_CFG3 (0x87) #define MCP_16MHz_10kBPS_CFG1 (0x1F) #define MCP_16MHz_10kBPS_CFG2 (0xFF) #define MCP_16MHz_10kBPS_CFG3 (0x87) #define MCP_16MHz_5kBPS_CFG1 (0x3F) #define MCP_16MHz_5kBPS_CFG2 (0xFF) #define MCP_16MHz_5kBPS_CFG3 (0x87) #define MCP_16MHz_666kBPS_CFG1 (0x00) #define MCP_16MHz_666kBPS_CFG2 (0xA0) #define MCP_16MHz_666kBPS_CFG3 (0x04) // speed 8M #define MCP_8MHz_1000kBPS_CFG1 (0x00) #define MCP_8MHz_1000kBPS_CFG2 (0x80) #define MCP_8MHz_1000kBPS_CFG3 (0x00) #define MCP_8MHz_500kBPS_CFG1 (0x00) #define MCP_8MHz_500kBPS_CFG2 (0x90) #define MCP_8MHz_500kBPS_CFG3 (0x02) #define MCP_8MHz_250kBPS_CFG1 (0x00) #define MCP_8MHz_250kBPS_CFG2 (0xb1) #define MCP_8MHz_250kBPS_CFG3 (0x05) #define MCP_8MHz_200kBPS_CFG1 (0x00) #define MCP_8MHz_200kBPS_CFG2 (0xb4) #define MCP_8MHz_200kBPS_CFG3 (0x06) #define MCP_8MHz_125kBPS_CFG1 (0x01) #define MCP_8MHz_125kBPS_CFG2 (0xb1) #define MCP_8MHz_125kBPS_CFG3 (0x05) #define MCP_8MHz_100kBPS_CFG1 (0x01) #define MCP_8MHz_100kBPS_CFG2 (0xb4) #define MCP_8MHz_100kBPS_CFG3 (0x06) #define MCP_8MHz_80kBPS_CFG1 (0x01) #define MCP_8MHz_80kBPS_CFG2 (0xbf) #define MCP_8MHz_80kBPS_CFG3 (0x07) #define MCP_8MHz_50kBPS_CFG1 (0x03) #define MCP_8MHz_50kBPS_CFG2 (0xb4) #define MCP_8MHz_50kBPS_CFG3 (0x06) #define MCP_8MHz_40kBPS_CFG1 (0x03) #define MCP_8MHz_40kBPS_CFG2 (0xbf) #define MCP_8MHz_40kBPS_CFG3 (0x07) #define MCP_8MHz_31k25BPS_CFG1 (0x07) #define MCP_8MHz_31k25BPS_CFG2 (0xa4) #define MCP_8MHz_31k25BPS_CFG3 (0x04) #define MCP_8MHz_20kBPS_CFG1 (0x07) #define MCP_8MHz_20kBPS_CFG2 (0xbf) #define MCP_8MHz_20kBPS_CFG3 (0x07) #define MCP_8MHz_10kBPS_CFG1 (0x0f) #define MCP_8MHz_10kBPS_CFG2 (0xbf) #define MCP_8MHz_10kBPS_CFG3 (0x07) #define MCP_8MHz_5kBPS_CFG1 (0x1f) #define MCP_8MHz_5kBPS_CFG2 (0xbf) #define MCP_8MHz_5kBPS_CFG3 (0x07) #define MCPDEBUG (0) #define MCPDEBUG_TXBUF (0) #define MCP_N_TXBUFFERS (3) #define MCP_RXBUF_0 (MCP_RXB0SIDH) #define MCP_RXBUF_1 (MCP_RXB1SIDH) #define MCP2515_SELECT() digitalWrite(SPICS, LOW) #define MCP2515_UNSELECT() digitalWrite(SPICS, HIGH) #define MCP2515_OK (0) #define MCP2515_FAIL (1) #define MCP_ALLTXBUSY (2) #define CANDEBUG 1 #define CANUSELOOP 0 #define CANSENDTIMEOUT (200) // milliseconds // initial value of gCANAutoProcess #define CANAUTOPROCESS (1) #define CANAUTOON (1) #define CANAUTOOFF (0) #define CAN_STDID (0) #define CAN_EXTID (1) #define CANDEFAULTIDENT (0x55CC) #define CANDEFAULTIDENTEXT (CAN_EXTID) #define CAN_5KBPS 1 #define CAN_10KBPS 2 #define CAN_20KBPS 3 #define CAN_25KBPS 4 #define CAN_31K25BPS 5 #define CAN_33KBPS 6 #define CAN_40KBPS 7 #define CAN_50KBPS 8 #define CAN_80KBPS 9 #define CAN_83K3BPS 10 #define CAN_95KBPS 11 #define CAN_100KBPS 12 #define CAN_125KBPS 13 #define CAN_200KBPS 14 #define CAN_250KBPS 15 #define CAN_500KBPS 16 #define CAN_666KBPS 17 #define CAN_1000KBPS 18 #define CAN_OK (0) #define CAN_FAILINIT (1) #define CAN_FAILTX (2) #define CAN_MSGAVAIL (3) #define CAN_NOMSG (4) #define CAN_CTRLERROR (5) #define CAN_GETTXBFTIMEOUT (6) #define CAN_SENDMSGTIMEOUT (7) #define CAN_FAIL (0xff) #define CAN_MAX_CHAR_IN_MESSAGE (8) #endif /********************************************************************************************************* END FILE *********************************************************************************************************/ ================================================ FILE: vp/src/platform/hifive/can/slcan_add.sh ================================================ #!/bin/sh # Bind the USBCAN device slcand -o -c -f -s6 /dev/ttyUSB_CAN slcan0 sleep 1 ifconfig slcan0 up ================================================ FILE: vp/src/platform/hifive/can/slcan_remove.sh ================================================ #!/bin/sh # Remove the USBCAN device pkill slcand ================================================ FILE: vp/src/platform/hifive/can.cpp ================================================ #include "can.h" #include #include #include #include #include #include #include #include #include #include CAN::CAN() { state = State::init; status = 0; stop = false; s = socket(PF_CAN, SOCK_RAW, CAN_RAW); if (s < 0) { perror("Could not open socket!"); return; } memset(&ifr, 0, sizeof(struct ifreq)); strcpy(ifr.ifr_name, "slcan0"); if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { close(s); perror("Could not ctl to device"); return; } addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) { close(s); perror("Could not bind to can family"); return; } listener = std::thread(&CAN::listen, this); } CAN::~CAN() { stop = true; if (listener.joinable()) listener.join(); } const char* CAN::registerName(uint8_t id) { switch (id) { /*..*/ case MCP_CANCTRL: return "MCP_CANCTRL"; case MCP_RXF0SIDH: return "MCP_RXF0SIDH"; /*..*/ case MCP_CNF1: return "MCP_CNF1"; case MCP_CNF2: return "MCP_CNF2"; case MCP_CNF3: return "MCP_CNF3"; /*..*/ case MCP_CANINTF: return "MCP_CANINTF"; case MCP_TXB1CTRL: return "MCP_TXB1CTRL"; case MCP_TXB2CTRL: return "MCP_TXB2CTRL"; default: return "UNKNOWN-RegName"; } } const char* CAN::regValueName(uint8_t id) { switch (id) { /*..*/ case MODE_NORMAL: return "MODE_NORMAL"; case MODE_SLEEP: return "MODE_SLEEP"; case MODE_CONFIG: return "MODE_CONFIG"; case MODE_ONESHOT: return "MODE_ONESHOT"; default: return "UNKNOWN-RegValue"; } } const char* CAN::spiInstName(uint8_t id) { switch (id) { /*..*/ case MCP_WRITE: return "MCP_WRITE"; case MCP_READ: return "MCP_READ"; case MCP_BITMOD: return "MCP_BITMOD"; case MCP_LOAD_TX0: return "MCP_LOAD_TX0"; case MCP_LOAD_TX1: return "MCP_LOAD_TX1"; case MCP_LOAD_TX2: return "MCP_LOAD_TX2"; case MCP_RTS_TX0: return "MCP_RTS_TX0"; case MCP_RTS_TX1: return "MCP_RTS_TX1"; case MCP_RTS_TX2: return "MCP_RTS_TX2"; case MCP_RTS_ALL: return "MCP_RTS_ALL"; case MCP_READ_RX0: return "MCP_READ_RX0"; case MCP_READ_RX1: return "MCP_READ_RX1"; case MCP_READ_STATUS: return "MCP_READ_STATUS"; case MCP_RX_STATUS: return "MCP_RX_STATUS"; case MCP_RESET: return "MCP_RESET"; default: return "UNKNOWN-SpiInst"; } } uint8_t CAN::write(uint8_t byte) { uint8_t ret = 0; uint8_t whichBuf = 0; switch (state) { case State::init: command(byte); ret = 0; break; case State::readRegister: ret = readRegister(byte); break; case State::writeRegister: ret = writeRegister(byte); break; case State::bitmod: ret = modifyRegister(byte); break; case State::loadTX2: whichBuf++; // fall-through case State::loadTX1: whichBuf++; // fall-through case State::loadTX0: ret = loadTxBuf(whichBuf, byte); break; case State::sendALL: whichBuf++; // fall-through case State::sendTX2: whichBuf++; // fall-through case State::sendTX1: whichBuf++; // fall-through case State::sendTX0: ret = sendTxBuf(whichBuf, byte); break; case State::readRX1: whichBuf++; // fall-through case State::readRX0: ret = readRxBuf(whichBuf, byte); break; case State::getStatus: ret = status; // short enough to be handled here state = State::init; break; default: std::cerr << "[CAN] in unknown state!" << std::endl; } return ret; } void CAN::command(uint8_t byte) { // std::cout << "[CAN] " << spiInstName(byte); switch (byte) { case MCP_WRITE: state = State::writeRegister; break; case MCP_READ: state = State::readRegister; break; case MCP_BITMOD: state = State::bitmod; break; case MCP_LOAD_TX0: state = State::loadTX0; break; case MCP_LOAD_TX1: state = State::loadTX1; break; case MCP_LOAD_TX2: state = State::loadTX2; break; case MCP_RTS_TX0: state = State::sendTX0; break; case MCP_RTS_TX1: state = State::sendTX1; break; case MCP_RTS_TX2: state = State::sendTX2; break; case MCP_RTS_ALL: state = State::sendALL; break; case MCP_READ_RX0: state = State::readRX0; break; case MCP_READ_RX1: state = State::readRX1; break; case MCP_READ_STATUS: state = State::getStatus; break; case MCP_RX_STATUS: break; case MCP_RESET: // do reset stuff state = State::init; break; default: std::cerr << std::hex << unsigned(byte) << " is unknown command " << std::endl; } // std::cout << std::endl; } uint8_t CAN::readRegister(uint8_t byte) { static int16_t selectedRegister = -1; uint8_t ret = 0; if (selectedRegister < 0) { selectedRegister = byte; // std::cout << "\t[CAN] read select Register " << registerName(selectedRegister) << std::endl; ret = 0; } else { if (byte != 0) { // end "auto increment" selectedRegister = -1; command(byte); return 0; } // std::cout << "[CAN] Read on Register " << registerName(selectedRegister) << std::endl; if (selectedRegister > MCP_RXB1SIDH) { std::cerr << "Read on Register too high! "; ret = 0; } else { ret = registers[selectedRegister]; } selectedRegister++; } return ret; } uint8_t CAN::writeRegister(uint8_t byte) { static int16_t selectedRegister = -1; if (selectedRegister < 0) { selectedRegister = byte; // std::cout << "\t[CAN] Write select Register " << registerName(selectedRegister) << std::endl; return 0; } else { // std::cout << "[CAN] Write on Register " << registerName(selectedRegister) << std::endl; if (selectedRegister > MCP_RXB1SIDH) { std::cerr << "Write on Register too high! "; return 0; } else { registers[selectedRegister] = byte; } selectedRegister = -1; state = State::init; } return 0; } uint8_t CAN::modifyRegister(uint8_t byte) { static struct ModReg { enum : uint8_t { _address = 0, _mask, _data } state; uint8_t address; uint8_t mask; uint8_t data; ModReg() : state(_address), address(0), mask(0), data(0){}; } command; // std::cout << "\t[CAN] modReg "; switch (command.state) { case ModReg::_address: command.address = byte; command.state = ModReg::_mask; // std::cout << "select " << registerName(command.address) << std::endl; break; case ModReg::_mask: command.mask = byte; command.state = ModReg::_data; // std::cout << "mask " << std::hex << unsigned(byte) << std::endl; break; case ModReg::_data: command.data = byte; command.state = ModReg::_address; state = State::init; // std::cout << "setData " << regValueName(command.data) << std::endl; registers[command.address] &= ~command.mask; registers[command.address] |= command.data; break; } return 0; } uint8_t CAN::loadTxBuf(uint8_t no, uint8_t byte) { static struct LoadTX { enum { id, length, payload, } state = id; uint8_t payload_ptr = 0; } command; switch (command.state) { case LoadTX::id: // std::cout << "\t[CAN] ID: " << std::hex << unsigned(byte) << std::endl; txBuf[no].fields.id[command.payload_ptr++] = byte; if (command.payload_ptr == 4) { command.payload_ptr = 0; command.state = LoadTX::length; } break; case LoadTX::length: // std::cout << "\t[CAN] Length : " << std::hex << unsigned(byte) << std::endl; command.state = LoadTX::payload; txBuf[no].fields.length = byte; break; case LoadTX::payload: // std::cout << "\t[CAN] PL : " << std::hex << unsigned(byte) << std::endl; txBuf[no].fields.payload[command.payload_ptr++] = byte; if (command.payload_ptr == txBuf[no].fields.length) { command = LoadTX(); state = State::init; } break; } return 0; } uint8_t CAN::sendTxBuf(uint8_t no, uint8_t) { if (no == 4) { // todo: Special case to send all buffers no = 0; } struct can_frame frame; bool extended; // this is ignored memset(&frame, 0, sizeof(struct can_frame)); mcp2515_buf_to_id(frame.can_id, extended, txBuf[no].fields.id); frame.can_dlc = txBuf[no].fields.length; memcpy(frame.data, txBuf[no].fields.payload, txBuf[no].fields.length); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-result" ::write(s, &frame, sizeof(struct can_frame)); ; #pragma GCC diagnostic pop // Set 'sent' status ok registers[MCP_TXB0CTRL] = 0; state = State::readRegister; return 0; } uint8_t CAN::readRxBuf(uint8_t no, uint8_t) { static uint8_t payload_ptr = 0; uint8_t ret = rxBuf[no].raw[payload_ptr++]; if (payload_ptr > rxBuf[no].fields.length + 4) { payload_ptr = 0; state = State::init; status &= ~(1 << no); // MCP_STAT_RX0IF = 1 << 0 } // std::cout << "[CAN] readRxBuf" << unsigned(no) << " " << unsigned(ret) << std::endl; return ret; } void CAN::mcp2515_id_to_buf(const unsigned long id, uint8_t* idField, const bool extended) { uint16_t canid; canid = (uint16_t)(id & 0x0FFFF); if (extended) { idField[MCP_EID0] = (uint8_t)(canid & 0xFF); idField[MCP_EID8] = (uint8_t)(canid >> 8); canid = (uint16_t)(id >> 16); idField[MCP_SIDL] = (uint8_t)(canid & 0x03); idField[MCP_SIDL] += (uint8_t)((canid & 0x1C) << 3); idField[MCP_SIDL] |= MCP_TXB_EXIDE_M; idField[MCP_SIDH] = (uint8_t)(canid >> 5); } else { idField[MCP_SIDH] = (uint8_t)(canid >> 3); idField[MCP_SIDL] = (uint8_t)((canid & 0x07) << 5); idField[MCP_EID0] = 0; idField[MCP_EID8] = 0; } } void CAN::mcp2515_buf_to_id(unsigned& id, bool& extended, uint8_t* idField) { extended = false; id = 0; id = (idField[MCP_SIDH] << 3) + (idField[MCP_SIDL] >> 5); if ((idField[MCP_SIDL] & MCP_TXB_EXIDE_M) == MCP_TXB_EXIDE_M) { // extended id id = (id << 2) + (idField[MCP_SIDL] & 0x03); id = (id << 8) + idField[MCP_EID8]; id = (id << 8) + idField[MCP_EID0]; extended = true; } } void CAN::enqueueIncomingCanFrame(const struct can_frame& frame) { if ((status & 0b11) == 0b11) { // all buffers full return; } for (unsigned i = 0; i < 2; i++) { if (!(status & (1 << i))) // Correnspond to MCP_STAT_RXnIF registers { // empty buffer memset(&rxBuf[i], 0, sizeof(MCPFrame)); mcp2515_id_to_buf(frame.can_id, rxBuf[i].fields.id); // FIXME: This will break if extended frame or stuff happens rxBuf[i].fields.length = frame.can_dlc; memcpy(rxBuf[i].fields.payload, frame.data, frame.can_dlc); status |= 1 << i; return; } } } void CAN::listen() { while (!stop) { struct can_frame frame; int nbytes = read(s, &frame, sizeof(struct can_frame)); if (nbytes < 0) { perror("can raw socket read"); continue; } /* paranoid check ... */ if (nbytes < static_cast(sizeof(struct can_frame))) { fprintf(stderr, "read: incomplete CAN frame\n"); continue; } enqueueIncomingCanFrame(frame); } } ================================================ FILE: vp/src/platform/hifive/can.h ================================================ #pragma once #include "can/mcp_can_dfs.h" #include "spi.h" #include #include #include #include class CAN { enum class State { init, readRegister, writeRegister, bitmod, loadTX0, loadTX1, loadTX2, sendTX0, sendTX1, sendTX2, sendALL, readRX0, readRX1, getStatus, shit, wank, fuck, arse, crap, dick, } state; std::thread listener; uint8_t registers[MCP_RXB1SIDH + 1]; struct MCPFrame { union { uint8_t raw[5 + CANFD_MAX_DLEN]; struct { union { uint8_t id[4]; struct { /* MCP_SIDH 0 MCP_SIDL 1 MCP_EID8 2 MCP_EID0 3 */ uint16_t sid; uint16_t eid; } fields; }; uint8_t length; uint8_t payload[CANFD_MAX_DLEN]; } fields; }; }; MCPFrame txBuf[3]; MCPFrame rxBuf[2]; uint8_t status; int s; struct sockaddr_can addr; struct ifreq ifr; volatile bool stop; public: CAN(); ~CAN(); uint8_t write(uint8_t byte); const char* registerName(uint8_t id); const char* regValueName(uint8_t id); const char* spiInstName(uint8_t id); void command(uint8_t byte); uint8_t readRegister(uint8_t byte); uint8_t writeRegister(uint8_t byte); uint8_t modifyRegister(uint8_t byte); uint8_t loadTxBuf(uint8_t no, uint8_t byte); uint8_t sendTxBuf(uint8_t no, uint8_t byte); uint8_t readRxBuf(uint8_t no, uint8_t byte); void mcp2515_id_to_buf(const unsigned long id, uint8_t* idField, const bool extended = false); void mcp2515_buf_to_id(unsigned& id, bool& extended, uint8_t* idField); void enqueueIncomingCanFrame(const struct can_frame& frame); void listen(); }; ================================================ FILE: vp/src/platform/hifive/gpio.cpp ================================================ #include "gpio.h" using namespace std; using namespace gpio; static Pinstate getIOF(PinNumber pin, bool iofsel) { switch(pin) { case 16: // UART0 RX return !iofsel ? Pinstate::IOF_UART_RX : Pinstate::UNSET; case 17: // UART0 TX return !iofsel ? Pinstate::IOF_UART_TX : Pinstate::UNSET; case 19: // PWM1_1 case 20: // PWM1_0 case 21: // PWM1_2 case 22: // PWM1_3 return !iofsel ? Pinstate::UNSET : Pinstate::IOF_PWM; case 0: // PWM0_0 case 1: // PWM0_1 return !iofsel ? Pinstate::UNSET : Pinstate::IOF_PWM; case 2: // SPI1 CS0, PWM0_2 case 3: // SPI1 OSI, PWM0_3 return !iofsel ? Pinstate::IOF_SPI : Pinstate::IOF_PWM; case 4: // SPI1 MISO case 5: // SPI1 SCK return !iofsel ? Pinstate::IOF_SPI : Pinstate::UNSET; case 9: // SPI1 CS2 return !iofsel ? Pinstate::IOF_SPI : Pinstate::UNSET; case 10: // SPI1 CS3, PWM2_0 return !iofsel ? Pinstate::IOF_SPI : Pinstate::IOF_PWM; case 11: // PWM2_1 case 12: // PWM2_2 case 13: // PWM2_3 return !iofsel ? Pinstate::UNSET : Pinstate::IOF_PWM; case 18: // UART1 (RX?) return !iofsel ? Pinstate::IOF_UART_RX : Pinstate::UNSET; case 23: // UART1 (TX?) return !iofsel ? Pinstate::IOF_UART_TX : Pinstate::UNSET; default: return Pinstate::UNSET; } } static PinNumber getPinOffsFromSPIcs(PinNumber cs) { switch (cs) { case 0: return 2; case 1: assert(false && "[GPIO] On Fe310, CS 1 is not routable"); return max_num_pins; case 2: return 9; case 3: return 10; default: assert(false && "[GPIO] Invalid CS pin given"); return max_num_pins; } } GPIO::GPIO(sc_core::sc_module_name, unsigned int_gpio_base) : int_gpio_base(int_gpio_base) { tsock.register_b_transport(this, &GPIO::transport); router .add_register_bank({ {PIN_VALUE_ADDR, &value}, {INPUT_EN_REG_ADDR, &input_en}, {OUTPUT_EN_REG_ADDR, &output_en}, {PORT_REG_ADDR, &port}, {PULLUP_EN_ADDR, &pullup_en}, {PIN_DRIVE_STNGTH, &pin_drive_strength}, {RISE_INTR_EN, &rise_intr_en}, {RISE_INTR_PEND, &rise_intr_pending}, {FALL_INTR_EN, &fall_intr_en}, {FALL_INTR_PEND, &fall_intr_pending}, {HIGH_INTR_EN, &high_intr_en}, {HIGH_INTR_PEND, &high_intr_pending}, {LOW_INTR_EN, &low_intr_en}, {LOW_INTR_PEND, &low_intr_pending}, {IOF_EN_REG_ADDR, &iof_en}, {IOF_SEL_REG_ADDR, &iof_sel}, {OUT_XOR_REG_ADDR, &out_xor}, }) .register_handler(this, &GPIO::register_access_callback); SC_METHOD(synchronousChange); sensitive << asyncEvent; dont_initialize(); server.setupConnection(to_string(gpio::default_port).c_str()); server.registerOnChange(bind(&GPIO::asyncOnchange, this, placeholders::_1, placeholders::_2)); serverThread = new thread(bind(&GpioServer::startAccepting, &server)); } GPIO::~GPIO() { server.quit(); if (serverThread) { if(serverThread->joinable()){ serverThread->join(); } delete serverThread; } } void GPIO::register_access_callback(const vp::map::register_access_t &r) { if (r.write) { switch (r.addr) { case PIN_VALUE_ADDR: cerr << "[GPIO] write to value register is ignored!" << endl; return; case PORT_REG_ADDR: // cout << "[GPIO] new Port value: "; // bitPrint(reinterpret_cast(&r.nv), sizeof(uint32_t)); // value and server.state might differ, if a bit is changed by // client and the synchronous_change was not fired yet. // Server wins in this scenario. { const auto prv_output_enabled_port = (port & output_en) & ~iof_en; const auto new_output_enabled_port = (r.nv & output_en) & ~iof_en; const auto changed_output_pins = new_output_enabled_port ^ prv_output_enabled_port; if(!changed_output_pins) break; value = (value & ~output_en) | new_output_enabled_port; for(PinNumber i = 0; i < available_pins; i++) { const auto bitoffs = (1l << i); if(bitoffs & changed_output_pins) { server.state.pins[i] = new_output_enabled_port & bitoffs ? Pinstate::HIGH : Pinstate::LOW; server.pushPin(i, toTristate(server.state.pins[i])); } } } break; case PULLUP_EN_ADDR: // cout << "[GPIO] pullup changed" << endl; // bitPrint(reinterpret_cast(&pullup_en), sizeof(uint32_t)); { const auto newly_pulled_up_bits = (r.nv ^ pullup_en) & r.nv; value |= newly_pulled_up_bits; for(PinNumber i = 0; i < available_pins; i++) { if((1l << i) & newly_pulled_up_bits) { server.state.pins[i] = Pinstate::HIGH; // TODO: Notify pin subscriber } } } break; case OUTPUT_EN_REG_ADDR: { const auto& old_output_en = output_en; const auto& new_output_en = r.nv; const auto newly_output_disabled_bits = old_output_en & ~new_output_en; const auto newly_output_enabled_bits = ~old_output_en & new_output_en; // Implicit zero when output disabled value = (value & ~old_output_en) | (port & new_output_en); for(PinNumber i = 0; i < available_pins; i++) { const auto bitoffs = (1l << i); if(bitoffs & newly_output_disabled_bits) { // we can't differentiate between "driven by server" or "by client". // Server wins, so override. server.state.pins[i] = Pinstate::UNSET; server.pushPin(i, Tristate::UNSET); } else if (bitoffs & newly_output_enabled_bits) { server.state.pins[i] = value & bitoffs ? Pinstate::HIGH : Pinstate::LOW; server.pushPin(i, toTristate(server.state.pins[i])); } } } break; default: break; } } r.fn(); if (r.write) { switch (r.addr) { case IOF_EN_REG_ADDR: case IOF_SEL_REG_ADDR: for (PinNumber i = 0; i < available_pins; i++) { if((1l << i) & iof_en) { { const auto iof = getIOF(i, iof_sel & (1l << i)); //cout << "IOF for pin " << (int)i << " is " << (int) iof << endl; if(iof == Pinstate::UNSET) cerr << "[GPIO] Set invalid iof to pin " << (int)i << endl; else server.state.pins[i] = iof; } } // TODO: Upon IOF disable, set value and state according to (port & output_en) } break; case FALL_INTR_EN: // cout << "[GPIO] set fall_intr_en to "; // bitPrint(reinterpret_cast(&fall_intr_en), sizeof(uint32_t)); break; case FALL_INTR_PEND: // cout << "[GPIO] set fall_intr_pending to "; // bitPrint(reinterpret_cast(&fall_intr_pending),sizeof(uint32_t)); break; default: break; } } } void GPIO::transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { router.transport(trans, delay); } bool GPIO::isServerConnected() { return server.isConnected(); } void GPIO::asyncOnchange(PinNumber bit, Tristate val) { const auto state_prev = server.state.pins[bit]; switch(val){ case Tristate::UNSET: /* * TODO: Maybe do pullup/down decision here or emplace into a queue * Queue would be better for sync, but unsure about performance. * May be less overhead as only changed pins can be handled. * But moving a bitmask unconditionally for 32 Pins is pretty fast, too. */ case Tristate::LOW: case Tristate::HIGH: server.state.pins[bit] = toPinstate(val); break; default: cout << "[GPIO] Invalid pin value " << (int) val << " on pin " << bit << endl; } if(state_prev != server.state.pins[bit]){ // cout << "[GPIO] Bit " << (unsigned) bit << " changed to " << (unsigned) // val << endl; asyncEvent.notify(); } } void GPIO::synchronousChange() { // cout << "[GPIO] might have changed!" << endl; gpio::State serverSnapshot = server.state; // This is seriously more complicated just handling the last updated bit // from asyncChange. But because we have to wait until the update phase, and // until then there may fire multiple bits! for (PinNumber i = 0; i < available_pins; i++) { const auto bitmask = 1l << i; if (input_en & bitmask) { // Small optimization: If not set as input, unset will stay unset even if not pullup enabled. if (serverSnapshot.pins[i] == Pinstate::UNSET) { if(pullup_en & bitmask) serverSnapshot.pins[i] = Pinstate::HIGH; else serverSnapshot.pins[i] = Pinstate::LOW; } // cout << "bit " << (unsigned) i << " is input enabled "; if (!(value & bitmask) && serverSnapshot.pins[i] == Pinstate::HIGH) { // cout << " changed to 1 "; if (rise_intr_en & bitmask) { // cout << "and interrupt is enabled "; // interrupt pending is inverted if (~rise_intr_pending & bitmask) { // cout << "but not yet consumed" << endl; } else { // cout << "and is being fired at " << int_gpio_base + i // << endl; rise_intr_pending &= ~bitmask; plic->gateway_trigger_interrupt(int_gpio_base + i); } } else { // cout << "but no interrupt is registered." << endl; } // transfer to value register value |= bitmask; } else if ((value & bitmask) && serverSnapshot.pins[i] == Pinstate::LOW){ // cout << " changed to 0 "; if (fall_intr_en & bitmask) { // cout << "and interrupt is enabled "; // interrupt pending is inverted if (~fall_intr_pending & bitmask) { // cout << "but not yet consumed" << endl; } else { // cout << "and is being fired at " << int_gpio_base + i // << endl; fall_intr_pending &= ~bitmask; plic->gateway_trigger_interrupt(int_gpio_base + i); } } else { // cout << "but no interrupt is registered." << endl; } // transfer to value register value &= ~bitmask; } else { // This pin did not change } } } // if something changed between snapshot and now, change is discarded. "Yeet" server.state = serverSnapshot; } UartTXFunction GPIO::getUartTransmitFunction(const gpio::PinNumber tx){ return bind(&GpioServer::pushUART, &server, tx, placeholders::_1); } void GPIO::registerUartReceiveFunction(const gpio::PinNumber rx, UartRXFunction fun){ server.registerUARTRX(rx, fun); } SpiWriteFunction GPIO::getSPIwriteFunction(gpio::PinNumber cs) { const auto pin = getPinOffsFromSPIcs(cs); return bind(&GpioServer::pushSPI, &server, pin, placeholders::_1); } ================================================ FILE: vp/src/platform/hifive/gpio.h ================================================ #pragma once #include "platform/common/async_event.h" #include "core/common/irq_if.h" #include #include "util/tlm_map.h" #include "spi.h" #include "tunnel-uart.hpp" #include #include #include struct GPIO : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; // memory mapped configuration registers uint32_t value = 0; // Current state of pin, input or output uint32_t input_en = 0; uint32_t output_en = 0; uint32_t port = 0; // Desired output values of enabled pins uint32_t pullup_en = 0; uint32_t pin_drive_strength = 0; uint32_t rise_intr_en = 0; uint32_t rise_intr_pending = ~0l; uint32_t fall_intr_en = 0; uint32_t fall_intr_pending = ~0l; uint32_t high_intr_en = 0; uint32_t high_intr_pending = ~0l; uint32_t low_intr_en = 0; uint32_t low_intr_pending = ~0l; uint32_t iof_en = 0; uint32_t iof_sel = 0; uint32_t out_xor = 0; enum { PIN_VALUE_ADDR = 0x000, INPUT_EN_REG_ADDR = 0x004, OUTPUT_EN_REG_ADDR = 0x008, PORT_REG_ADDR = 0x00C, PULLUP_EN_ADDR = 0x010, PIN_DRIVE_STNGTH = 0x014, RISE_INTR_EN = 0x018, RISE_INTR_PEND = 0x01C, FALL_INTR_EN = 0x020, FALL_INTR_PEND = 0x024, HIGH_INTR_EN = 0x028, HIGH_INTR_PEND = 0x02C, LOW_INTR_EN = 0x030, LOW_INTR_PEND = 0x034, IOF_EN_REG_ADDR = 0x038, IOF_SEL_REG_ADDR = 0x03C, OUT_XOR_REG_ADDR = 0x040, }; vp::map::LocalRouter router = {"GPIO"}; interrupt_gateway *plic = nullptr; static constexpr gpio::PinNumber available_pins = 32; const unsigned int_gpio_base; GpioServer server; std::thread *serverThread; AsyncEvent asyncEvent; SC_HAS_PROCESS(GPIO); GPIO(sc_core::sc_module_name, unsigned int_gpio_base); ~GPIO(); void register_access_callback(const vp::map::register_access_t &r); void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay); bool isServerConnected(); void asyncOnchange(gpio::PinNumber bit, gpio::Tristate val); void synchronousChange(); UartTXFunction getUartTransmitFunction(gpio::PinNumber tx); void registerUartReceiveFunction(gpio::PinNumber rx, UartRXFunction); SpiWriteFunction getSPIwriteFunction(gpio::PinNumber cs); }; ================================================ FILE: vp/src/platform/hifive/hifive_main.cpp ================================================ #include #include #include "aon.h" #include "can.h" #include "oled/oled.hpp" #include "core/common/clint.h" #include "core/rv32/syscall.h" #include "elf_loader.h" #include "fe310_plic.h" #include "debug_memory.h" #include "gpio.h" #include "iss.h" #include "maskROM.h" #include "mem.h" #include "memory.h" #include "prci.h" #include "slip.h" #include "spi.h" #include "uart.h" #include "platform/common/options.h" #include "gdb-mc/gdb_server.h" #include "gdb-mc/gdb_runner.h" #include #include #include #include #include #include // Interrupt numbers (see platform.h) #define INT_RESERVED 0 #define INT_WDOGCMP 1 #define INT_RTCCMP 2 #define INT_UART0_BASE 3 #define INT_UART1_BASE 4 #define INT_SPI0_BASE 5 #define INT_SPI1_BASE 6 #define INT_SPI2_BASE 7 #define INT_GPIO_BASE 8 #define INT_PWM0_BASE 40 #define INT_PWM1_BASE 44 #define INT_PWM2_BASE 48 using namespace rv32; namespace po = boost::program_options; class HifiveOptions : public Options { public: typedef unsigned int addr_t; addr_t maskROM_start_addr = 0x00001000; addr_t maskROM_end_addr = 0x00001FFF; addr_t clint_start_addr = 0x02000000; addr_t clint_end_addr = 0x0200FFFF; addr_t sys_start_addr = 0x02010000; addr_t sys_end_addr = 0x020103ff; addr_t plic_start_addr = 0x0C000000; addr_t plic_end_addr = 0x0FFFFFFF; addr_t aon_start_addr = 0x10000000; addr_t aon_end_addr = 0x10007FFF; addr_t prci_start_addr = 0x10008000; addr_t prci_end_addr = 0x1000FFFF; addr_t uart0_start_addr = 0x10013000; addr_t uart0_end_addr = 0x10013FFF; addr_t uart1_start_addr = 0x10023000; addr_t uart1_end_addr = 0x10023FFF; // not routed on Hifive1 Rev. A addr_t spi0_start_addr = 0x10014000; addr_t spi0_end_addr = 0x10014FFF; addr_t spi1_start_addr = 0x10024000; addr_t spi1_end_addr = 0x10024FFF; addr_t spi2_start_addr = 0x10034000; addr_t spi2_end_addr = 0x10034FFF; addr_t gpio0_start_addr = 0x10012000; addr_t gpio0_end_addr = 0x10012FFF; addr_t flash_size = 1024 * 1024 * 512; // 512 MB flash addr_t flash_start_addr = 0x20000000; addr_t flash_end_addr = flash_start_addr + flash_size - 1; addr_t dram_size = 1024 * 16; // 16 KB dram addr_t dram_start_addr = 0x80000000; addr_t dram_end_addr = dram_start_addr + dram_size - 1; bool enable_can = false; bool disable_inline_oled = false; bool wait_for_gpio_connection = false; bool forward_uart_0 = false; bool forward_uart_1 = false; std::string tun_device = "tun0"; HifiveOptions(void) { // clang-format off add_options() ("enable-inline-can", po::bool_switch(&enable_can), "enable support for CAN SPI module") ("disable-inline-oled", po::bool_switch(&disable_inline_oled), "enable support for OLED SPI module") ("forward-uart0-to-vbb", po::bool_switch(&forward_uart_0), "forwards UART_0 TX/RX to virtual breadboard") ("forward-uart1-to-vbb", po::bool_switch(&forward_uart_1), "forwards UART_1 TX/RX to virtual breadboard") ("wait-for-gpio-connection", po::bool_switch(&wait_for_gpio_connection), "Waits for a GPIO-Connection before starting program") ("tun-device", po::value(&tun_device), "tun device used by SLIP"); // clang-format on } void printValues(std::ostream& os) const override { os << std::hex; os << "flash_start_addr:\t" << +flash_start_addr << std::endl; os << "flash_end_addr:\t" << +flash_end_addr << std::endl; os << "dram_start_addr:\t" << +dram_start_addr << std::endl; os << "dram_end_addr:\t" << +dram_end_addr << std::endl; static_cast ( *this ).printValues(os); } }; int sc_main(int argc, char **argv) { HifiveOptions opt; opt.parse(argc, argv); std::srand(std::time(nullptr)); // use current time as seed for random generator tlm::tlm_global_quantum::instance().set(sc_core::sc_time(opt.tlm_global_quantum, sc_core::SC_NS)); ISS core(0); SimpleMemory dram("DRAM", opt.dram_size); SimpleMemory flash("Flash", opt.flash_size); ELFLoader loader(opt.input_program.c_str()); SimpleBus<2, 14> bus("SimpleBus"); CombinedMemoryInterface iss_mem_if("MemoryInterface", core); SyscallHandler sys("SyscallHandler"); FE310_PLIC<1, 53, 64, 7> plic("PLIC"); CLINT<1> clint("CLINT"); AON aon("AON"); PRCI prci("PRCI"); GPIO gpio0("GPIO0", INT_GPIO_BASE); SPI spi0("SPI0"); SPI spi1("SPI1"); std::shared_ptr can; if (opt.enable_can) { std::cout << "using internal CAN controller on SPI CS 0" << std::endl; can = std::make_shared(); spi1.connect(0, std::bind(&CAN::write, can, std::placeholders::_1)); } else { // pass through to gpio server spi1.connect(0, gpio0.getSPIwriteFunction(0)); } std::shared_ptr oled; if(!opt.disable_inline_oled) { std::cout << "[hifive_main] using internal SS1106 oled controller on SPI CS 2 (with DC as Pin 16, Bit 10)" << std::endl; oled = std::make_shared([&gpio0]{return gpio0.value & (1 << 10);}); // custom pin 16 is offset 10 spi1.connect(2, std::bind(&SS1106::write, oled, std::placeholders::_1)); } else { // pass through to gpio server spi1.connect(2, gpio0.getSPIwriteFunction(2)); } spi1.connect(3, gpio0.getSPIwriteFunction(3)); SPI spi2("SPI2"); std::shared_ptr uart0; std::shared_ptr uart0_tunnel; if(opt.forward_uart_0) { std::cout << "[hifive_main] tunneling UART0 over virtual breadboard protocol" << std::endl; uart0_tunnel = std::make_shared("UART0", 3); uart0_tunnel->register_transmit_function(gpio0.getUartTransmitFunction(17)); gpio0.registerUartReceiveFunction(16, std::bind(&Tunnel_UART::nonblock_receive, uart0_tunnel, std::placeholders::_1)); } else { uart0 = std::make_shared("UART0", 3); } std::shared_ptr slip; std::shared_ptr uart1_tunnel; if(opt.forward_uart_1) { std::cout << "[hifive_main] tunneling UART1 over virtual breadboard protocol" << std::endl; uart1_tunnel = std::make_shared("UART1", 4); // following pins only connected on RevB uart1_tunnel->register_transmit_function(gpio0.getUartTransmitFunction(23)); gpio0.registerUartReceiveFunction(18, std::bind(&Tunnel_UART::nonblock_receive, uart1_tunnel, std::placeholders::_1)); } else { slip = std::make_shared("SLIP", 4, opt.tun_device); } MaskROM maskROM("MASKROM"); DebugMemoryInterface dbg_if("DebugMemoryInterface"); MemoryDMI dram_dmi = MemoryDMI::create_start_size_mapping(dram.data, opt.dram_start_addr, dram.size); MemoryDMI flash_dmi = MemoryDMI::create_start_size_mapping(flash.data, opt.flash_start_addr, flash.size); InstrMemoryProxy instr_mem(flash_dmi, core); std::shared_ptr bus_lock = std::make_shared(); iss_mem_if.bus_lock = bus_lock; instr_memory_if *instr_mem_if = &iss_mem_if; data_memory_if *data_mem_if = &iss_mem_if; if (opt.use_instr_dmi) instr_mem_if = &instr_mem; if (opt.use_data_dmi) iss_mem_if.dmi_ranges.emplace_back(dram_dmi); bus.ports[ 0] = new PortMapping(opt.flash_start_addr, opt.flash_end_addr); bus.ports[ 1] = new PortMapping(opt.dram_start_addr, opt.dram_end_addr); bus.ports[ 2] = new PortMapping(opt.plic_start_addr, opt.plic_end_addr); bus.ports[ 3] = new PortMapping(opt.clint_start_addr, opt.clint_end_addr); bus.ports[ 4] = new PortMapping(opt.aon_start_addr, opt.aon_end_addr); bus.ports[ 5] = new PortMapping(opt.prci_start_addr, opt.prci_end_addr); bus.ports[ 6] = new PortMapping(opt.spi0_start_addr, opt.spi0_end_addr); bus.ports[ 7] = new PortMapping(opt.uart0_start_addr, opt.uart0_end_addr); bus.ports[ 8] = new PortMapping(opt.maskROM_start_addr,opt.maskROM_end_addr); bus.ports[ 9] = new PortMapping(opt.gpio0_start_addr, opt.gpio0_end_addr); bus.ports[10] = new PortMapping(opt.sys_start_addr, opt.sys_end_addr); bus.ports[11] = new PortMapping(opt.spi1_start_addr, opt.spi1_end_addr); bus.ports[12] = new PortMapping(opt.spi2_start_addr, opt.spi2_end_addr); bus.ports[13] = new PortMapping(opt.uart1_start_addr, opt.uart1_end_addr); loader.load_executable_image(flash, flash.size, opt.flash_start_addr, false); loader.load_executable_image(dram, dram.size, opt.dram_start_addr, false); core.init(instr_mem_if, data_mem_if, &clint, loader.get_entrypoint(), rv32_align_address(opt.dram_end_addr)); sys.init(dram.data, opt.dram_start_addr, loader.get_heap_addr()); sys.register_core(&core); if (opt.intercept_syscalls) core.sys = &sys; // connect TLM sockets iss_mem_if.isock.bind(bus.tsocks[0]); dbg_if.isock.bind(bus.tsocks[1]); bus.isocks[0].bind(flash.tsock); bus.isocks[1].bind(dram.tsock); bus.isocks[2].bind(plic.tsock); bus.isocks[3].bind(clint.tsock); bus.isocks[4].bind(aon.tsock); bus.isocks[5].bind(prci.tsock); bus.isocks[6].bind(spi0.tsock); if(uart0) { bus.isocks[7].bind(uart0->tsock); } else if (uart0_tunnel) { bus.isocks[7].bind(uart0_tunnel->tsock); } bus.isocks[8].bind(maskROM.tsock); bus.isocks[9].bind(gpio0.tsock); bus.isocks[10].bind(sys.tsock); bus.isocks[11].bind(spi1.tsock); bus.isocks[12].bind(spi2.tsock); if(slip) { bus.isocks[13].bind(slip->tsock); } else if (uart1_tunnel) { bus.isocks[13].bind(uart1_tunnel->tsock); } // connect interrupt signals/communication plic.target_harts[0] = &core; clint.target_harts[0] = &core; gpio0.plic = &plic; if(uart0) uart0->plic = &plic; if(uart0_tunnel) uart0_tunnel->plic = &plic; if(slip) slip->plic = &plic; if(uart1_tunnel) uart1_tunnel->plic = &plic; std::vector threads; threads.push_back(&core); core.trace = opt.trace_mode; // switch for printing instructions if (opt.use_debug_runner) { auto server = new GDBServer("GDBServer", threads, &dbg_if, opt.debug_port); new GDBServerRunner("GDBRunner", server, &core); } else { new DirectCoreRunner(core); } if(opt.wait_for_gpio_connection) { std::cout << "[hifive_main] Waiting for virtual breadboard protocol connection" << std::endl; while(!gpio0.isServerConnected()) { usleep(2000); } } sc_core::sc_start(); core.show(); return 0; } ================================================ FILE: vp/src/platform/hifive/maskROM.h ================================================ #pragma once #include #include #include "core/common/irq_if.h" #include "util/tlm_map.h" #include struct MaskROM : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; const uint32_t baseAddr = 0x1000; const uint32_t configStringOffs = 0x03b0; const char *configString = "/cs-v1/;" "/{" "model = \"SiFive,FE310G-0000-Z0\";" "compatible = \"sifive,fe300\";" "/include/ 0x20004;" "};"; MaskROM(sc_core::sc_module_name) { tsock.register_b_transport(this, &MaskROM::transport); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { tlm::tlm_command cmd = trans.get_command(); unsigned addr = trans.get_address(); auto *ptr = trans.get_data_ptr(); auto len = trans.get_data_length(); if (cmd != tlm::TLM_READ_COMMAND) { throw(std::runtime_error("invalid write to MROM")); } if (addr < 0x000C) { // should contain jump to OTP memset(ptr, 0, len); return; } if (addr + len <= 0x000C + sizeof(uint32_t)) { uint32_t buf = baseAddr + configStringOffs; memcpy(ptr, &buf, sizeof(uint32_t)); delay += sc_core::sc_time(len * 5, sc_core::SC_NS); return; } if (addr < configStringOffs) { std::cerr << "invalid access to Mask-ROM at " << std::hex << addr << std::endl; assert(false); return; } if (addr < configStringOffs + strlen(configString)) { uint32_t offs = addr - configStringOffs; uint8_t cut = offs + len <= strlen(configString) ? len : (offs + len) - strlen(configString); memcpy(ptr, &configString[offs], cut); if (cut != len) { memset(&ptr[cut], 0, len - cut); } return; } memset(ptr, 0, len); delay += sc_core::sc_time(len * 5, sc_core::SC_NS); return; } }; ================================================ FILE: vp/src/platform/hifive/oled/common.cpp ================================================ /* * common.cpp * * Created on: 24 Sep 2019 * Author: dwd */ #include "common.hpp" #include #include #include namespace ss1106 { IMPL_ENUM(Operator); State* getSharedState() { int shmid; for(unsigned i = 0; i < 2; i++) { if ((shmid = shmget(shm_key, sizeof(State), IPC_CREAT | 0660)) >= 0) continue; std::cerr << "Could not get " << sizeof(State) << " Byte of shared Memory " << int(shm_key) << " for oled display" << std::endl; perror("shmget"); std::cerr << "Trying again...\n" << std::endl; if(-1 == (shmctl(shm_key, IPC_RMID, nullptr))) { std::cerr << "Could not destroy SHM" << std::endl; perror("shmctl"); return nullptr; } } void *addr = shmat(shmid, nullptr, 0); if (addr == nullptr) { perror("shmat"); return nullptr; } return reinterpret_cast(addr); } }; ================================================ FILE: vp/src/platform/hifive/oled/common.hpp ================================================ /* * common.hpp * * Created on: 24 Sep 2019 * Author: dwd */ #pragma once #include #include "util/elegantEnums.hpp" namespace ss1106 { static constexpr uint8_t width = 132; static constexpr uint8_t padding_lr = 2; static constexpr uint8_t height = 64; static_assert(height%8 == 0, "invalid height"); static constexpr uint16_t shm_key = 1339; struct State { uint8_t changed:1; //beh, this is for syncing uint8_t column; uint8_t page; uint8_t pump_voltage:2; uint8_t display_startline:6; uint8_t contrast; uint8_t segment_remap:1; uint8_t entire_disp_on:1; uint8_t invert_color:1; uint8_t multiplex_whatever:6; uint8_t display_on:1; uint8_t frame[(height / 8)][width]; }; State* getSharedState(); DECLARE_ENUM(Operator, COL_LOW, COL_HIGH, PUMP_VOLTAGE, DISPLAY_START_LINE, CONTRAST_MODE_SET, //Double Command SEGMENT_REMAP, ENTIRE_DISPLAY, NORMAL_INVERSE, MULTIPLEX_RATIO, //Double command DC_DC_VOLTAGE, DISPLAY_ON, PAGE_ADDR, COMMON_OUTPUT_DIR, DISPLAY_OFFSET, //Double command DISPLAY_DIVIDE_RATIO, //Double command DIS_PRE_CHARGE_PERIOD, //Double command COMMON_PADS_STUFF, //DC VCOM_DESELECT, //DC RMW, RMW_END, NOP ); } ================================================ FILE: vp/src/platform/hifive/oled/oled.cpp ================================================ /* * oled.cpp * * Created on: 20 Sep 2019 * Author: dwd */ #include #include #include #include #include #include using namespace ss1106; const std::map SS1106::opcode = { {ss1106::Operator::COL_LOW, 0x00}, {ss1106::Operator::COL_HIGH, 0x10}, {ss1106::Operator::PUMP_VOLTAGE, 0b00110000}, {ss1106::Operator::DISPLAY_START_LINE, 0b01000000}, {ss1106::Operator::CONTRAST_MODE_SET, 0b10000001}, {ss1106::Operator::SEGMENT_REMAP, 0xA0}, {ss1106::Operator::ENTIRE_DISPLAY, 0xA4}, {ss1106::Operator::NORMAL_INVERSE, 0xA6}, {ss1106::Operator::MULTIPLEX_RATIO, 0b10101000}, {ss1106::Operator::DC_DC_VOLTAGE, 0x8B}, {ss1106::Operator::DISPLAY_ON, 0xAE}, {ss1106::Operator::PAGE_ADDR, 0xB0}, {ss1106::Operator::COMMON_OUTPUT_DIR, 0xC0}, {ss1106::Operator::DISPLAY_OFFSET, 0b11010011}, {ss1106::Operator::DISPLAY_DIVIDE_RATIO, 0b11010101}, {ss1106::Operator::DIS_PRE_CHARGE_PERIOD, 0b11011001}, {ss1106::Operator::COMMON_PADS_STUFF, 0b11011010}, {ss1106::Operator::VCOM_DESELECT, 0b11011011}, {ss1106::Operator::RMW, 0b11100000}, {ss1106::Operator::RMW_END, 0b11101110}, {ss1106::Operator::NOP, 0b11100011}, }; uint8_t SS1106::mask(Operator op) { switch(op) { case Operator::DISPLAY_START_LINE: return 0b11000000; case Operator::COL_LOW: case Operator::COL_HIGH: case Operator::PAGE_ADDR: case Operator::COMMON_OUTPUT_DIR: return 0b11110000; case Operator::PUMP_VOLTAGE: return 0b11111100; case Operator::SEGMENT_REMAP: case Operator::ENTIRE_DISPLAY: case Operator::NORMAL_INVERSE: case Operator::DISPLAY_ON: return 0b11111110; case Operator::CONTRAST_MODE_SET: case Operator::MULTIPLEX_RATIO: case Operator::DC_DC_VOLTAGE: case Operator::DISPLAY_OFFSET: case Operator::DISPLAY_DIVIDE_RATIO: case Operator::DIS_PRE_CHARGE_PERIOD: case Operator::COMMON_PADS_STUFF: case Operator::VCOM_DESELECT: case Operator::RMW: case Operator::RMW_END: case Operator::NOP: return 0b11111111; } return 0xff; } SS1106::Command SS1106::match(uint8_t cmd) { //printf("CMD: %02X\n", cmd); for(uint16_t opu = 0; opu < *Operator(); opu++) { Operator op = static_cast(opu); //Bwah, ugly //printf("%d: \tMask %02X, opcode %02X %s\n", opu, mask(op), opcode[op], (~Operator(op)).c_str()); if(((cmd ^ opcode.at(op)) & mask(op)) == 0) return Command{op, static_cast(cmd & ~mask(op))}; } return Command{Operator::NOP, 0}; } SS1106::SS1106(std::function getDCPin, ss1106::State* state_memory_override) : getDCPin(getDCPin) { if(!state_memory_override) { sharedSegment = ss1106::getSharedState(); if(sharedSegment == nullptr) { throw std::runtime_error("[OLED] shared Memory unexpectedly NULL"); } state = reinterpret_cast(sharedSegment); } else { // Memory is somewhere else state = state_memory_override; } memset(state, 0, sizeof(State)); }; SS1106::~SS1106(){ if (sharedSegment && shmdt(sharedSegment)) perror("shmdt"); }; uint8_t SS1106::write(uint8_t byte) { if(getDCPin()) { //Data //std::cout << "Got Data " << std::hex << (unsigned) byte << std::endl; if(state->column > width) { std::cerr << "OLED: Warning, exceeding column width (" << (int)state->column << " of " << (int)width << ")" << std::endl; return -1; //this is not in spec. } if(state->page > height/8) { std::cerr << "OLED: Warning, exceeding page (" << (int)state->page << " of " << (int)height/8 << ")" << std::endl; return -1; //this is not in spec. } state->frame[state->page][state->column] = byte; state->changed = 1; state->column++; } else { //Command switch(mode) { case Mode::normal: last_cmd = match(byte); //std::cout << "OLED: " << ~last_cmd.op << " " << std::hex << (unsigned)last_cmd.payload << std::endl; switch(last_cmd.op) { case Operator::COL_LOW: state->column = (state->column & 0xf0) | last_cmd.payload; break; case Operator::COL_HIGH: state->column = (state->column & 0x0f) | (last_cmd.payload << 4); break; case Operator::PUMP_VOLTAGE: state->pump_voltage = last_cmd.payload; break; case Operator::CONTRAST_MODE_SET: mode = Mode::second_arg; break; case Operator::NORMAL_INVERSE: state->invert_color = last_cmd.payload; break; //stuff inbetween... case Operator::DISPLAY_ON: state->display_on = last_cmd.payload; break; case Operator::PAGE_ADDR: state->page = last_cmd.payload; break; default: std::cerr << "OLED: Unhandled Operator " << ~last_cmd.op << std::endl; } break; case Mode::second_arg: //std::cout << "OLED: " << ~last_cmd.op << " " << std::hex << (unsigned)byte << std::endl; switch(last_cmd.op) { case Operator::CONTRAST_MODE_SET: state->contrast = byte; state->changed = 1; break; default: std::cerr << "OLED: Unhandled Dual-command-Operator " << ~last_cmd.op << std::endl; } mode = Mode::normal; break; } } //state->changed = 1; //This may be optimizable return 0; } ================================================ FILE: vp/src/platform/hifive/oled/oled.hpp ================================================ /* * oled.hpp * * Created on: 20 Sep 2019 * Author: dwd * * This class models the SH1106 oled Display driver. */ #pragma once #include "common.hpp" #include #include class SS1106 { public: typedef std::function GetDCPin_function; private: static const std::map opcode; struct Command { ss1106::Operator op; uint8_t payload; }; enum class Mode : uint_fast8_t { normal, second_arg } mode = Mode::normal; void *sharedSegment = nullptr; ss1106::State* state; Command last_cmd = Command{ss1106::Operator::NOP, 0}; GetDCPin_function getDCPin; uint8_t mask(ss1106::Operator op); Command match(uint8_t cmd); public: SS1106(GetDCPin_function getDCPin, ss1106::State* state_memory_override = nullptr); ~SS1106(); uint8_t write(uint8_t byte); }; ================================================ FILE: vp/src/platform/hifive/otp.h ================================================ #pragma once #include #include #include "irq_if.h" #include "tlm_map.h" struct OTP : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; OTP(sc_core::sc_module_name) { tsock.register_b_transport(this, &OTP::transport); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { assert(false && "OTP not yet implemented"); return; } }; ================================================ FILE: vp/src/platform/hifive/prci.h ================================================ #ifndef RISCV_VP_PRCI_H #define RISCV_VP_PRCI_H #include #include #include "core/common/irq_if.h" #include "util/tlm_map.h" struct PRCI : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; // memory mapped configuration registers uint32_t hfrosccfg = 0; uint32_t hfxosccfg = 0; uint32_t pllcfg = 0; uint32_t plloutdiv = 0; enum { HFROSCCFG_REG_ADDR = 0x0, HFXOSCCFG_REG_ADDR = 0x4, PLLCFG_REG_ADDR = 0x8, PLLOUTDIV_REG_ADDR = 0xC, }; vp::map::LocalRouter router = {"PRCI"}; PRCI(sc_core::sc_module_name) { tsock.register_b_transport(this, &PRCI::transport); router .add_register_bank({ {HFROSCCFG_REG_ADDR, &hfrosccfg}, {HFXOSCCFG_REG_ADDR, &hfxosccfg}, {PLLCFG_REG_ADDR, &pllcfg}, {PLLOUTDIV_REG_ADDR, &plloutdiv}, }) .register_handler(this, &PRCI::register_access_callback); } void register_access_callback(const vp::map::register_access_t &r) { /* Pretend that the crystal oscillator output is always ready. */ if (r.read && r.vptr == &hfxosccfg) hfxosccfg = 1 << 31; r.fn(); if ((r.vptr == &hfrosccfg) && r.nv) hfrosccfg |= 1 << 31; if ((r.vptr == &pllcfg) && r.nv) pllcfg |= 1 << 31; } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { router.transport(trans, delay); } }; #endif // RISCV_VP_PRCI_H ================================================ FILE: vp/src/platform/hifive/spi.h ================================================ #ifndef RISCV_VP_SPI_H #define RISCV_VP_SPI_H #include #include #include "core/common/irq_if.h" #include "util/tlm_map.h" #include #include typedef std::function SpiWriteFunction; typedef uint32_t Pin; struct SPI : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; //single queue for all targets static constexpr uint_fast8_t queue_size = 16; std::queue rxqueue; std::map targets; // memory mapped configuration registers uint32_t sckdiv = 0; uint32_t sckmode = 0; uint32_t csid = 0; uint32_t csdef = 1; uint32_t csmode = 0; uint32_t delay0 = 0; uint32_t delay1 = 0; uint32_t fmt = 0; uint32_t txdata = 0; uint32_t rxdata = 0; uint32_t txmark = 0; uint32_t rxmark = 0; uint32_t fctrl = 1; uint32_t ffmt = 0; uint32_t ie = 0; uint32_t ip = 0; enum { SCKDIV_REG_ADDR = 0x00, SCKMODE_REG_ADDR = 0x04, CSID_REG_ADDR = 0x10, CSDEF_REG_ADDR = 0x14, CSMODE_REG_ADDR = 0x18, DELAY0_REG_ADDR = 0x28, DELAY1_REG_ADDR = 0x2C, FMT_REG_ADDR = 0x40, TXDATA_REG_ADDR = 0x48, RXDATA_REG_ADDR = 0x4C, TXMARK_REG_ADDR = 0x50, RXMARK_REG_ADDR = 0x54, FCTRL_REG_ADDR = 0x60, FFMT_REG_ADDR = 0x64, IE_REG_ADDR = 0x70, IP_REG_ADDR = 0x74, }; static constexpr uint_fast8_t SPI_IP_TXWM = 0x1; static constexpr uint_fast8_t SPI_IP_RXWM = 0x2; vp::map::LocalRouter router = {"SPI"}; SPI(sc_core::sc_module_name) { tsock.register_b_transport(this, &SPI::transport); router .add_register_bank({ {SCKDIV_REG_ADDR, &sckdiv}, {SCKMODE_REG_ADDR, &sckmode}, {CSID_REG_ADDR, &csid}, {CSDEF_REG_ADDR, &csdef}, {CSMODE_REG_ADDR, &csmode}, {DELAY0_REG_ADDR, &delay0}, {DELAY1_REG_ADDR, &delay1}, {FMT_REG_ADDR, &fmt}, {TXDATA_REG_ADDR, &txdata}, {RXDATA_REG_ADDR, &rxdata}, {TXMARK_REG_ADDR, &txmark}, {RXMARK_REG_ADDR, &rxmark}, {FCTRL_REG_ADDR, &fctrl}, {FFMT_REG_ADDR, &ffmt}, {IE_REG_ADDR, &ie}, {IP_REG_ADDR, &ip}, }) .register_handler(this, &SPI::register_access_callback); } void register_access_callback(const vp::map::register_access_t &r) { if (r.read) { if (r.vptr == &rxdata) { auto target = targets.find(csid); if (target == targets.end()) { std::cerr << "Read on unregistered Chip-Select " << csid << std::endl; } else { if (rxqueue.empty()) { rxdata = 1 << 31; } else { rxdata = rxqueue.front(); rxqueue.pop(); } } } } r.fn(); if (r.write) { if (r.vptr == &csid) { //std::cout << "Chip select " << csid << std::endl; } else if (r.vptr == &txdata) { //std::cout << std::hex << txdata << " "; auto target = targets.find(csid); if (target != targets.end()) { rxqueue.push(target->second(txdata)); //TODO: Model RX-Watermark IP if(rxqueue.size() > queue_size) rxqueue.pop(); //TODO: Model latency. if(txmark > 0 && (ie & SPI_IP_TXWM)) ip |= SPI_IP_TXWM; } else { std::cerr << "Write on unregistered Chip-Select " << csid << std::endl; } txdata = 0; } } } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { router.transport(trans, delay); } void connect(Pin cs, SpiWriteFunction interface) { if(cs == 1 || cs > 3) { std::cerr << "SPI: Unsupported chip select " << cs << std::endl; return; } targets.insert(std::pair(cs, interface)); } }; #endif // RISCV_VP_SPI_H ================================================ FILE: vp/src/platform/hifive/tunnel-uart.cpp ================================================ #include "tunnel-uart.hpp" #include Tunnel_UART::Tunnel_UART(sc_core::sc_module_name name, uint32_t irqsrc) : UART_IF(name, irqsrc) { stop = false; rx_worker = std::thread(std::bind(&Tunnel_UART::rx_dequeue, this)); }; Tunnel_UART::~Tunnel_UART(){ stop = true; if(rx_worker.joinable()) { spost(&rxempty); // unblock receive thread rx_worker.join(); } if(tx_worker.joinable()) { spost(&txfull); // unblock transmit thread } } void Tunnel_UART::nonblock_receive(gpio::UART_Bytes bytes) { const std::lock_guard lock(nonblock_rx_mutex); if(nonblocking_rx_queue.size() > DROP_AT_FIFO_DEPTH - UART_FIFO_DEPTH) { std::cerr << "[tunnel-uart] Warn: pre-rx_queue growing to " << nonblocking_rx_queue.size() << " byte." << std::endl; std::cerr << " The VP can probably not keep up with the remote." << std::endl; } if(nonblocking_rx_queue.size() > DROP_AT_FIFO_DEPTH) { // Dropping elements return; } for(const auto& byte : bytes) { nonblocking_rx_queue.push(byte); } } void Tunnel_UART::register_transmit_function(UartTXFunction fun) { tx_worker = std::thread(std::bind(&Tunnel_UART::tx_dequeue, this, fun)); } void Tunnel_UART::rx_dequeue() { while(!stop) { nonblock_rx_mutex.lock(); if(!nonblocking_rx_queue.empty() && !stop){ gpio::UART_Byte byte = nonblocking_rx_queue.front(); nonblocking_rx_queue.pop(); nonblock_rx_mutex.unlock(); rxpush(byte); // may block } else { nonblock_rx_mutex.unlock(); } } } void Tunnel_UART::tx_dequeue(UartTXFunction fun) { while(!stop) { // TODO: Perhaps make this a SysC-Thread for more realism? const auto data = txpull(); // TODO: Optimize if more elems are in tx queue if(stop) break; fun(gpio::UART_Bytes{data}); } } ================================================ FILE: vp/src/platform/hifive/tunnel-uart.hpp ================================================ #pragma once #include "uart_if.h" #include // For UART_Byte types #include #include #include #include typedef std::function UartRXFunction; // from server to peripheral typedef std::function UartTXFunction; // from peripheral to server class Tunnel_UART : public UART_IF { static constexpr unsigned DROP_AT_FIFO_DEPTH = 1600; public: Tunnel_UART(sc_core::sc_module_name, uint32_t irqsrc); virtual ~Tunnel_UART(void); void nonblock_receive(gpio::UART_Bytes bytes); void register_transmit_function(UartTXFunction fun); private: std::queue nonblocking_rx_queue; std::mutex nonblock_rx_mutex; bool stop; std::thread rx_worker; void rx_dequeue(); std::thread tx_worker; void tx_dequeue(UartTXFunction fun); }; ================================================ FILE: vp/src/platform/hwitl/CMakeLists.txt ================================================ file(GLOB HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h*) file(GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.c*) add_git_submodule(virtual-bus) add_executable(hwitl-vp ${SOURCES} ) target_link_libraries(hwitl-vp rv32 virtual-bus platform-common gdb-mc ${Boost_LIBRARIES} systemc pthread) INSTALL(TARGETS hwitl-vp RUNTIME DESTINATION bin) ================================================ FILE: vp/src/platform/hwitl/main.cpp ================================================ #include #include #include "core/common/clint.h" #include "core/common/real_clint.h" #include "elf_loader.h" #include "fe310_plic.h" #include "debug_memory.h" #include "iss.h" #include "mem.h" #include "memory.h" #include "syscall.h" #include "util/options.h" #include "platform/common/options.h" #include "platform/common/terminal.h" #include "virtual_bus_tlm_connector.hpp" #include "gdb-mc/gdb_server.h" #include "gdb-mc/gdb_runner.h" #include #include #include #include #include #include using namespace rv32; namespace po = boost::program_options; class HwitlOptions : public Options { public: typedef unsigned int addr_t; std::string virtual_bus_device; unsigned virtual_bus_baudrate = 0; std::string test_signature; bool use_real_clint = false; addr_t mem_size = 1024 * 1024 * 32; // 32 MB ram, to place it before the CLINT and run the base examples (assume // memory start at zero) without modifications addr_t mem_start_addr = 0x00000000; addr_t mem_end_addr = mem_start_addr + mem_size - 1; addr_t clint_start_addr = 0x02000000; addr_t clint_end_addr = 0x0200ffff; addr_t sys_start_addr = 0x02010000; addr_t sys_end_addr = 0x020103ff; addr_t plic_start_addr = 0x40000000; addr_t plic_end_addr = 0x41000000; addr_t term_start_addr = 0x20000000; addr_t term_end_addr = term_start_addr + 16; addr_t virtual_bus_start_addr = 0x50000000; addr_t virtual_bus_end_addr = 0x5FFFFFFF; OptionValue entry_point; HwitlOptions(void) { // clang-format off add_options() ("use-real-clint", po::bool_switch(&use_real_clint),"Lock clint to wall-clock time") ("memory-start", po::value(&mem_start_addr),"set memory start address") ("memory-size", po::value(&mem_size), "set memory size") ("entry-point", po::value(&entry_point.option),"set entry point address (ISS program counter)") ("virtual-bus-device", po::value(&virtual_bus_device)->required(),"tty to virtual bus responder") ("virtual-bus-baudrate", po::value(&virtual_bus_baudrate),"If set, change baudrate of tty device") ("virtual-device-start", po::value(&virtual_bus_start_addr),"start of virtual peripheral") ("virtual-device-end", po::value(&virtual_bus_end_addr),"end of virtual peripheral"); // clang-format on } void parse(int argc, char **argv) override { Options::parse(argc, argv); entry_point.finalize(parse_ulong_option); } }; std::ostream& operator<<(std::ostream& os, const HwitlOptions& o) { os << "virtual-bus-device:\t" << o.virtual_bus_device << std::endl; os << static_cast ( o ); return os; } int sc_main(int argc, char **argv) { HwitlOptions opt; opt.parse(argc, argv); std::srand(std::time(nullptr)); // use current time as seed for random generator tlm::tlm_global_quantum::instance().set(sc_core::sc_time(opt.tlm_global_quantum, sc_core::SC_NS)); ISS core(0); SimpleMemory mem("SimpleMemory", opt.mem_size); SimpleTerminal term("SimpleTerminal"); ELFLoader loader(opt.input_program.c_str()); SimpleBus<2, 6> bus("SimpleBus"); CombinedMemoryInterface iss_mem_if("MemoryInterface", core); SyscallHandler sys("SyscallHandler"); FE310_PLIC<1, 64, 96, 32> plic("PLIC"); DebugMemoryInterface dbg_if("DebugMemoryInterface"); std::shared_ptr> sim_clint; std::shared_ptr real_clint; std::vector real_clint_targets {&core}; clint_if* one_clint; if(opt.use_real_clint) { real_clint = std::make_shared("REAL_CLINT", real_clint_targets); one_clint = real_clint.get(); } else { sim_clint = std::make_shared>("SIM_CLINT"); one_clint = sim_clint.get(); } int virtual_bus_device_handle = -1; virtual_bus_device_handle = open(opt.virtual_bus_device.c_str(), O_RDWR| O_NOCTTY); if(virtual_bus_device_handle < 0) { std::cerr << "[hwitl-vp] Device " << opt.virtual_bus_device << " could not be opened: " << strerror(errno) << std::endl; return -1; } if(opt.virtual_bus_baudrate > 0) { if(!setBaudrate(virtual_bus_device_handle, opt.virtual_bus_baudrate)) { std::cerr << "[hwitl-vp] WARN: Could not set baudrate of " << opt.virtual_bus_baudrate << "!" << std::endl; } } setTTYRawmode(virtual_bus_device_handle); // ignore return Initiator virtual_bus_connector(virtual_bus_device_handle); VirtualBusMember virtual_bus_member("virtual_bus_member", virtual_bus_connector, opt.virtual_bus_start_addr); virtual_bus_member.setInterruptRoutine([&plic](){plic.gateway_trigger_interrupt(2);}); MemoryDMI dmi = MemoryDMI::create_start_size_mapping(mem.data, opt.mem_start_addr, mem.size); InstrMemoryProxy instr_mem(dmi, core); std::shared_ptr bus_lock = std::make_shared(); iss_mem_if.bus_lock = bus_lock; instr_memory_if *instr_mem_if = &iss_mem_if; data_memory_if *data_mem_if = &iss_mem_if; if (opt.use_instr_dmi) instr_mem_if = &instr_mem; if (opt.use_data_dmi) { iss_mem_if.dmi_ranges.emplace_back(dmi); } uint64_t entry_point = loader.get_entrypoint(); if (opt.entry_point.available) entry_point = opt.entry_point.value; try { loader.load_executable_image(mem, mem.size, opt.mem_start_addr); } catch(ELFLoader::load_executable_exception& e) { std::cerr << e.what() << std::endl; std::cerr << "Memory map: " << std::endl; std::cerr << opt << std::endl; return -1; } /* * The rv32 calling convention defaults to 32 bit, but as this Config is * mainly used together with the syscall handler, this helps for certain floats. * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc */ core.init(instr_mem_if, data_mem_if, one_clint, entry_point, rv64_align_address(opt.mem_end_addr)); sys.init(mem.data, opt.mem_start_addr, loader.get_heap_addr()); sys.register_core(&core); if (opt.intercept_syscalls) core.sys = &sys; // address mapping { unsigned it = 0; bus.ports[it++] = new PortMapping(opt.mem_start_addr, opt.mem_end_addr); bus.ports[it++] = new PortMapping(opt.clint_start_addr, opt.clint_end_addr); bus.ports[it++] = new PortMapping(opt.plic_start_addr, opt.plic_end_addr); bus.ports[it++] = new PortMapping(opt.term_start_addr, opt.term_end_addr); bus.ports[it++] = new PortMapping(opt.sys_start_addr, opt.sys_end_addr); bus.ports[it++] = new PortMapping(opt.virtual_bus_start_addr, opt.virtual_bus_end_addr); } // connect TLM sockets iss_mem_if.isock.bind(bus.tsocks[0]); dbg_if.isock.bind(bus.tsocks[1]); { unsigned it = 0; bus.isocks[it++].bind(mem.tsock); if(opt.use_real_clint) bus.isocks[it++].bind(real_clint->tsock); else bus.isocks[it++].bind(sim_clint->tsock); bus.isocks[it++].bind(plic.tsock); bus.isocks[it++].bind(term.tsock); bus.isocks[it++].bind(sys.tsock); bus.isocks[it++].bind(virtual_bus_member.tsock); } // connect interrupt signals/communication plic.target_harts[0] = &core; if(sim_clint) sim_clint->target_harts[0] = &core; std::vector threads; threads.push_back(&core); core.trace = opt.trace_mode; // switch for printing instructions if (opt.use_debug_runner) { auto server = new GDBServer("GDBServer", threads, &dbg_if, opt.debug_port); new GDBServerRunner("GDBRunner", server, &core); } else { new DirectCoreRunner(core); } sc_core::sc_start(); core.show(); if (opt.test_signature != "") { auto begin_sig = loader.get_begin_signature_address(); auto end_sig = loader.get_end_signature_address(); { std::cout << std::hex; std::cout << "begin_signature: " << begin_sig << std::endl; std::cout << "end_signature: " << end_sig << std::endl; std::cout << "signature output file: " << opt.test_signature << std::endl; std::cout << std::dec; } assert(end_sig >= begin_sig); assert(begin_sig >= opt.mem_start_addr); auto begin = begin_sig - opt.mem_start_addr; auto end = end_sig - opt.mem_start_addr; std::ofstream sigfile(opt.test_signature, std::ios::out); auto n = begin; while (n < end) { sigfile << std::hex << std::setw(2) << std::setfill('0') << (unsigned)mem.data[n]; ++n; } } return 0; } ================================================ FILE: vp/src/platform/hwitl/virtual_bus_tlm_connector.cpp ================================================ /* * virtual_bus_tlm_connector.cpp * * Created on: Oct 20, 2022 * Author: dwd */ #include "virtual_bus_tlm_connector.hpp" using namespace std; using namespace sc_core; using namespace tlm_utils; using namespace tlm; VirtualBusMember::VirtualBusMember(sc_module_name name, Initiator& virtual_bus_connector, hwitl::Address base_address) : sc_module(name), virtual_bus(virtual_bus_connector), base_address(base_address) { tsock.register_b_transport(this, &VirtualBusMember::transport); m_read_delay = sc_time(SC_ZERO_TIME); m_write_delay = sc_time(SC_ZERO_TIME); // TODO: Issue Reset command to remote device // Zero time: Special case, dont update m_interrupt_polling_delay = SC_ZERO_TIME; SC_THREAD(interrupt_service); } void VirtualBusMember::setDelayTimes(sc_time read_delay, sc_time write_delay) { m_read_delay = read_delay; m_write_delay = write_delay; } void VirtualBusMember::setInterruptRoutine(std::function trigger_target, sc_core::sc_time polling_time) { trigger_interrupt_callback = trigger_target; m_interrupt_polling_delay = polling_time; m_interrupt_event.notify(m_interrupt_polling_delay); } void VirtualBusMember::transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { tlm::tlm_command cmd = trans.get_command(); unsigned addr = trans.get_address(); auto len = trans.get_data_length(); if(len > sizeof(hwitl::Payload)) { cerr << "[virtual_bus_tlm_connector] accesses of length > " << sizeof(hwitl::Payload) << " currently unsupported (was " << len << ")" << endl; trans.set_response_status(tlm_response_status::TLM_ADDRESS_ERROR_RESPONSE); return; } hwitl::Payload temp; hwitl::Payload* data = &temp; const bool unaligned = len != sizeof(hwitl::Payload); if(!unaligned) { data = reinterpret_cast(trans.get_data_ptr()); } else { temp = 0; if(cmd == tlm::TLM_WRITE_COMMAND) { // This just ignores word size and writes to unaligned addresses. // WARN: This lets the actual peripheral handle this assert(len <= sizeof(hwitl::Payload)); // should always be the case memcpy(data, trans.get_data_ptr(), len); } } if (cmd == tlm::TLM_WRITE_COMMAND) { const auto response = virtual_bus.write(base_address + addr, *data); switch(response) { case hwitl::ResponseStatus::Ack::ok: break; case hwitl::ResponseStatus::Ack::not_mapped: trans.set_response_status(tlm_response_status::TLM_ADDRESS_ERROR_RESPONSE); cerr << "[virtual_bus_tlm_connector] Write Address " << showbase << hex << base_address + addr << dec << " not mapped" << endl; break; default: trans.set_response_status(tlm_response_status::TLM_GENERIC_ERROR_RESPONSE); cerr << "[virtual_bus_tlm_connector] Write Error '" << static_cast(response) << "' at address " << showbase << hex << base_address + addr << dec << endl; } delay += m_write_delay; } else if (cmd == tlm::TLM_READ_COMMAND) { const auto response = virtual_bus.read(base_address + addr); if(!response) { trans.set_response_status(tlm_response_status::TLM_GENERIC_ERROR_RESPONSE); cerr << "[virtual_bus_tlm_connector] Could not read from remote" << endl; return; } switch(response->getStatus().ack) { case hwitl::ResponseStatus::Ack::ok: *data = response->getPayload(); break; case hwitl::ResponseStatus::Ack::not_mapped: trans.set_response_status(tlm_response_status::TLM_ADDRESS_ERROR_RESPONSE); cerr << "[virtual_bus_tlm_connector] Read Address " << showbase << hex << base_address + addr << dec << " not mapped" << endl; break; default: trans.set_response_status(tlm_response_status::TLM_GENERIC_ERROR_RESPONSE); cerr << "[virtual_bus_tlm_connector] Read Error " << static_cast(response->getStatus().ack) << " at address " << showbase << hex << base_address + addr << dec << endl; } if(unaligned) { assert(len <= sizeof(hwitl::Payload)); // should always be the case memcpy(trans.get_data_ptr(), data, len); } delay += m_read_delay; } else { sc_assert(false && "unsupported tlm command"); } } void VirtualBusMember::interrupt_service() { while (true) { if(m_interrupt_polling_delay > SC_ZERO_TIME) m_interrupt_event.notify(m_interrupt_polling_delay); sc_core::wait(m_interrupt_event); if(trigger_interrupt_callback && virtual_bus.getInterrupt()) trigger_interrupt_callback(); } } ================================================ FILE: vp/src/platform/hwitl/virtual_bus_tlm_connector.hpp ================================================ /* * virtual_bus_tlm_connector.cpp * * Created on: Oct 20, 2022 * Author: dwd */ #include #include #include #include "bus.h" #include "virtual-bus/initiator.hpp" struct VirtualBusMember : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; Initiator& virtual_bus; const hwitl::Address base_address; sc_core::sc_time m_read_delay; sc_core::sc_time m_write_delay; // interrupt stuff sc_core::sc_time m_interrupt_polling_delay; std::function trigger_interrupt_callback; sc_core::sc_event m_interrupt_event; /** * @input base_address will be added to the local (!) address */ VirtualBusMember(sc_core::sc_module_name, Initiator& virtual_bus_connector, hwitl::Address base_address = 0); void setDelayTimes(sc_core::sc_time read_delay, sc_core::sc_time write_delay); void setInterruptRoutine(std::function trigger_target, sc_core::sc_time polling_time = sc_core::sc_time(10, sc_core::SC_MS)); void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay); SC_HAS_PROCESS(VirtualBusMember); void interrupt_service(); }; ================================================ FILE: vp/src/platform/linux/CMakeLists.txt ================================================ file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) add_executable(linux-vp linux_main.cpp ${HEADERS}) target_link_libraries(linux-vp rv64 platform-common gdb-mc ${Boost_LIBRARIES} systemc pthread) INSTALL(TARGETS linux-vp RUNTIME DESTINATION bin) ================================================ FILE: vp/src/platform/linux/linux_main.cpp ================================================ #include #include #include "core/common/clint.h" #include "elf_loader.h" #include "fu540_plic.h" #include "debug_memory.h" #include "iss.h" #include "mem.h" #include "memory.h" #include "mmu.h" #include "platform/common/slip.h" #include "platform/common/uart.h" #include "prci.h" #include "syscall.h" #include "debug.h" #include "util/options.h" #include "platform/common/options.h" #include "gdb-mc/gdb_server.h" #include "gdb-mc/gdb_runner.h" #include #include #include #include #include #include enum { NUM_CORES = 5, }; using namespace rv64; namespace po = boost::program_options; struct LinuxOptions : public Options { public: typedef unsigned int addr_t; addr_t mem_size = 1024u * 1024u * 2048u; // 2048 MB ram addr_t mem_start_addr = 0x80000000; addr_t mem_end_addr = mem_start_addr + mem_size - 1; addr_t clint_start_addr = 0x02000000; addr_t clint_end_addr = 0x0200ffff; addr_t sys_start_addr = 0x02010000; addr_t sys_end_addr = 0x020103ff; addr_t dtb_rom_start_addr = 0x00001000; addr_t dtb_rom_size = 0x2000; addr_t dtb_rom_end_addr = dtb_rom_start_addr + dtb_rom_size - 1; addr_t uart0_start_addr = 0x10010000; addr_t uart0_end_addr = 0x10010fff; addr_t uart1_start_addr = 0x10011000; addr_t uart1_end_addr = 0x10011fff; addr_t plic_start_addr = 0x0C000000; addr_t plic_end_addr = 0x10000000; addr_t prci_start_addr = 0x10000000; addr_t prci_end_addr = 0x1000FFFF; OptionValue entry_point; std::string dtb_file; std::string tun_device = "tun0"; LinuxOptions(void) { // clang-format off add_options() ("memory-start", po::value(&mem_start_addr),"set memory start address") ("memory-size", po::value(&mem_size), "set memory size") ("entry-point", po::value(&entry_point.option),"set entry point address (ISS program counter)") ("dtb-file", po::value(&dtb_file)->required(), "dtb file for boot loading") ("tun-device", po::value(&tun_device), "tun device used by SLIP"); // clang-format on } void parse(int argc, char **argv) override { Options::parse(argc, argv); entry_point.finalize(parse_ulong_option); mem_end_addr = mem_start_addr + mem_size - 1; } }; class Core { public: ISS iss; MMU mmu; CombinedMemoryInterface memif; InstrMemoryProxy imemif; Core(unsigned int id, MemoryDMI dmi) : iss(id), mmu(iss), memif(("MemoryInterface" + std::to_string(id)).c_str(), iss, mmu), imemif(dmi, iss) { return; } void init(bool use_data_dmi, bool use_instr_dmi, clint_if *clint, uint64_t entry, uint64_t addr) { if (use_data_dmi) memif.dmi_ranges.emplace_back(imemif.dmi); iss.init(get_instr_memory_if(use_instr_dmi), &memif, clint, entry, addr); } private: instr_memory_if *get_instr_memory_if(bool use_instr_dmi) { if (use_instr_dmi) return &imemif; else return &memif; } }; int sc_main(int argc, char **argv) { LinuxOptions opt; opt.parse(argc, argv); std::srand(std::time(nullptr)); // use current time as seed for random generator tlm::tlm_global_quantum::instance().set(sc_core::sc_time(opt.tlm_global_quantum, sc_core::SC_NS)); SimpleMemory mem("SimpleMemory", opt.mem_size); SimpleMemory dtb_rom("DBT_ROM", opt.dtb_rom_size); ELFLoader loader(opt.input_program.c_str()); SimpleBus bus("SimpleBus"); SyscallHandler sys("SyscallHandler"); FU540_PLIC plic("PLIC", NUM_CORES); CLINT clint("CLINT"); PRCI prci("PRCI"); UART uart0("UART0", 3); SLIP slip("SLIP", 4, opt.tun_device); DebugMemoryInterface dbg_if("DebugMemoryInterface"); MemoryDMI dmi = MemoryDMI::create_start_size_mapping(mem.data, opt.mem_start_addr, mem.size); Core *cores[NUM_CORES]; for (unsigned i = 0; i < NUM_CORES; i++) { cores[i] = new Core(i, dmi); } std::shared_ptr bus_lock = std::make_shared(); for (size_t i = 0; i < NUM_CORES; i++) { cores[i]->memif.bus_lock = bus_lock; cores[i]->mmu.mem = &cores[i]->memif; } uint64_t entry_point = loader.get_entrypoint(); if (opt.entry_point.available) entry_point = opt.entry_point.value; loader.load_executable_image(mem, mem.size, opt.mem_start_addr); sys.init(mem.data, opt.mem_start_addr, loader.get_heap_addr()); for (size_t i = 0; i < NUM_CORES; i++) { cores[i]->init(opt.use_data_dmi, opt.use_instr_dmi, &clint, entry_point, rv64_align_address(opt.mem_end_addr)); sys.register_core(&cores[i]->iss); if (opt.intercept_syscalls) cores[i]->iss.sys = &sys; } // setup port mapping bus.ports[0] = new PortMapping(opt.mem_start_addr, opt.mem_end_addr); bus.ports[1] = new PortMapping(opt.clint_start_addr, opt.clint_end_addr); bus.ports[2] = new PortMapping(opt.sys_start_addr, opt.sys_end_addr); bus.ports[3] = new PortMapping(opt.dtb_rom_start_addr, opt.dtb_rom_end_addr); bus.ports[4] = new PortMapping(opt.uart0_start_addr, opt.uart0_end_addr); bus.ports[5] = new PortMapping(opt.uart1_start_addr, opt.uart1_end_addr); bus.ports[6] = new PortMapping(opt.plic_start_addr, opt.plic_end_addr); bus.ports[7] = new PortMapping(opt.prci_start_addr, opt.prci_end_addr); // connect TLM sockets for (size_t i = 0; i < NUM_CORES; i++) { cores[i]->memif.isock.bind(bus.tsocks[i]); } dbg_if.isock.bind(bus.tsocks[NUM_CORES]); bus.isocks[0].bind(mem.tsock); bus.isocks[1].bind(clint.tsock); bus.isocks[2].bind(sys.tsock); bus.isocks[3].bind(dtb_rom.tsock); bus.isocks[4].bind(uart0.tsock); bus.isocks[5].bind(slip.tsock); bus.isocks[6].bind(plic.tsock); bus.isocks[7].bind(prci.tsock); // connect interrupt signals/communication for (size_t i = 0; i < NUM_CORES; i++) { plic.target_harts[i] = &cores[i]->iss; clint.target_harts[i] = &cores[i]->iss; } uart0.plic = &plic; slip.plic = &plic; for (size_t i = 0; i < NUM_CORES; i++) { // switch for printing instructions cores[i]->iss.trace = opt.trace_mode; // ignore WFI instructions (handle them as a NOP, which is ok according to the RISC-V ISA) to avoid running too // fast ahead with simulation time when the CPU is idle cores[i]->iss.ignore_wfi = true; // emulate RISC-V core boot loader cores[i]->iss.regs[RegFile::a0] = cores[i]->iss.get_hart_id(); cores[i]->iss.regs[RegFile::a1] = opt.dtb_rom_start_addr; } // OpenSBI boots all harts except hart 0 by default. // // To prevent this hart from being scheduled when stuck in // the OpenSBI `sbi_hart_hang()` function do not ignore WFI on // this hart. // // See: https://github.com/riscv/opensbi/commit/d70f8aab45d1e449b3b9be26e050b20ed76e12e9 cores[0]->iss.ignore_wfi = false; // load DTB (Device Tree Binary) file dtb_rom.load_binary_file(opt.dtb_file, 0); std::vector mmus; std::vector dharts; if (opt.use_debug_runner) { for (size_t i = 0; i < NUM_CORES; i++) { dharts.push_back(&cores[i]->iss); mmus.push_back(&cores[i]->memif); } auto server = new GDBServer("GDBServer", dharts, &dbg_if, opt.debug_port, mmus); for (size_t i = 0; i < dharts.size(); i++) new GDBServerRunner(("GDBRunner" + std::to_string(i)).c_str(), server, dharts[i]); } else { for (size_t i = 0; i < NUM_CORES; i++) { new DirectCoreRunner(cores[i]->iss); } } sc_core::sc_start(); for (size_t i = 0; i < NUM_CORES; i++) { cores[i]->iss.show(); } return 0; } ================================================ FILE: vp/src/platform/linux/prci.h ================================================ #ifndef RISCV_VP_PRCI_H #define RISCV_VP_PRCI_H #include #include #include "core/common/irq_if.h" #include "util/tlm_map.h" struct PRCI : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; // memory mapped configuration registers uint32_t hfrosccfg = 0; uint32_t core_pllcfg0 = 0; uint32_t ddr_pllcfg0 = 0; uint32_t core_pllcfg1 = 0; uint32_t gemgxl_pllcfg0 = 0; uint32_t gemgxl_pllcfg1 = 0; uint32_t core_clksel = 0; uint32_t reset = 0; uint32_t clkmux_status = 0; enum { HFROSCCFG_REG_ADDR = 0x0, CORE_PLLCFG0_REG_ADDR = 0x4, DDR_PLLCFG0_REG_ADDR = 0x8, CORE_PLLCFG1_REG_ADDR = 0x10, GEMGXL_PLLCFG0_REG_ADDR = 0x1C, GEMGXL_PLLCFG1_REG_ADDR = 0x20, CORE_CLKSEL_REG_ADDR = 0x24, RESET_REG_ADDR = 0x28, CLKMUX_STATUS_REG_ADDR = 0x2C, }; vp::map::LocalRouter router = {"PRCI"}; PRCI(sc_core::sc_module_name) { tsock.register_b_transport(this, &PRCI::transport); router .add_register_bank({ {HFROSCCFG_REG_ADDR, &hfrosccfg}, {CORE_PLLCFG0_REG_ADDR, &core_pllcfg0}, {DDR_PLLCFG0_REG_ADDR, &ddr_pllcfg0}, {CORE_PLLCFG1_REG_ADDR, &core_pllcfg1}, {GEMGXL_PLLCFG0_REG_ADDR, &gemgxl_pllcfg0}, {GEMGXL_PLLCFG1_REG_ADDR, &gemgxl_pllcfg1}, {CORE_CLKSEL_REG_ADDR, &core_clksel}, {RESET_REG_ADDR, &reset}, {CLKMUX_STATUS_REG_ADDR, &clkmux_status}, }) .register_handler(this, &PRCI::register_access_callback); } void register_access_callback(const vp::map::register_access_t &r) { r.fn(); /* TODO: not implemented yet, this is a stub */ } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { router.transport(trans, delay); } }; #endif // RISCV_VP_PRCI_H ================================================ FILE: vp/src/platform/linux32/CMakeLists.txt ================================================ file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) add_executable(linux32-vp linux32_main.cpp ${HEADERS}) target_link_libraries(linux32-vp rv32 platform-common gdb-mc ${Boost_LIBRARIES} systemc pthread) INSTALL(TARGETS linux32-vp RUNTIME DESTINATION bin) ================================================ FILE: vp/src/platform/linux32/linux32_main.cpp ================================================ #include #include #include "core/common/clint.h" #include "elf_loader.h" #include "fu540_plic.h" #include "debug_memory.h" #include "iss.h" #include "mem.h" #include "memory.h" #include "mmu.h" #include "platform/common/slip.h" #include "platform/common/uart.h" #include "prci.h" #include "syscall.h" #include "debug.h" #include "util/options.h" #include "platform/common/options.h" #include "gdb-mc/gdb_server.h" #include "gdb-mc/gdb_runner.h" #include #include #include #include #include #include enum { NUM_CORES = 5, }; using namespace rv32; namespace po = boost::program_options; struct LinuxOptions : public Options { public: typedef unsigned int addr_t; addr_t mem_size = 1024u * 1024u * 1024u; // 1024 MB ram addr_t mem_start_addr = 0x80000000; addr_t mem_end_addr = mem_start_addr + mem_size - 1; addr_t clint_start_addr = 0x02000000; addr_t clint_end_addr = 0x0200ffff; addr_t sys_start_addr = 0x02010000; addr_t sys_end_addr = 0x020103ff; addr_t dtb_rom_start_addr = 0x00001000; addr_t dtb_rom_size = 0x2000; addr_t dtb_rom_end_addr = dtb_rom_start_addr + dtb_rom_size - 1; addr_t uart0_start_addr = 0x10010000; addr_t uart0_end_addr = 0x10010fff; addr_t uart1_start_addr = 0x10011000; addr_t uart1_end_addr = 0x10011fff; addr_t plic_start_addr = 0x0C000000; addr_t plic_end_addr = 0x10000000; addr_t prci_start_addr = 0x10000000; addr_t prci_end_addr = 0x1000FFFF; OptionValue entry_point; std::string dtb_file; std::string tun_device = "tun0"; LinuxOptions(void) { // clang-format off add_options() ("memory-start", po::value(&mem_start_addr),"set memory start address") ("memory-size", po::value(&mem_size), "set memory size") ("entry-point", po::value(&entry_point.option),"set entry point address (ISS program counter)") ("dtb-file", po::value(&dtb_file)->required(), "dtb file for boot loading") ("tun-device", po::value(&tun_device), "tun device used by SLIP"); // clang-format on } void parse(int argc, char **argv) override { Options::parse(argc, argv); entry_point.finalize(parse_ulong_option); mem_end_addr = mem_start_addr + mem_size - 1; } }; class Core { public: ISS iss; MMU mmu; CombinedMemoryInterface memif; InstrMemoryProxy imemif; Core(unsigned int id, MemoryDMI dmi) : iss(id), mmu(iss), memif(("MemoryInterface" + std::to_string(id)).c_str(), iss, &mmu), imemif(dmi, iss) { return; } void init(bool use_data_dmi, bool use_instr_dmi, clint_if *clint, uint64_t entry, uint64_t addr) { if (use_data_dmi) memif.dmi_ranges.emplace_back(imemif.dmi); iss.init(get_instr_memory_if(use_instr_dmi), &memif, clint, entry, addr); } private: instr_memory_if *get_instr_memory_if(bool use_instr_dmi) { if (use_instr_dmi) return &imemif; else return &memif; } }; int sc_main(int argc, char **argv) { LinuxOptions opt; opt.parse(argc, argv); std::srand(std::time(nullptr)); // use current time as seed for random generator tlm::tlm_global_quantum::instance().set(sc_core::sc_time(opt.tlm_global_quantum, sc_core::SC_NS)); SimpleMemory mem("SimpleMemory", opt.mem_size); SimpleMemory dtb_rom("DBT_ROM", opt.dtb_rom_size); ELFLoader loader(opt.input_program.c_str()); SimpleBus bus("SimpleBus"); SyscallHandler sys("SyscallHandler"); FU540_PLIC plic("PLIC", NUM_CORES); CLINT clint("CLINT"); PRCI prci("PRCI"); UART uart0("UART0", 3); SLIP slip("SLIP", 4, opt.tun_device); DebugMemoryInterface dbg_if("DebugMemoryInterface"); MemoryDMI dmi = MemoryDMI::create_start_size_mapping(mem.data, opt.mem_start_addr, mem.size); Core *cores[NUM_CORES]; for (unsigned i = 0; i < NUM_CORES; i++) { cores[i] = new Core(i, dmi); } std::shared_ptr bus_lock = std::make_shared(); for (size_t i = 0; i < NUM_CORES; i++) { cores[i]->memif.bus_lock = bus_lock; cores[i]->mmu.mem = &cores[i]->memif; } uint64_t entry_point = loader.get_entrypoint(); if (opt.entry_point.available) entry_point = opt.entry_point.value; loader.load_executable_image(mem, mem.size, opt.mem_start_addr); sys.init(mem.data, opt.mem_start_addr, loader.get_heap_addr()); for (size_t i = 0; i < NUM_CORES; i++) { cores[i]->init(opt.use_data_dmi, opt.use_instr_dmi, &clint, entry_point, rv64_align_address(opt.mem_end_addr)); sys.register_core(&cores[i]->iss); if (opt.intercept_syscalls) cores[i]->iss.sys = &sys; } // setup port mapping bus.ports[0] = new PortMapping(opt.mem_start_addr, opt.mem_end_addr); bus.ports[1] = new PortMapping(opt.clint_start_addr, opt.clint_end_addr); bus.ports[2] = new PortMapping(opt.sys_start_addr, opt.sys_end_addr); bus.ports[3] = new PortMapping(opt.dtb_rom_start_addr, opt.dtb_rom_end_addr); bus.ports[4] = new PortMapping(opt.uart0_start_addr, opt.uart0_end_addr); bus.ports[5] = new PortMapping(opt.uart1_start_addr, opt.uart1_end_addr); bus.ports[6] = new PortMapping(opt.plic_start_addr, opt.plic_end_addr); bus.ports[7] = new PortMapping(opt.prci_start_addr, opt.prci_end_addr); // connect TLM sockets for (size_t i = 0; i < NUM_CORES; i++) { cores[i]->memif.isock.bind(bus.tsocks[i]); } dbg_if.isock.bind(bus.tsocks[NUM_CORES]); bus.isocks[0].bind(mem.tsock); bus.isocks[1].bind(clint.tsock); bus.isocks[2].bind(sys.tsock); bus.isocks[3].bind(dtb_rom.tsock); bus.isocks[4].bind(uart0.tsock); bus.isocks[5].bind(slip.tsock); bus.isocks[6].bind(plic.tsock); bus.isocks[7].bind(prci.tsock); // connect interrupt signals/communication for (size_t i = 0; i < NUM_CORES; i++) { plic.target_harts[i] = &cores[i]->iss; clint.target_harts[i] = &cores[i]->iss; } uart0.plic = &plic; slip.plic = &plic; for (size_t i = 0; i < NUM_CORES; i++) { // switch for printing instructions cores[i]->iss.trace = opt.trace_mode; // ignore WFI instructions (handle them as a NOP, which is ok according to the RISC-V ISA) to avoid running too // fast ahead with simulation time when the CPU is idle cores[i]->iss.ignore_wfi = true; // emulate RISC-V core boot loader cores[i]->iss.regs[RegFile::a0] = cores[i]->iss.get_hart_id(); cores[i]->iss.regs[RegFile::a1] = opt.dtb_rom_start_addr; // configure supported instructions cores[i]->iss.csrs.misa.fields.extensions |= cores[i]->iss.csrs.misa.M | cores[i]->iss.csrs.misa.A | cores[i]->iss.csrs.misa.F | cores[i]->iss.csrs.misa.D; } // OpenSBI boots all harts except hart 0 by default. // // To prevent this hart from being scheduled when stuck in // the OpenSBI `sbi_hart_hang()` function do not ignore WFI on // this hart. // // See: https://github.com/riscv/opensbi/commit/d70f8aab45d1e449b3b9be26e050b20ed76e12e9 cores[0]->iss.ignore_wfi = false; // load DTB (Device Tree Binary) file dtb_rom.load_binary_file(opt.dtb_file, 0); std::vector mmus; std::vector dharts; if (opt.use_debug_runner) { for (size_t i = 0; i < NUM_CORES; i++) { dharts.push_back(&cores[i]->iss); mmus.push_back(&cores[i]->memif); } auto server = new GDBServer("GDBServer", dharts, &dbg_if, opt.debug_port, mmus); for (size_t i = 0; i < dharts.size(); i++) new GDBServerRunner(("GDBRunner" + std::to_string(i)).c_str(), server, dharts[i]); } else { for (size_t i = 0; i < NUM_CORES; i++) { new DirectCoreRunner(cores[i]->iss); } } sc_core::sc_start(); for (size_t i = 0; i < NUM_CORES; i++) { cores[i]->iss.show(); } return 0; } ================================================ FILE: vp/src/platform/linux32/prci.h ================================================ #ifndef RISCV_VP_PRCI_H #define RISCV_VP_PRCI_H #include #include #include "core/common/irq_if.h" #include "util/tlm_map.h" struct PRCI : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; // memory mapped configuration registers uint32_t hfrosccfg = 0; uint32_t core_pllcfg0 = 0; uint32_t ddr_pllcfg0 = 0; uint32_t core_pllcfg1 = 0; uint32_t gemgxl_pllcfg0 = 0; uint32_t gemgxl_pllcfg1 = 0; uint32_t core_clksel = 0; uint32_t reset = 0; uint32_t clkmux_status = 0; enum { HFROSCCFG_REG_ADDR = 0x0, CORE_PLLCFG0_REG_ADDR = 0x4, DDR_PLLCFG0_REG_ADDR = 0x8, CORE_PLLCFG1_REG_ADDR = 0x10, GEMGXL_PLLCFG0_REG_ADDR = 0x1C, GEMGXL_PLLCFG1_REG_ADDR = 0x20, CORE_CLKSEL_REG_ADDR = 0x24, RESET_REG_ADDR = 0x28, CLKMUX_STATUS_REG_ADDR = 0x2C, }; vp::map::LocalRouter router = {"PRCI"}; PRCI(sc_core::sc_module_name) { tsock.register_b_transport(this, &PRCI::transport); router .add_register_bank({ {HFROSCCFG_REG_ADDR, &hfrosccfg}, {CORE_PLLCFG0_REG_ADDR, &core_pllcfg0}, {DDR_PLLCFG0_REG_ADDR, &ddr_pllcfg0}, {CORE_PLLCFG1_REG_ADDR, &core_pllcfg1}, {GEMGXL_PLLCFG0_REG_ADDR, &gemgxl_pllcfg0}, {GEMGXL_PLLCFG1_REG_ADDR, &gemgxl_pllcfg1}, {CORE_CLKSEL_REG_ADDR, &core_clksel}, {RESET_REG_ADDR, &reset}, {CLKMUX_STATUS_REG_ADDR, &clkmux_status}, }) .register_handler(this, &PRCI::register_access_callback); } void register_access_callback(const vp::map::register_access_t &r) { r.fn(); /* TODO: not implemented yet, this is a stub */ } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { router.transport(trans, delay); } }; #endif // RISCV_VP_PRCI_H ================================================ FILE: vp/src/platform/microrv32/CMakeLists.txt ================================================ file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) add_executable(microrv32-vp ${HEADERS} main.cpp) target_link_libraries(microrv32-vp rv32 platform-common gdb-mc ${Boost_LIBRARIES} systemc pthread) INSTALL(TARGETS microrv32-vp RUNTIME DESTINATION bin) ================================================ FILE: vp/src/platform/microrv32/main.cpp ================================================ #include #include #include "core/common/clint.h" #include "elf_loader.h" #include "debug_memory.h" #include "iss.h" #include "mem.h" #include "memory.h" #include "syscall.h" #include "microrv32_uart.h" #include "microrv32_led.h" #include "microrv32_gpio.h" #include "util/options.h" #include "platform/common/options.h" #include "gdb-mc/gdb_server.h" #include "gdb-mc/gdb_runner.h" #include #include #include #include using namespace rv32; namespace po = boost::program_options; class BasicOptions : public Options { public: typedef unsigned int addr_t; addr_t clint_start_addr = 0x2000000; addr_t clint_end_addr = 0x200ffff; addr_t sys_start_addr = 0x02010000; addr_t sys_end_addr = 0x020103ff; addr_t mem_start_addr = 0x80000000; addr_t mem_end_addr = 0x80ffffff; addr_t led_start_addr = 0x81000000; addr_t led_end_addr = 0x810000ff; addr_t uart_start_addr = 0x82000000; addr_t uart_end_addr = 0x820000ff; addr_t gpio_a_start_addr = 0x83000000; addr_t gpio_a_end_addr = 0x830000ff; addr_t mem_size = mem_end_addr - mem_start_addr; bool use_E_base_isa = false; OptionValue entry_point; BasicOptions(void) { // clang-format off add_options() ("use-E-base-isa", po::bool_switch(&use_E_base_isa), "use the E instead of the I integer base ISA") ("entry-point", po::value(&entry_point.option),"set entry point address (ISS program counter)"); // clang-format on } void parse(int argc, char **argv) override { Options::parse(argc, argv); entry_point.finalize(parse_ulong_option); } }; int sc_main(int argc, char **argv) { BasicOptions opt; opt.parse(argc, argv); std::srand(std::time(nullptr)); // use current time as seed for random generator tlm::tlm_global_quantum::instance().set(sc_core::sc_time(opt.tlm_global_quantum, sc_core::SC_NS)); ISS core(0, opt.use_E_base_isa); SimpleMemory mem("SimpleMemory", opt.mem_size); ELFLoader loader(opt.input_program.c_str()); SimpleBus<2, 6> bus("SimpleBus"); CombinedMemoryInterface iss_mem_if("MemoryInterface", core); SyscallHandler sys("SyscallHandler"); CLINT<1> clint("CLINT"); DebugMemoryInterface dbg_if("DebugMemoryInterface"); MicroRV32UART uart("MicroRV32UART"); MicroRV32LED led("MicroRV32LED"); MicroRV32GPIO gpio_a("MicroRV32GPIO"); MemoryDMI dmi = MemoryDMI::create_start_size_mapping(mem.data, opt.mem_start_addr, mem.size); InstrMemoryProxy instr_mem(dmi, core); std::shared_ptr bus_lock = std::make_shared(); iss_mem_if.bus_lock = bus_lock; instr_memory_if *instr_mem_if = &iss_mem_if; data_memory_if *data_mem_if = &iss_mem_if; if (opt.use_instr_dmi) instr_mem_if = &instr_mem; if (opt.use_data_dmi) { iss_mem_if.dmi_ranges.emplace_back(dmi); } uint64_t entry_point = loader.get_entrypoint(); if (opt.entry_point.available) entry_point = opt.entry_point.value; loader.load_executable_image(mem, mem.size, opt.mem_start_addr); core.init(instr_mem_if, data_mem_if, &clint, entry_point, rv32_align_address(opt.mem_end_addr)); sys.init(mem.data, opt.mem_start_addr, loader.get_heap_addr()); sys.register_core(&core); if (opt.intercept_syscalls) core.sys = &sys; // address mapping bus.ports[0] = new PortMapping(opt.mem_start_addr, opt.mem_end_addr); bus.ports[1] = new PortMapping(opt.clint_start_addr, opt.clint_end_addr); bus.ports[2] = new PortMapping(opt.uart_start_addr, opt.uart_end_addr); bus.ports[3] = new PortMapping(opt.sys_start_addr, opt.sys_end_addr); bus.ports[4] = new PortMapping(opt.led_start_addr, opt.led_end_addr); bus.ports[5] = new PortMapping(opt.gpio_a_start_addr, opt.gpio_a_end_addr); // connect TLM sockets iss_mem_if.isock.bind(bus.tsocks[0]); dbg_if.isock.bind(bus.tsocks[1]); bus.isocks[0].bind(mem.tsock); bus.isocks[1].bind(clint.tsock); bus.isocks[2].bind(uart.tsock); bus.isocks[3].bind(sys.tsock); bus.isocks[4].bind(led.tsock); bus.isocks[5].bind(gpio_a.tsock); // connect interrupt signals/communication clint.target_harts[0] = &core; std::vector threads; threads.push_back(&core); core.trace = opt.trace_mode; // switch for printing instructions if (opt.use_debug_runner) { auto server = new GDBServer("GDBServer", threads, &dbg_if, opt.debug_port); new GDBServerRunner("GDBRunner", server, &core); } else { new DirectCoreRunner(core); } sc_core::sc_start(); core.show(); return 0; } ================================================ FILE: vp/src/platform/microrv32/microrv32_gpio.h ================================================ #pragma once #include #include #include #include struct MicroRV32GPIO : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; sc_core::sc_event run_event; // each bit represents a pin in each register uint8_t direction = 0; // direction of pins, 0: input (read pin), 1: output (write pin) uint8_t input = 0; // incomming, read pin values uint8_t output = 0; // outgoing pin values SC_HAS_PROCESS(MicroRV32GPIO); MicroRV32GPIO(sc_core::sc_module_name) { tsock.register_b_transport(this, &MicroRV32GPIO::transport); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { auto addr = trans.get_address(); auto cmd = trans.get_command(); // auto len = trans.get_data_length(); auto ptr = trans.get_data_ptr(); if (cmd == tlm::TLM_WRITE_COMMAND) { if (addr == 0) { direction = *ptr; // printf("\n[TLM] GPIO direction write: %X\n", *ptr); } else if (addr == 4) { output = *ptr; // printf("\n[TLM] GPIO output write: %X\n", *ptr); } } else if (cmd == tlm::TLM_READ_COMMAND) { if (addr == 0) { *((uint32_t*)ptr) = direction; } else if (addr == 4) { *((uint32_t*)ptr) = output; } else if (addr == 8) { *((uint32_t*)ptr) = input; } } (void)delay; // zero delay } /* * TODO for future : generate data for GPIO input register * a) generate random data * b) read file with timestamp and value for input register * c) accept values for input register from socket/outside vp */ }; ================================================ FILE: vp/src/platform/microrv32/microrv32_led.h ================================================ #pragma once #include #include #include #include struct MicroRV32LED : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; sc_core::sc_event run_event; uint8_t led_vals = 0; SC_HAS_PROCESS(MicroRV32LED); MicroRV32LED(sc_core::sc_module_name) { tsock.register_b_transport(this, &MicroRV32LED::transport); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { auto addr = trans.get_address(); auto cmd = trans.get_command(); // auto len = trans.get_data_length(); auto ptr = trans.get_data_ptr(); if (cmd == tlm::TLM_WRITE_COMMAND) { if (addr == 0) { led_vals = *ptr; // printf("\n[TLM] LED write : %X \n", *ptr); } } else if (cmd == tlm::TLM_READ_COMMAND) { if (addr == 0) { *((uint32_t*)ptr) = led_vals; } } (void)delay; // zero delay } }; ================================================ FILE: vp/src/platform/microrv32/microrv32_uart.h ================================================ #pragma once #include #include #include #include #include #include struct MicroRV32UART : public sc_core::sc_module { tlm_utils::simple_target_socket tsock; sc_core::sc_event run_event; // tx char buf = 0; // rx std::queue rxFifo; uint8_t rxFifoDepth = 16; SC_HAS_PROCESS(MicroRV32UART); MicroRV32UART(sc_core::sc_module_name) { tsock.register_b_transport(this, &MicroRV32UART::transport); SC_THREAD(run); } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { auto addr = trans.get_address(); auto cmd = trans.get_command(); // auto len = trans.get_data_length(); auto ptr = trans.get_data_ptr(); if (cmd == tlm::TLM_WRITE_COMMAND) { if (addr == 0) { buf = *ptr; } else if (addr == 4) { std::cout << buf; } } else if (cmd == tlm::TLM_READ_COMMAND) { if (addr == 0) { // ignore } else if (addr == 4) { *((uint32_t *)ptr) = 1; } else if (addr == 8) { if (rxFifo.size() > 0) { *((uint32_t *)ptr) = rxFifo.front(); // printf("\n[TLM] UART, transport, read RX: %2X\n", rxFifo.front()); // std::cout << std::endl << "[TLM] uart transport RX: " << std::hex << // static_cast(rxFifo.front()) << std::endl; rxFifo.pop(); } } else if (addr == 12) { *((uint32_t *)ptr) = rxFifo.size(); } else if (addr == 16) { *((uint32_t *)ptr) = rxFifo.size() == 1; } } // std::cout << "sc_time: " << sc_core::sc_time_stamp() << std::endl; // (void)delay; // zero delay // wait(sc_core::sc_time(50, sc_core::SC_NS)); delay += sc_core::sc_time(50, sc_core::SC_NS); } // untested void run() { while (true) { // 9600 baud ~= 1ms, 115200 ~= 87us // run_event.notify(sc_core::sc_time(1, sc_core::SC_MS)); run_event.notify(sc_core::sc_time(87, sc_core::SC_US)); sc_core::wait(run_event); // 40 times per second by default unsigned char newRXChar = (rand() %('z'-'A')) + 'A'; if (rxFifo.size() <= rxFifoDepth) { rxFifo.push(newRXChar); // printf("\n[TLM] UART, run: %X\n", newRXChar); // std::cout << std::endl << "[TLM] uart run: " << std::hex << (newRXChar & 0xff) << std::endl; } } } }; ================================================ FILE: vp/src/platform/test32/CMakeLists.txt ================================================ file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) add_executable(test32-vp test32_main.cpp ${HEADERS}) target_link_libraries(test32-vp rv32 platform-common gdb-mc ${Boost_LIBRARIES} systemc pthread) INSTALL(TARGETS test32-vp RUNTIME DESTINATION bin) ================================================ FILE: vp/src/platform/test32/htif.h ================================================ #pragma once #include struct HTIF : public sc_core::sc_module { uint64_t *to_host; uint64_t *num_instr; uint64_t max_instrs; std::function to_host_callback; SC_HAS_PROCESS(HTIF); HTIF(sc_core::sc_module_name, uint64_t *to_host, uint64_t *num_instr, uint64_t max_instrs, std::function to_host_callback) { this->to_host = to_host; this->num_instr = num_instr; this->max_instrs = max_instrs; this->to_host_callback = to_host_callback; SC_THREAD(run); } void run() { while (true) { sc_core::wait(10, sc_core::SC_US); auto x = *to_host; to_host_callback(x); x = *num_instr; if (x >= max_instrs) throw std::runtime_error("reached >= max #instrs: " + std::to_string(x)); } } }; ================================================ FILE: vp/src/platform/test32/test32_main.cpp ================================================ #include #include #include "core/common/clint.h" #include "elf_loader.h" #include "debug_memory.h" #include "iss.h" #include "mem.h" #include "memory.h" #include "syscall.h" #include "platform/common/options.h" #include "gdb-mc/gdb_server.h" #include "gdb-mc/gdb_runner.h" #include "htif.h" #include #include #include #include #include using namespace rv32; namespace po = boost::program_options; class TestOptions : public Options { public: typedef unsigned int addr_t; std::string test_signature; std::string isa; unsigned int max_test_instrs = 1000000; addr_t mem_size = 1024 * 1024 * 32; // 32 MB ram, to place it before the CLINT and run the base examples (assume // memory start at zero) without modifications addr_t mem_start_addr = 0x00000000; addr_t mem_end_addr = mem_start_addr + mem_size - 1; addr_t clint_start_addr = 0x02000000; addr_t clint_end_addr = 0x0200ffff; addr_t sys_start_addr = 0x02010000; addr_t sys_end_addr = 0x020103ff; bool use_E_base_isa = false; TestOptions(void) { // clang-format off add_options() ("memory-start", po::value(&mem_start_addr),"set memory start address") ("memory-size", po::value(&mem_size), "set memory size") ("use-E-base-isa", po::bool_switch(&use_E_base_isa), "use the E instead of the I integer base ISA") ("max-instrs", po::value(&max_test_instrs), "maximum number of instructions to execute (soft limit, checked periodically)") ("signature", po::value(&test_signature)->default_value(""), "output filename for the test execution signature") ("isa", po::value(&isa)->default_value("imacfnus"), "output filename for the test execution signature"); // clang-format on } void parse(int argc, char **argv) override { Options::parse(argc, argv); mem_end_addr = mem_start_addr + mem_size - 1; } }; void dump_test_signature(TestOptions &opt, uint8_t *mem, ELFLoader &loader) { auto begin_sig = loader.get_begin_signature_address(); auto end_sig = loader.get_end_signature_address(); { boost::io::ios_flags_saver ifs(std::cout); std::cout << std::hex; std::cout << "begin_signature: " << begin_sig << std::endl; std::cout << "end_signature: " << end_sig << std::endl; std::cout << "signature output file: " << opt.test_signature << std::endl; } assert (end_sig >= begin_sig); assert (begin_sig >= opt.mem_start_addr); auto begin = begin_sig - opt.mem_start_addr; auto end = end_sig - opt.mem_start_addr; std::ofstream sigfile(opt.test_signature, std::ios::out); auto n = begin; assert (n % 4 == 0); while (n < end) { uint32_t *p = ((uint32_t*)&mem[n]); assert ((uintptr_t)p % 4 == 0); sigfile << std::hex << std::setw(8) << std::setfill('0') << *p << std::endl; n += 4; } } int sc_main(int argc, char **argv) { TestOptions opt; opt.parse(argc, argv); std::srand(std::time(nullptr)); // use current time as seed for random generator tlm::tlm_global_quantum::instance().set(sc_core::sc_time(opt.tlm_global_quantum, sc_core::SC_NS)); ISS core(0, opt.use_E_base_isa); MMU mmu(core); CombinedMemoryInterface core_mem_if("MemoryInterface0", core, &mmu); SimpleMemory mem("SimpleMemory", opt.mem_size); ELFLoader loader(opt.input_program.c_str()); SimpleBus<2, 3> bus("SimpleBus"); SyscallHandler sys("SyscallHandler"); CLINT<1> clint("CLINT"); DebugMemoryInterface dbg_if("DebugMemoryInterface"); MemoryDMI dmi = MemoryDMI::create_start_size_mapping(mem.data, opt.mem_start_addr, mem.size); InstrMemoryProxy instr_mem(dmi, core); std::shared_ptr bus_lock = std::make_shared(); core_mem_if.bus_lock = bus_lock; instr_memory_if *instr_mem_if = &core_mem_if; data_memory_if *data_mem_if = &core_mem_if; if (opt.use_instr_dmi) instr_mem_if = &instr_mem; if (opt.use_data_dmi) { core_mem_if.dmi_ranges.emplace_back(dmi); } loader.load_executable_image(mem, mem.size, opt.mem_start_addr); core.init(instr_mem_if, data_mem_if, &clint, loader.get_entrypoint(), rv32_align_address(opt.mem_end_addr)); sys.init(mem.data, opt.mem_start_addr, loader.get_heap_addr()); sys.register_core(&core); if (opt.intercept_syscalls) core.sys = &sys; // setup port mapping bus.ports[0] = new PortMapping(opt.mem_start_addr, opt.mem_end_addr); bus.ports[1] = new PortMapping(opt.clint_start_addr, opt.clint_end_addr); bus.ports[2] = new PortMapping(opt.sys_start_addr, opt.sys_end_addr); // connect TLM sockets core_mem_if.isock.bind(bus.tsocks[0]); dbg_if.isock.bind(bus.tsocks[1]); bus.isocks[0].bind(mem.tsock); bus.isocks[1].bind(clint.tsock); bus.isocks[2].bind(sys.tsock); // connect interrupt signals/communication clint.target_harts[0] = &core; // switch for printing instructions core.trace = opt.trace_mode; std::vector threads; threads.push_back(&core); if (opt.use_debug_runner) { auto server = new GDBServer("GDBServer", threads, &dbg_if, opt.debug_port); new GDBServerRunner("GDBRunner", server, &core); } else { new DirectCoreRunner(core); } { auto addr = loader.get_to_host_address(); uint8_t *p = &(mem.data[addr - opt.mem_start_addr]); assert (((uintptr_t)p) % 8 == 0); // correct alignment for uint64_t auto to_host_callback = [&core](uint64_t x) { if (x == 1) { //NOTE: the "scall" benchmark (RISC-V compliance) still requires HTIF support for successful completion ... core.sys_exit(); } else { if (x != 0) { std::cout << "to-host: " << std::to_string(x) << std::endl; core.sys_exit(); } //throw std::runtime_error("to-host: " + std::to_string(x)); } }; new HTIF("HTIF", (uint64_t*)p, &core.total_num_instr, opt.max_test_instrs, to_host_callback); } { std::transform(opt.isa.begin(), opt.isa.end(), opt.isa.begin(), ::toupper); core.csrs.misa.fields.extensions = core.csrs.misa.I; if (opt.isa.find('G') != std::string::npos) core.csrs.misa.fields.extensions |= core.csrs.misa.M | core.csrs.misa.A | core.csrs.misa.F | core.csrs.misa.D; if (opt.isa.find('M') != std::string::npos) core.csrs.misa.fields.extensions |= core.csrs.misa.M; if (opt.isa.find('A') != std::string::npos) core.csrs.misa.fields.extensions |= core.csrs.misa.A; if (opt.isa.find('C') != std::string::npos) core.csrs.misa.fields.extensions |= core.csrs.misa.C; if (opt.isa.find('F') != std::string::npos) core.csrs.misa.fields.extensions |= core.csrs.misa.F; if (opt.isa.find('D') != std::string::npos) core.csrs.misa.fields.extensions |= core.csrs.misa.D; if (opt.isa.find('N') != std::string::npos) core.csrs.misa.fields.extensions |= core.csrs.misa.N; if (opt.isa.find('U') != std::string::npos) core.csrs.misa.fields.extensions |= core.csrs.misa.U; if (opt.isa.find('S') != std::string::npos) core.csrs.misa.fields.extensions |= core.csrs.misa.S | core.csrs.misa.U; // NOTE: S mode implies U mode } sc_core::sc_start(); core.show(); if (!opt.test_signature.empty()) { dump_test_signature(opt, mem.data, loader); } return 0; } ================================================ FILE: vp/src/platform/tiny32/CMakeLists.txt ================================================ file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) add_executable(tiny32-vp tiny32_main.cpp ${HEADERS}) target_link_libraries(tiny32-vp rv32 platform-common gdb-mc ${Boost_LIBRARIES} systemc pthread) INSTALL(TARGETS tiny32-vp RUNTIME DESTINATION bin) ================================================ FILE: vp/src/platform/tiny32/tiny32_main.cpp ================================================ #include #include #include "core/common/real_clint.h" #include "elf_loader.h" #include "debug_memory.h" #include "iss.h" #include "mem.h" #include "memory.h" #include "syscall.h" #include "platform/common/options.h" #include "gdb-mc/gdb_server.h" #include "gdb-mc/gdb_runner.h" #include #include #include #include using namespace rv32; namespace po = boost::program_options; struct TinyOptions : public Options { public: typedef unsigned int addr_t; addr_t mem_size = 1024 * 1024 * 32; // 32 MB ram, to place it before the CLINT and run the base examples (assume // memory start at zero) without modifications addr_t mem_start_addr = 0x00000000; addr_t mem_end_addr = mem_start_addr + mem_size - 1; addr_t clint_start_addr = 0x02000000; addr_t clint_end_addr = 0x0200ffff; addr_t sys_start_addr = 0x02010000; addr_t sys_end_addr = 0x020103ff; bool quiet = false; bool use_E_base_isa = false; TinyOptions(void) { // clang-format off add_options() ("quiet", po::bool_switch(&quiet), "do not output register values on exit") ("memory-start", po::value(&mem_start_addr), "set memory start address") ("memory-size", po::value(&mem_size), "set memory size") ("use-E-base-isa", po::bool_switch(&use_E_base_isa), "use the E instead of the I integer base ISA"); // clang-format on } void parse(int argc, char **argv) override { Options::parse(argc, argv); mem_end_addr = mem_start_addr + mem_size - 1; } }; int sc_main(int argc, char **argv) { TinyOptions opt; opt.parse(argc, argv); std::srand(std::time(nullptr)); // use current time as seed for random generator tlm::tlm_global_quantum::instance().set(sc_core::sc_time(opt.tlm_global_quantum, sc_core::SC_NS)); ISS core(0, opt.use_E_base_isa); MMU mmu(core); CombinedMemoryInterface core_mem_if("MemoryInterface0", core, &mmu); SimpleMemory mem("SimpleMemory", opt.mem_size); ELFLoader loader(opt.input_program.c_str()); SimpleBus<2, 3> bus("SimpleBus"); SyscallHandler sys("SyscallHandler"); DebugMemoryInterface dbg_if("DebugMemoryInterface"); std::vector clint_targets {&core}; RealCLINT clint("CLINT", clint_targets); MemoryDMI dmi = MemoryDMI::create_start_size_mapping(mem.data, opt.mem_start_addr, mem.size); InstrMemoryProxy instr_mem(dmi, core); std::shared_ptr bus_lock = std::make_shared(); core_mem_if.bus_lock = bus_lock; instr_memory_if *instr_mem_if = &core_mem_if; data_memory_if *data_mem_if = &core_mem_if; if (opt.use_instr_dmi) instr_mem_if = &instr_mem; if (opt.use_data_dmi) { core_mem_if.dmi_ranges.emplace_back(dmi); } loader.load_executable_image(mem, mem.size, opt.mem_start_addr); core.init(instr_mem_if, data_mem_if, &clint, loader.get_entrypoint(), rv32_align_address(opt.mem_end_addr)); sys.init(mem.data, opt.mem_start_addr, loader.get_heap_addr()); sys.register_core(&core); if (opt.intercept_syscalls) core.sys = &sys; core.error_on_zero_traphandler = opt.error_on_zero_traphandler; // setup port mapping bus.ports[0] = new PortMapping(opt.mem_start_addr, opt.mem_end_addr); bus.ports[1] = new PortMapping(opt.clint_start_addr, opt.clint_end_addr); bus.ports[2] = new PortMapping(opt.sys_start_addr, opt.sys_end_addr); // connect TLM sockets core_mem_if.isock.bind(bus.tsocks[0]); dbg_if.isock.bind(bus.tsocks[1]); bus.isocks[0].bind(mem.tsock); bus.isocks[1].bind(clint.tsock); bus.isocks[2].bind(sys.tsock); // switch for printing instructions core.trace = opt.trace_mode; std::vector threads; threads.push_back(&core); if (opt.use_debug_runner) { auto server = new GDBServer("GDBServer", threads, &dbg_if, opt.debug_port); new GDBServerRunner("GDBRunner", server, &core); } else { new DirectCoreRunner(core); } if (opt.quiet) sc_core::sc_report_handler::set_verbosity_level(sc_core::SC_NONE); sc_core::sc_start(); if (!opt.quiet) { core.show(); } return 0; } ================================================ FILE: vp/src/platform/tiny32-mc/CMakeLists.txt ================================================ file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) add_executable(tiny32-mc mc_main.cpp ${HEADERS}) target_link_libraries(tiny32-mc rv32 platform-common gdb-mc ${Boost_LIBRARIES} systemc pthread) INSTALL(TARGETS tiny32-mc RUNTIME DESTINATION bin) ================================================ FILE: vp/src/platform/tiny32-mc/mc_main.cpp ================================================ #include #include #include "core/common/clint.h" #include "elf_loader.h" #include "iss.h" #include "mem.h" #include "memory.h" #include "syscall.h" #include "platform/common/options.h" #include "gdb-mc/gdb_server.h" #include "gdb-mc/gdb_runner.h" #include #include #include #include using namespace rv32; namespace po = boost::program_options; struct TinyOptions : public Options { public: typedef unsigned int addr_t; addr_t mem_size = 1024 * 1024 * 32; // 32 MB ram, to place it before the CLINT and run the base examples (assume // memory start at zero) without modifications addr_t mem_start_addr = 0x00000000; addr_t mem_end_addr = mem_start_addr + mem_size - 1; addr_t clint_start_addr = 0x02000000; addr_t clint_end_addr = 0x0200ffff; addr_t sys_start_addr = 0x02010000; addr_t sys_end_addr = 0x020103ff; bool quiet = false; bool use_E_base_isa = false; TinyOptions(void) { // clang-format off add_options() ("quiet", po::bool_switch(&quiet), "do not output register values on exit") ("memory-start", po::value(&mem_start_addr), "set memory start address") ("memory-size", po::value(&mem_size), "set memory size") ("use-E-base-isa", po::bool_switch(&use_E_base_isa), "use the E instead of the I integer base ISA"); // clang-format on } void parse(int argc, char **argv) override { Options::parse(argc, argv); mem_end_addr = mem_start_addr + mem_size - 1; } }; int sc_main(int argc, char **argv) { TinyOptions opt; opt.parse(argc, argv); std::srand(std::time(nullptr)); // use current time as seed for random generator tlm::tlm_global_quantum::instance().set(sc_core::sc_time(opt.tlm_global_quantum, sc_core::SC_NS)); ISS core0(0); ISS core1(1); CombinedMemoryInterface core0_mem_if("MemoryInterface0", core0); CombinedMemoryInterface core1_mem_if("MemoryInterface1", core1); SimpleMemory mem("SimpleMemory", opt.mem_size); ELFLoader loader(opt.input_program.c_str()); SimpleBus<3, 3> bus("SimpleBus"); SyscallHandler sys("SyscallHandler"); CLINT<2> clint("CLINT"); DebugMemoryInterface dbg_if("DebugMemoryInterface"); std::shared_ptr bus_lock = std::make_shared(); core0_mem_if.bus_lock = bus_lock; core1_mem_if.bus_lock = bus_lock; bus.ports[0] = new PortMapping(opt.mem_start_addr, opt.mem_end_addr); bus.ports[1] = new PortMapping(opt.clint_start_addr, opt.clint_end_addr); bus.ports[2] = new PortMapping(opt.sys_start_addr, opt.sys_end_addr); loader.load_executable_image(mem, mem.size, opt.mem_start_addr); core0.init(&core0_mem_if, &core0_mem_if, &clint, loader.get_entrypoint(), opt.mem_end_addr - 3); // -3 to not overlap with the next region and stay 32 bit aligned core1.init(&core1_mem_if, &core1_mem_if, &clint, loader.get_entrypoint(), opt.mem_end_addr - 32767); sys.init(mem.data, opt.mem_start_addr, loader.get_heap_addr()); sys.register_core(&core0); sys.register_core(&core1); if (opt.intercept_syscalls) { core0.sys = &sys; core1.sys = &sys; } core0.error_on_zero_traphandler = opt.error_on_zero_traphandler; core1.error_on_zero_traphandler = opt.error_on_zero_traphandler; // connect TLM sockets core0_mem_if.isock.bind(bus.tsocks[0]); core1_mem_if.isock.bind(bus.tsocks[1]); dbg_if.isock.bind(bus.tsocks[2]); bus.isocks[0].bind(mem.tsock); bus.isocks[1].bind(clint.tsock); bus.isocks[2].bind(sys.tsock); // connect interrupt signals/communication clint.target_harts[0] = &core0; clint.target_harts[1] = &core1; // switch for printing instructions core0.trace = opt.trace_mode; core1.trace = opt.trace_mode; std::vector threads; threads.push_back(&core0); threads.push_back(&core1); if (opt.use_debug_runner) { auto server = new GDBServer("GDBServer", threads, &dbg_if, opt.debug_port); new GDBServerRunner("GDBRunner0", server, &core0); new GDBServerRunner("GDBRunner1", server, &core1); } else { new DirectCoreRunner(core0); new DirectCoreRunner(core1); } if (opt.quiet) sc_core::sc_report_handler::set_verbosity_level(sc_core::SC_NONE); sc_core::sc_start(); if (!opt.quiet) { core0.show(); core1.show(); } return 0; } ================================================ FILE: vp/src/platform/tiny64/CMakeLists.txt ================================================ file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) add_executable(tiny64-vp tiny64_main.cpp ${HEADERS}) target_link_libraries(tiny64-vp rv64 platform-common gdb-mc ${Boost_LIBRARIES} systemc pthread) INSTALL(TARGETS tiny64-vp RUNTIME DESTINATION bin) ================================================ FILE: vp/src/platform/tiny64/tiny64_main.cpp ================================================ #include #include #include "core/common/real_clint.h" #include "elf_loader.h" #include "debug_memory.h" #include "iss.h" #include "mem.h" #include "memory.h" #include "mmu.h" #include "syscall.h" #include "platform/common/options.h" #include "gdb-mc/gdb_server.h" #include "gdb-mc/gdb_runner.h" #include #include #include #include using namespace rv64; namespace po = boost::program_options; struct TinyOptions : public Options { public: typedef unsigned int addr_t; addr_t mem_size = 1024 * 1024 * 32; // 32 MB ram, to place it before the CLINT and run the base examples (assume // memory start at zero) without modifications addr_t mem_start_addr = 0x00000000; addr_t mem_end_addr = mem_start_addr + mem_size - 1; addr_t clint_start_addr = 0x02000000; addr_t clint_end_addr = 0x0200ffff; addr_t sys_start_addr = 0x02010000; addr_t sys_end_addr = 0x020103ff; bool quiet = false; bool use_E_base_isa = false; TinyOptions(void) { // clang-format off add_options() ("quiet", po::bool_switch(&quiet), "do not output register values on exit") ("memory-start", po::value(&mem_start_addr), "set memory start address") ("memory-size", po::value(&mem_size), "set memory size") ("use-E-base-isa", po::bool_switch(&use_E_base_isa), "use the E instead of the I integer base ISA"); // clang-format on } void parse(int argc, char **argv) override { Options::parse(argc, argv); mem_end_addr = mem_start_addr + mem_size - 1; } }; int sc_main(int argc, char **argv) { TinyOptions opt; opt.parse(argc, argv); std::srand(std::time(nullptr)); // use current time as seed for random generator tlm::tlm_global_quantum::instance().set(sc_core::sc_time(opt.tlm_global_quantum, sc_core::SC_NS)); ISS core(0); MMU mmu(core); CombinedMemoryInterface core_mem_if("MemoryInterface0", core, mmu); SimpleMemory mem("SimpleMemory", opt.mem_size); ELFLoader loader(opt.input_program.c_str()); SimpleBus<2, 3> bus("SimpleBus"); SyscallHandler sys("SyscallHandler"); DebugMemoryInterface dbg_if("DebugMemoryInterface"); std::vector clint_targets {&core}; RealCLINT clint("CLINT", clint_targets); MemoryDMI dmi = MemoryDMI::create_start_size_mapping(mem.data, opt.mem_start_addr, mem.size); InstrMemoryProxy instr_mem(dmi, core); std::shared_ptr bus_lock = std::make_shared(); core_mem_if.bus_lock = bus_lock; mmu.mem = &core_mem_if; instr_memory_if *instr_mem_if = &core_mem_if; data_memory_if *data_mem_if = &core_mem_if; if (opt.use_instr_dmi) instr_mem_if = &instr_mem; if (opt.use_data_dmi) { core_mem_if.dmi_ranges.emplace_back(dmi); } loader.load_executable_image(mem, mem.size, opt.mem_start_addr); core.init(instr_mem_if, data_mem_if, &clint, loader.get_entrypoint(), rv64_align_address(opt.mem_end_addr)); sys.init(mem.data, opt.mem_start_addr, loader.get_heap_addr()); sys.register_core(&core); if (opt.intercept_syscalls) core.sys = &sys; // setup port mapping bus.ports[0] = new PortMapping(opt.mem_start_addr, opt.mem_end_addr); bus.ports[1] = new PortMapping(opt.clint_start_addr, opt.clint_end_addr); bus.ports[2] = new PortMapping(opt.sys_start_addr, opt.sys_end_addr); // connect TLM sockets core_mem_if.isock.bind(bus.tsocks[0]); dbg_if.isock.bind(bus.tsocks[1]); bus.isocks[0].bind(mem.tsock); bus.isocks[1].bind(clint.tsock); bus.isocks[2].bind(sys.tsock); // switch for printing instructions core.trace = opt.trace_mode; std::vector threads; threads.push_back(&core); if (opt.use_debug_runner) { auto server = new GDBServer("GDBServer", threads, &dbg_if, opt.debug_port); new GDBServerRunner("GDBRunner", server, &core); } else { new DirectCoreRunner(core); } if (opt.quiet) sc_core::sc_report_handler::set_verbosity_level(sc_core::SC_NONE); sc_core::sc_start(); if (!opt.quiet) { core.show(); } return 0; } ================================================ FILE: vp/src/platform/tiny64-mc/CMakeLists.txt ================================================ file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) add_executable(tiny64-mc mc_main.cpp ${HEADERS}) target_link_libraries(tiny64-mc rv64 platform-common gdb-mc ${Boost_LIBRARIES} systemc pthread) INSTALL(TARGETS tiny64-mc RUNTIME DESTINATION bin) ================================================ FILE: vp/src/platform/tiny64-mc/mc_main.cpp ================================================ #include #include #include "core/common/clint.h" #include "elf_loader.h" #include "iss.h" #include "mem.h" #include "memory.h" #include "syscall.h" #include "platform/common/options.h" #include "gdb-mc/gdb_server.h" #include "gdb-mc/gdb_runner.h" #include #include #include #include using namespace rv64; namespace po = boost::program_options; struct TinyOptions : public Options { public: typedef unsigned int addr_t; addr_t mem_size = 1024 * 1024 * 32; // 32 MB ram, to place it before the CLINT and run the base examples (assume // memory start at zero) without modifications addr_t mem_start_addr = 0x00000000; addr_t mem_end_addr = mem_start_addr + mem_size - 1; addr_t clint_start_addr = 0x02000000; addr_t clint_end_addr = 0x0200ffff; addr_t sys_start_addr = 0x02010000; addr_t sys_end_addr = 0x020103ff; bool quiet = false; bool use_E_base_isa = false; TinyOptions(void) { // clang-format off add_options() ("quiet", po::bool_switch(&quiet), "do not output register values on exit") ("memory-start", po::value(&mem_start_addr), "set memory start address") ("memory-size", po::value(&mem_size), "set memory size") ("use-E-base-isa", po::bool_switch(&use_E_base_isa), "use the E instead of the I integer base ISA"); // clang-format on } void parse(int argc, char **argv) override { Options::parse(argc, argv); mem_end_addr = mem_start_addr + mem_size - 1; } }; int sc_main(int argc, char **argv) { TinyOptions opt; opt.parse(argc, argv); std::srand(std::time(nullptr)); // use current time as seed for random generator tlm::tlm_global_quantum::instance().set(sc_core::sc_time(opt.tlm_global_quantum, sc_core::SC_NS)); ISS core0(0); MMU mmu0(core0); ISS core1(1); MMU mmu1(core1); CombinedMemoryInterface core0_mem_if("MemoryInterface0", core0, mmu0); CombinedMemoryInterface core1_mem_if("MemoryInterface1", core1, mmu1); SimpleMemory mem("SimpleMemory", opt.mem_size); ELFLoader loader(opt.input_program.c_str()); SimpleBus<3, 3> bus("SimpleBus"); SyscallHandler sys("SyscallHandler"); CLINT<2> clint("CLINT"); DebugMemoryInterface dbg_if("DebugMemoryInterface"); std::shared_ptr bus_lock = std::make_shared(); core0_mem_if.bus_lock = bus_lock; core1_mem_if.bus_lock = bus_lock; bus.ports[0] = new PortMapping(opt.mem_start_addr, opt.mem_end_addr); bus.ports[1] = new PortMapping(opt.clint_start_addr, opt.clint_end_addr); bus.ports[2] = new PortMapping(opt.sys_start_addr, opt.sys_end_addr); loader.load_executable_image(mem, mem.size, opt.mem_start_addr); core0.init(&core0_mem_if, &core0_mem_if, &clint, loader.get_entrypoint(), opt.mem_end_addr - 3); // -3 to not overlap with the next region and stay 32 bit aligned core1.init(&core1_mem_if, &core1_mem_if, &clint, loader.get_entrypoint(), opt.mem_end_addr - 32767); sys.init(mem.data, opt.mem_start_addr, loader.get_heap_addr()); sys.register_core(&core0); sys.register_core(&core1); if (opt.intercept_syscalls) { core0.sys = &sys; core1.sys = &sys; } // connect TLM sockets core0_mem_if.isock.bind(bus.tsocks[0]); core1_mem_if.isock.bind(bus.tsocks[1]); dbg_if.isock.bind(bus.tsocks[2]); bus.isocks[0].bind(mem.tsock); bus.isocks[1].bind(clint.tsock); bus.isocks[2].bind(sys.tsock); // connect interrupt signals/communication clint.target_harts[0] = &core0; clint.target_harts[1] = &core1; // switch for printing instructions core0.trace = opt.trace_mode; core1.trace = opt.trace_mode; std::vector threads; threads.push_back(&core0); threads.push_back(&core1); if (opt.use_debug_runner) { auto server = new GDBServer("GDBServer", threads, &dbg_if, opt.debug_port); new GDBServerRunner("GDBRunner0", server, &core0); new GDBServerRunner("GDBRunner1", server, &core1); } else { new DirectCoreRunner(core0); new DirectCoreRunner(core1); } if (opt.quiet) sc_core::sc_report_handler::set_verbosity_level(sc_core::SC_NONE); sc_core::sc_start(); if (!opt.quiet) { core0.show(); core1.show(); } return 0; } ================================================ FILE: vp/src/util/common.h ================================================ #pragma once #include #define likely(x) __builtin_expect((x), 1) #define unlikely(x) __builtin_expect((x), 0) #define UNUSED(x) (void)(x) inline void ensure(bool cond) { if (unlikely(!cond)) throw std::runtime_error("runtime assertion failed"); } inline void ensure(bool cond, const std::string &reason) { if (unlikely(!cond)) throw std::runtime_error(reason); } inline uint64_t rv64_align_address(uint64_t addr) { return addr - addr % 8; } inline uint32_t rv32_align_address(uint32_t addr) { return addr - addr % 4; } /* Allow to provide a custom function name for a SystemC thread to avoid duplicate name warning in case the same * SystemC module is instantiated multiple times. */ #define SC_NAMED_THREAD(func, name) declare_thread_process(func##_handle, name, SC_CURRENT_USER_MODULE, func) ================================================ FILE: vp/src/util/elegantEnums.cpp ================================================ /* * elegantEnums.hpp * * Created on: 14 Mar 2019 * Author: dwd */ #include "elegantEnums.hpp" std::vector splitString(std::string str, char sep) { std::vector vecString; std::string item; std::stringstream stringStream(str); while (std::getline(stringStream, item, sep)) { vecString.push_back(item); } return vecString; } ================================================ FILE: vp/src/util/elegantEnums.hpp ================================================ /* * elegantEnums.hpp * * Created on: 14 Mar 2019 * Author: dwd */ #pragma once #include #include #include #include #include #include #define STRING_REMOVE_CHAR(str, ch) str.erase(std::remove(str.begin(), str.end(), ch), str.end()) std::vector splitString(std::string str, char sep = ','); #define DECLARE_ENUM_WITH_TYPE(E, T, ...) \ enum class E : T { __VA_ARGS__ }; \ typedef T E##_underlying_type; \ static std::map E##MapName(generateEnumMap(#__VA_ARGS__)); \ std::ostream &operator<<(std::ostream &os, E enumTmp); \ size_t operator*(E enumTmp); \ std::string operator~(E enumTmp); \ std::string operator+(std::string &&str, E enumTmp); \ std::string operator+(E enumTmp, std::string &&str); \ std::string &operator+=(std::string &str, E enumTmp); \ E operator++(E &enumTmp); \ bool valid##E(T value); \ bool operator==(E left, E right); \ template \ bool operator<(E left, Other right) { \ return static_cast(left) < right; \ } #define DECLARE_ENUM(E, ...) DECLARE_ENUM_WITH_TYPE(E, uint16_t, __VA_ARGS__) #define IMPL_ENUM_WITH_TYPE(E, T) \ std::ostream &operator<<(std::ostream &os, E enumTmp) { \ os << E##MapName[static_cast(enumTmp)]; \ return os; \ } \ size_t operator*(E enumTmp) { \ (void)enumTmp; \ return E##MapName.size(); \ } \ std::string operator~(E enumTmp) { \ return E##MapName[static_cast(enumTmp)]; \ } \ std::string operator+(std::string &&str, E enumTmp) { \ return str + E##MapName[static_cast(enumTmp)]; \ } \ std::string operator+(E enumTmp, std::string &&str) { \ return E##MapName[static_cast(enumTmp)] + str; \ } \ std::string &operator+=(std::string &str, E enumTmp) { \ str += E##MapName[static_cast(enumTmp)]; \ return str; \ } \ E operator++(E &enumTmp) { \ auto iter = E##MapName.find(static_cast(enumTmp)); \ if (iter == E##MapName.end() || std::next(iter) == E##MapName.end()) \ iter = E##MapName.begin(); \ else { \ ++iter; \ } \ enumTmp = static_cast(iter->first); \ return enumTmp; \ } \ bool valid##E(T value) { \ return (E##MapName.find(value) != E##MapName.end()); \ } \ bool operator==(E left, E right) { \ return static_cast(left) == static_cast(right); \ } #define IMPL_ENUM(E) IMPL_ENUM_WITH_TYPE(E, int32_t) template std::map generateEnumMap(std::string strMap) { STRING_REMOVE_CHAR(strMap, ' '); STRING_REMOVE_CHAR(strMap, '('); std::vector enumTokens(splitString(strMap)); std::map retMap; T inxMap; inxMap = 0; for (auto iter = enumTokens.begin(); iter != enumTokens.end(); ++iter) { // Token: [EnumName | EnumName=EnumValue] std::string enumName; //T enumValue; if (iter->find('=') == std::string::npos) { enumName = *iter; } else { std::vector enumNameValue(splitString(*iter, '=')); enumName = enumNameValue[0]; // inxMap = static_cast(enumNameValue[1]); if (std::is_unsigned::value) { inxMap = static_cast(std::stoull(enumNameValue[1], 0, 0)); } else { inxMap = static_cast(std::stoll(enumNameValue[1], 0, 0)); } } retMap[inxMap++] = enumName; } return retMap; } ================================================ FILE: vp/src/util/gtkwave_riscv-filter/.gitignore ================================================ build/ ================================================ FILE: vp/src/util/gtkwave_riscv-filter/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.18) project(GTKWAVE_RISCV_INSTR_FILTER CXX) SET(INSTR ${CMAKE_CURRENT_SOURCE_DIR}/../../core/common) add_executable(gtkwave_riscv-filter riscv-filter.cpp ${INSTR}/instr.cpp ) target_include_directories(gtkwave_riscv-filter PRIVATE ${INSTR} ${CMAKE_CURRENT_SOURCE_DIR}/../.. ) target_compile_features(gtkwave_riscv-filter PRIVATE cxx_std_20) ================================================ FILE: vp/src/util/gtkwave_riscv-filter/riscv-filter.cpp ================================================ #include #include #include #include #include #include #include static Architecture ARCH = Architecture::RV32; static bool USE_PRETTY_NAMES = false; using namespace std; string registerName(uint_fast16_t num) { if(USE_PRETTY_NAMES) { return Opcode::regnamePrettyStr[num]; } else { return {"x" + to_string(num)}; } } void printOpcode(Instruction& instr) { Opcode::Mapping op; if (instr.is_compressed()) { op = instr.decode_and_expand_compressed(ARCH); } else { op = instr.decode_normal(ARCH); } cout << Opcode::mappingStr.at(op) << " "; switch (Opcode::getType(op)) { case Opcode::Type::R: cout << registerName(instr.rd()) << ", " << registerName(instr.rs1()) << ", " << registerName(instr.rs2()); break; case Opcode::Type::R4: // only >= rv64 cout << registerName(instr.rd()) << ", " << registerName(instr.rs1()) << ", " << registerName(instr.rs2()) << ", " << registerName(instr.rs3()); break; case Opcode::Type::I: cout << registerName(instr.rd()) << ", " << registerName(instr.rs1()) << ", " << instr.I_imm(); break; case Opcode::Type::S: cout << registerName(instr.rd()) << ", " << registerName(instr.rs1()) << ", " << instr.S_imm(); break; case Opcode::Type::B: cout << registerName(instr.rd()) << ", " << registerName(instr.rs1()) << ", " << instr.B_imm(); break; case Opcode::Type::U: cout << registerName(instr.rd()) << ", " << instr.U_imm(); break; case Opcode::Type::J: cout << registerName(instr.rd()) << ", " << instr.J_imm(); break; default: cout << "Unknown Opcode Type " << instr.opcode(); } cout << endl; } int main(int argc, const char* argv[]) { string line; Instruction instr; cout << showbase << hex; for(unsigned i = 1; i < argc; i++) { if(argv[i] == string{"--use-pretty-names"}) USE_PRETTY_NAMES = true; else if(argv[i] == string{"--rv64"}) ARCH = Architecture::RV64; else { cout << argv[0] << " [--use-pretty-names] [--rv64]" << endl; return 0; } } while(std::getline(cin, line)) { try { instr = std::stoul(line, nullptr, 16); // Base 16 } catch (std::invalid_argument&) { cerr << "Not a parse-able hex number: '" << line << "'" << endl; continue; } printOpcode(instr); } } ================================================ FILE: vp/src/util/gtkwave_riscv-filter.py ================================================ #!/usr/bin/env python3 import sys import tempfile import subprocess def main(): fh_in = sys.stdin fh_out = sys.stdout while True: l = fh_in.readline() if not l: return 0 if "x" in l: fh_out.write(l) fh_out.flush() continue obj_temp = tempfile.NamedTemporaryFile(delete=False, mode='w') with tempfile.NamedTemporaryFile(delete=False, mode='w') as asm_temp: asm_temp.write(".word 0x%s\n" % l) asm_temp.flush() subprocess.run(["riscv64-unknown-elf-as", "-march=rv32i", "-o", obj_temp.name, asm_temp.name]) result = subprocess.run(["riscv64-unknown-elf-objdump", "-d", obj_temp.name], capture_output=True) lastline = result.stdout.splitlines()[-1] chunks = lastline.decode().split('\t') opcodes = " ".join(chunks[2:]) fh_out.write("%s\n" % opcodes) fh_out.flush() if __name__ == '__main__': sys.exit(main()) ================================================ FILE: vp/src/util/memory_map.h ================================================ #pragma once #include #include #include "common.h" struct RegisterRange { struct WriteInfo { uint64_t addr; size_t size; tlm::tlm_generic_payload &trans; sc_core::sc_time &delay; }; struct ReadInfo { uint64_t addr; size_t size; tlm::tlm_generic_payload &trans; sc_core::sc_time &delay; }; typedef std::function PreWriteCallback; typedef std::function PostWriteCallback; typedef std::function PreReadCallback; typedef std::function PostReadCallback; uint64_t start; uint64_t end; std::vector mem; bool readonly = false; uint64_t alignment = 1; PreWriteCallback pre_write_callback; PostWriteCallback post_write_callback; PreReadCallback pre_read_callback; PostReadCallback post_read_callback; RegisterRange(uint64_t start, uint64_t size) : start(start) { assert(size > 0); end = start + size - 1; assert(end >= start); mem = std::vector(size); } static RegisterRange make_start_end(uint64_t start, uint64_t end) { assert(end >= start); return {start, end - start + 1}; } static RegisterRange make_start_size(uint64_t start, uint64_t size) { assert(size > 0); return {start, size}; } template static RegisterRange make_array(uint64_t start, uint64_t num_elems) { static_assert(std::is_integral::value, "integer type required"); assert(num_elems > 0); return {start, sizeof(T) * num_elems}; } bool contains(uint64_t addr) { return addr >= start && addr <= end; } uint64_t to_local(uint64_t addr) { return addr - start; } void write(uint64_t addr, const uint8_t *src, size_t len, tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { assert(contains(addr)); auto local_addr = to_local(addr); assert(local_addr + len <= mem.size()); if (pre_write_callback) if (!pre_write_callback({local_addr, len, trans, delay})) return; memcpy(mem.data() + local_addr, src, len); if (post_write_callback) post_write_callback({local_addr, len, trans, delay}); } void read(uint64_t addr, uint8_t *dst, size_t len, tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { assert(contains(addr)); auto local_addr = to_local(addr); assert(local_addr + len <= mem.size()); if (pre_read_callback) if (!pre_read_callback({local_addr, len, trans, delay})) return; memcpy(dst, mem.data() + local_addr, len); if (post_read_callback) post_read_callback({local_addr, len, trans, delay}); } bool match(tlm::tlm_generic_payload &trans) { return contains(trans.get_address()); } void process(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { auto addr = trans.get_address(); auto cmd = trans.get_command(); auto len = trans.get_data_length(); auto ptr = trans.get_data_ptr(); ensure((addr % alignment == 0) && (len % alignment == 0)); if (cmd == tlm::TLM_READ_COMMAND) { read(addr, ptr, len, trans, delay); } else if (cmd == tlm::TLM_WRITE_COMMAND) { ensure(!readonly); write(addr, ptr, len, trans, delay); } else { throw std::runtime_error("unsupported TLM command"); } } }; template struct IntegerView { static_assert(std::is_integral::value, "integer type required"); T *ptr; IntegerView(RegisterRange &r) { assert(((uintptr_t)r.mem.data()) % sizeof(T) == 0); assert(r.mem.size() >= sizeof(T)); ptr = reinterpret_cast(r.mem.data()); } T read() const { return *ptr; } void write(T value) { *ptr = value; } operator T() const { return read(); } IntegerView &operator=(uint64_t value) { write(value); return *this; } }; template struct ArrayView { static_assert(std::is_integral::value || std::is_pod::value, "integer or POD type required"); RegisterRange ®s; T *ptr; const size_t size; ArrayView(RegisterRange &r) : regs(r), size(r.mem.size() / sizeof(T)) { assert(r.mem.size() % sizeof(T) == 0); assert(size > 0); ptr = reinterpret_cast(r.mem.data()); } T &at(size_t idx) { if (idx >= size) throw std::out_of_range("ArrayView index out-of-range"); else return ptr[idx]; } T &operator[](unsigned idx) { assert(idx < size); return ptr[idx]; } // use for 2d array access T &operator()(unsigned idx, unsigned row_idx) { return ptr[idx * RowSize + row_idx]; } T *begin() { return &ptr[0]; } const T *begin() const { return &ptr[0]; } T *end() { return &ptr[size - 1]; } const T *end() const { return &ptr[size - 1]; } }; namespace vp { namespace mm { template void route(const char *name, Iter &iterable_mm, tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { for (auto e : iterable_mm) { if (e->match(trans)) { e->process(trans, delay); return; } } throw std::runtime_error(std::string(name) + " unable to route address " + std::to_string(trans.get_address())); } } // namespace mm } // namespace vp ================================================ FILE: vp/src/util/options.h ================================================ #pragma once #include #include #include template struct OptionValue { bool available = false; T value{}; std::string option; bool finalize(std::function parser) { if (!option.empty()) { value = parser(option); available = true; } return available; } }; unsigned long parse_ulong_option(const std::string &s) { bool is_hex = false; if (s.size() >= 2) { if ((s[0] == '0') && ((s[1] == 'x') || (s[1] == 'X'))) is_hex = true; } try { if (is_hex) return stoul(s, 0, 16); return stoul(s); } catch (std::exception &e) { throw std::runtime_error(std::string("unable to parse option '") + s + "' into a number"); } } ================================================ FILE: vp/src/util/tlm_map.h ================================================ #ifndef RISCV_TLM_MAP_H #define RISCV_TLM_MAP_H #include #include #include #include #include #include /* * Optional modelling layer to simplify TLM register and memory access. * sensor2.h demonstrates how to use it. */ namespace vp { namespace map { struct access_mode { bool allow_read = true; bool allow_write = true; static access_mode make_writeonly() { return access_mode({false, true}); } static access_mode make_readonly() { return access_mode({true, false}); } bool can_read() { return allow_read; } bool can_write() { return allow_write; } bool is_readonly() { return allow_read && !allow_write; } }; constexpr access_mode read_write = {true, true}; constexpr access_mode read_only = {true, false}; constexpr access_mode write_only = {false, true}; struct AbstractMapping { virtual ~AbstractMapping() {} virtual bool try_handle(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) = 0; }; inline void execute_memory_access(tlm::tlm_generic_payload &trans, uint8_t *local_memory) { if (trans.get_command() == tlm::TLM_WRITE_COMMAND) { memcpy(&local_memory[trans.get_address()], trans.get_data_ptr(), trans.get_data_length()); } else if (trans.get_command() == tlm::TLM_READ_COMMAND) { memcpy(trans.get_data_ptr(), &local_memory[trans.get_address()], trans.get_data_length()); } else { throw std::runtime_error("unsupported TLM command detected"); } } struct AddressMapping : public AbstractMapping { typedef std::function fn_transport_t; uint64_t start; uint64_t end; access_mode mode; fn_transport_t handler; template AddressMapping ®ister_handler(Module *this_, MemberFun fn) { assert(!handler); handler = std::bind(fn, this_, std::placeholders::_1, std::placeholders::_2); return *this; } AddressMapping ®ister_handler(AddressMapping::fn_transport_t fn) { assert(!handler); handler = fn; return *this; } bool try_handle(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { auto addr = trans.get_address(); auto len = trans.get_data_length(); auto cmd = trans.get_command(); if (addr >= start && addr < end) { assert((addr + len <= end) && "memory out of bounds access"); assert(mode.can_read() || cmd != tlm::TLM_READ_COMMAND); assert(mode.can_write() || cmd != tlm::TLM_WRITE_COMMAND); trans.set_address(addr - start); handler(trans, delay); return true; } return false; } }; struct reg_mapping_t { uint64_t addr; uint32_t *vptr; access_mode mode = read_write; uint32_t mask = 0xffffffff; uint32_t value() { return *vptr; } void bus_write(uint32_t new_value) { assert(mode.can_write()); *vptr = new_value & mask; } uint32_t bus_read() { assert(mode.can_read()); return *vptr; } }; struct register_access_t { typedef std::function callback_t; /* * vptr points to the actual register. * nv is the new value that will be assigned to the register (only valid for * write access). calling fn will perform the actual read/write operation. */ bool read; bool write; uint32_t *vptr; uint32_t nv; callback_t fn; sc_core::sc_time &delay; uint64_t addr; }; struct RegisterMapping : public AbstractMapping { typedef std::function callback_t; typedef std::function handler_t; std::unordered_map addr_to_reg; handler_t handler; RegisterMapping &add_register(reg_mapping_t m) { addr_to_reg.insert(std::make_pair(m.addr, m)); return *this; } template RegisterMapping ®ister_handler(Module *this_, MemberFun fn) { assert(!handler); handler = std::bind(fn, this_, std::placeholders::_1); return *this; } RegisterMapping ®ister_handler(RegisterMapping::handler_t fn) { assert(!handler); handler = fn; return *this; } bool try_handle(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { auto addr = trans.get_address(); auto new_vptr = (uint32_t *)trans.get_data_ptr(); auto len = trans.get_data_length(); auto cmd = trans.get_command(); auto it = addr_to_reg.find(addr - addr % 4); // clamp to nearest register if (it == addr_to_reg.end()) return false; assert(len + (addr % 4) <= 4); // do not allow access beyond the register assert(cmd == tlm::TLM_READ_COMMAND || cmd == tlm::TLM_WRITE_COMMAND); reg_mapping_t &r = it->second; assert(r.mode.can_read() || cmd != tlm::TLM_READ_COMMAND); assert(r.mode.can_write() || cmd != tlm::TLM_WRITE_COMMAND); auto fn = [cmd, &r, new_vptr, &trans]() { (void) new_vptr; auto off = trans.get_address() % 4; if (cmd == tlm::TLM_READ_COMMAND) { uint32_t n = r.bus_read(); memcpy(trans.get_data_ptr(), ((uint8_t *)&n) + off, trans.get_data_length()); //*new_vptr = r.bus_read(); } else if (cmd == tlm::TLM_WRITE_COMMAND) { uint32_t n = r.value(); memcpy(((uint8_t *)&n) + off, trans.get_data_ptr(), trans.get_data_length()); r.bus_write(n); // r.bus_write(*new_vptr); } else { throw std::runtime_error("unsupported TLM command detected"); } }; assert(handler && "no callback function provided"); // introduce *nv* to get rid of "use of uninitialized value" warnings uint32_t nv = 0; if (cmd == tlm::TLM_WRITE_COMMAND) nv = *new_vptr; handler({cmd == tlm::TLM_READ_COMMAND, cmd == tlm::TLM_WRITE_COMMAND, r.vptr, nv, fn, delay, addr}); return true; } }; struct LocalRouter { std::string name; std::vector maps; LocalRouter(const std::string &name = "unamed") : name(name) {} ~LocalRouter() { for (auto p : maps) { assert(p); delete p; } } void transport(tlm::tlm_generic_payload &trans, sc_core::sc_time &delay) { for (auto &m : maps) { if (m->try_handle(trans, delay)) return; } throw std::runtime_error("access of unmapped address (local TLM router): name=" + name + ", addr=0x" + (boost::format("%X") % trans.get_address()).str()); } RegisterMapping &add_register_bank(const std::vector ®s) { auto p = new RegisterMapping(); for (auto &m : regs) { assert(p->addr_to_reg.find(m.addr) == p->addr_to_reg.end() && "register at this address already available"); p->addr_to_reg.insert(std::make_pair(m.addr, m)); } maps.push_back(p); return *p; } AddressMapping &add_start_end_mapping(uint64_t start, uint64_t end, const access_mode &m) { auto p = new AddressMapping(); p->start = start; p->end = end; p->mode = m; maps.push_back(p); return *p; } AddressMapping &add_start_size_mapping(uint64_t start, uint32_t size, const access_mode &m) { return add_start_end_mapping(start, start + size, m); } }; } // namespace map } // namespace vp #endif // RISCV_TLM_MAP_H ================================================ FILE: vp/src/vendor/CMakeLists.txt ================================================ subdirs(softfloat) if(NOT USE_SYSTEM_SYSTEMC) include(ExternalProject) ExternalProject_Add( systemc_project URL ${CMAKE_CURRENT_SOURCE_DIR}/systemc CMAKE_ARGS -DCMAKE_CXX_FLAGS_NO_WARNINGS="-w" -DCMAKE_BUILD_TYPE=NO_WARNINGS -DCMAKE_INSTALL_LIBDIR=lib #don't use lib64 -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} -DBUILD_SHARED_LIBS=OFF INSTALL_COMMAND "" BINARY_DIR ${CMAKE_BINARY_DIR}/systemc BUILD_BYPRODUCTS ${CMAKE_BINARY_DIR}/systemc/src/libsystemc.a ) add_library(systemc STATIC IMPORTED GLOBAL) set_target_properties(systemc PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/systemc/src IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/systemc/src/libsystemc.a) add_dependencies(systemc systemc_project) endif() ================================================ FILE: vp/src/vendor/softfloat/CMakeLists.txt ================================================ add_library(softfloat f128_add.c f128_classify.c f128_div.c f128_eq.c f128_eq_signaling.c f128_isSignalingNaN.c f128_le.c f128_le_quiet.c f128_lt.c f128_lt_quiet.c f128_mul.c f128_mulAdd.c f128_rem.c f128_roundToInt.c f128_sqrt.c f128_sub.c f128_to_f16.c f128_to_f32.c f128_to_f64.c f128_to_i32.c f128_to_i32_r_minMag.c f128_to_i64.c f128_to_i64_r_minMag.c f128_to_ui32.c f128_to_ui32_r_minMag.c f128_to_ui64.c f128_to_ui64_r_minMag.c f16_add.c f16_div.c f16_eq.c f16_eq_signaling.c f16_isSignalingNaN.c f16_le.c f16_le_quiet.c f16_lt.c f16_lt_quiet.c f16_mul.c f16_mulAdd.c f16_rem.c f16_roundToInt.c f16_sqrt.c f16_sub.c f16_to_f128.c f16_to_f32.c f16_to_f64.c f16_to_i32.c f16_to_i32_r_minMag.c f16_to_i64.c f16_to_i64_r_minMag.c f16_to_ui32.c f16_to_ui32_r_minMag.c f16_to_ui64.c f16_to_ui64_r_minMag.c f32_add.c f32_classify.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_mul.c f32_mulAdd.c f32_rem.c f32_roundToInt.c f32_sqrt.c f32_sub.c f32_to_f128.c f32_to_f16.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 f64_add.c f64_classify.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_mul.c f64_mulAdd.c f64_rem.c f64_roundToInt.c f64_sqrt.c f64_sub.c f64_to_f128.c f64_to_f16.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 i32_to_f128.c i32_to_f16.c i32_to_f32.c i32_to_f64.c i64_to_f128.c i64_to_f16.c i64_to_f32.c i64_to_f64.c s_add128.c s_add256M.c s_addCarryM.c s_addComplCarryM.c s_addM.c s_addMagsF128.c s_addMagsF16.c s_addMagsF32.c s_addMagsF64.c s_approxRecip32_1.c s_approxRecipSqrt32_1.c s_approxRecipSqrt_1Ks.c s_approxRecip_1Ks.c s_commonNaNToF128UI.c s_commonNaNToF16UI.c s_commonNaNToF32UI.c s_commonNaNToF64UI.c s_compare128M.c s_compare96M.c s_countLeadingZeros16.c s_countLeadingZeros32.c s_countLeadingZeros64.c s_countLeadingZeros8.c s_eq128.c s_f128UIToCommonNaN.c s_f16UIToCommonNaN.c s_f32UIToCommonNaN.c s_f64UIToCommonNaN.c s_le128.c s_lt128.c s_mul128By32.c s_mul128MTo256M.c s_mul128To256M.c s_mul64ByShifted32To128.c s_mul64To128.c s_mul64To128M.c s_mulAddF128.c s_mulAddF16.c s_mulAddF32.c s_mulAddF64.c s_negXM.c s_normRoundPackToF128.c s_normRoundPackToF16.c s_normRoundPackToF32.c s_normRoundPackToF64.c s_normSubnormalF128Sig.c s_normSubnormalF16Sig.c s_normSubnormalF32Sig.c s_normSubnormalF64Sig.c s_propagateNaNF128UI.c s_propagateNaNF16UI.c s_propagateNaNF32UI.c s_propagateNaNF64UI.c s_remStepMBy32.c s_roundMToI64.c s_roundMToUI64.c s_roundPackMToI64.c s_roundPackMToUI64.c s_roundPackToF128.c s_roundPackToF16.c s_roundPackToF32.c s_roundPackToF64.c s_roundPackToI32.c s_roundPackToI64.c s_roundPackToUI32.c s_roundPackToUI64.c s_roundToI32.c s_roundToI64.c s_roundToUI32.c s_roundToUI64.c s_shiftRightJam128.c s_shiftRightJam128Extra.c s_shiftRightJam256M.c s_shiftRightJam32.c s_shiftRightJam64.c s_shiftRightJam64Extra.c s_shortShiftLeft128.c s_shortShiftLeft64To96M.c s_shortShiftRight128.c s_shortShiftRightExtendM.c s_shortShiftRightJam128.c s_shortShiftRightJam128Extra.c s_shortShiftRightJam64.c s_shortShiftRightJam64Extra.c s_shortShiftRightM.c s_sub128.c s_sub1XM.c s_sub256M.c s_subM.c s_subMagsF128.c s_subMagsF16.c s_subMagsF32.c s_subMagsF64.c softfloat_raiseFlags.c softfloat_state.c ui32_to_f128.c ui32_to_f16.c ui32_to_f32.c ui32_to_f64.c ui64_to_f128.c ui64_to_f16.c ui64_to_f32.c ui64_to_f64.c) target_compile_definitions(softfloat PRIVATE SOFTFLOAT_ROUND_ODD INLINE_LEVEL=5 SOFTFLOAT_FAST_DIV32TO16 SOFTFLOAT_FAST_DIV64TO32 SOFTFLOAT_FAST_INT64) target_include_directories(softfloat PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include/softfloat) target_include_directories(softfloat PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) ================================================ FILE: vp/src/vendor/softfloat/f128_add.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" float128_t f128_add( float128_t a, float128_t b ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool signA; union ui128_f128 uB; uint_fast64_t uiB64, uiB0; bool signB; #if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) float128_t (*magsFuncPtr)( uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); #endif uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; signA = signF128UI64( uiA64 ); uB.f = b; uiB64 = uB.ui.v64; uiB0 = uB.ui.v0; signB = signF128UI64( uiB64 ); #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) if ( signA == signB ) { return softfloat_addMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); } else { return softfloat_subMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); } #else magsFuncPtr = (signA == signB) ? softfloat_addMagsF128 : softfloat_subMagsF128; return (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); #endif } ================================================ FILE: vp/src/vendor/softfloat/f128_classify.c ================================================ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast16_t f128_classify( float128_t a ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; uint_fast16_t infOrNaN = expF128UI64( uiA64 ) == 0x7FFF; uint_fast16_t subnormalOrZero = expF128UI64( uiA64 ) == 0; bool sign = signF128UI64( uiA64 ); bool fracZero = fracF128UI64( uiA64 ) == 0 && uiA0 == 0; bool isNaN = isNaNF128UI( uiA64, uiA0 ); bool isSNaN = softfloat_isSigNaNF128UI( uiA64, uiA0 ); return ( sign && infOrNaN && fracZero ) << 0 | ( sign && !infOrNaN && !subnormalOrZero ) << 1 | ( sign && subnormalOrZero && !fracZero ) << 2 | ( sign && subnormalOrZero && fracZero ) << 3 | ( !sign && infOrNaN && fracZero ) << 7 | ( !sign && !infOrNaN && !subnormalOrZero ) << 6 | ( !sign && subnormalOrZero && !fracZero ) << 5 | ( !sign && subnormalOrZero && fracZero ) << 4 | ( isNaN && isSNaN ) << 8 | ( isNaN && !isSNaN ) << 9; } ================================================ FILE: vp/src/vendor/softfloat/f128_div.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float128_t f128_div( float128_t a, float128_t b ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool signA; int_fast32_t expA; struct uint128 sigA; union ui128_f128 uB; uint_fast64_t uiB64, uiB0; bool signB; int_fast32_t expB; struct uint128 sigB; bool signZ; struct exp32_sig128 normExpSig; int_fast32_t expZ; struct uint128 rem; uint_fast32_t recip32; int ix; uint_fast64_t q64; uint_fast32_t q; struct uint128 term; uint_fast32_t qs[3]; uint_fast64_t sigZExtra; struct uint128 sigZ, uiZ; union ui128_f128 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; signA = signF128UI64( uiA64 ); expA = expF128UI64( uiA64 ); sigA.v64 = fracF128UI64( uiA64 ); sigA.v0 = uiA0; uB.f = b; uiB64 = uB.ui.v64; uiB0 = uB.ui.v0; signB = signF128UI64( uiB64 ); expB = expF128UI64( uiB64 ); sigB.v64 = fracF128UI64( uiB64 ); sigB.v0 = uiB0; signZ = signA ^ signB; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x7FFF ) { if ( sigA.v64 | sigA.v0 ) goto propagateNaN; if ( expB == 0x7FFF ) { if ( sigB.v64 | sigB.v0 ) goto propagateNaN; goto invalid; } goto infinity; } if ( expB == 0x7FFF ) { if ( sigB.v64 | sigB.v0 ) goto propagateNaN; goto zero; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expB ) { if ( ! (sigB.v64 | sigB.v0) ) { if ( ! (expA | sigA.v64 | sigA.v0) ) goto invalid; softfloat_raiseFlags( softfloat_flag_infinite ); goto infinity; } normExpSig = softfloat_normSubnormalF128Sig( sigB.v64, sigB.v0 ); expB = normExpSig.exp; sigB = normExpSig.sig; } if ( ! expA ) { if ( ! (sigA.v64 | sigA.v0) ) goto zero; normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); expA = normExpSig.exp; sigA = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA - expB + 0x3FFE; sigA.v64 |= UINT64_C( 0x0001000000000000 ); sigB.v64 |= UINT64_C( 0x0001000000000000 ); rem = sigA; if ( softfloat_lt128( sigA.v64, sigA.v0, sigB.v64, sigB.v0 ) ) { --expZ; rem = softfloat_add128( sigA.v64, sigA.v0, sigA.v64, sigA.v0 ); } recip32 = softfloat_approxRecip32_1( sigB.v64>>17 ); ix = 3; for (;;) { q64 = (uint_fast64_t) (uint32_t) (rem.v64>>19) * recip32; q = (q64 + 0x80000000)>>32; --ix; if ( ix < 0 ) break; rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); term = softfloat_mul128By32( sigB.v64, sigB.v0, q ); rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { --q; rem = softfloat_add128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); } qs[ix] = q; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ((q + 1) & 7) < 2 ) { rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); term = softfloat_mul128By32( sigB.v64, sigB.v0, q ); rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { --q; rem = softfloat_add128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); } else if ( softfloat_le128( sigB.v64, sigB.v0, rem.v64, rem.v0 ) ) { ++q; rem = softfloat_sub128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); } if ( rem.v64 | rem.v0 ) q |= 1; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sigZExtra = (uint64_t) ((uint_fast64_t) q<<60); term = softfloat_shortShiftLeft128( 0, qs[1], 54 ); sigZ = softfloat_add128( (uint_fast64_t) qs[2]<<19, ((uint_fast64_t) qs[0]<<25) + (q>>4), term.v64, term.v0 ); return softfloat_roundPackToF128( signZ, expZ, sigZ.v64, sigZ.v0, sigZExtra ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ.v64 = defaultNaNF128UI64; uiZ.v0 = defaultNaNF128UI0; goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infinity: uiZ.v64 = packToF128UI64( signZ, 0x7FFF, 0 ); goto uiZ0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zero: uiZ.v64 = packToF128UI64( signZ, 0, 0 ); uiZ0: uiZ.v0 = 0; uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f128_eq.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" bool f128_eq( float128_t a, float128_t b ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; union ui128_f128 uB; uint_fast64_t uiB64, uiB0; uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; uB.f = b; uiB64 = uB.ui.v64; uiB0 = uB.ui.v0; if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { if ( softfloat_isSigNaNF128UI( uiA64, uiA0 ) || softfloat_isSigNaNF128UI( uiB64, uiB0 ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); } return false; } return (uiA0 == uiB0) && ( (uiA64 == uiB64) || (! uiA0 && ! ((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) ); } ================================================ FILE: vp/src/vendor/softfloat/f128_eq_signaling.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" bool f128_eq_signaling( float128_t a, float128_t b ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; union ui128_f128 uB; uint_fast64_t uiB64, uiB0; uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; uB.f = b; uiB64 = uB.ui.v64; uiB0 = uB.ui.v0; if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return false; } return (uiA0 == uiB0) && ( (uiA64 == uiB64) || (! uiA0 && ! ((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) ); } ================================================ FILE: vp/src/vendor/softfloat/f128_isSignalingNaN.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" bool f128_isSignalingNaN( float128_t a ) { union ui128_f128 uA; uA.f = a; return softfloat_isSigNaNF128UI( uA.ui.v64, uA.ui.v0 ); } ================================================ FILE: vp/src/vendor/softfloat/f128_le.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" bool f128_le( float128_t a, float128_t b ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; union ui128_f128 uB; uint_fast64_t uiB64, uiB0; bool signA, signB; uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; uB.f = b; uiB64 = uB.ui.v64; uiB0 = uB.ui.v0; if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return false; } signA = signF128UI64( uiA64 ); signB = signF128UI64( uiB64 ); return (signA != signB) ? signA || ! (((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) | uiA0 | uiB0) : ((uiA64 == uiB64) && (uiA0 == uiB0)) || (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); } ================================================ FILE: vp/src/vendor/softfloat/f128_le_quiet.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" bool f128_le_quiet( float128_t a, float128_t b ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; union ui128_f128 uB; uint_fast64_t uiB64, uiB0; bool signA, signB; uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; uB.f = b; uiB64 = uB.ui.v64; uiB0 = uB.ui.v0; if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { if ( softfloat_isSigNaNF128UI( uiA64, uiA0 ) || softfloat_isSigNaNF128UI( uiB64, uiB0 ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); } return false; } signA = signF128UI64( uiA64 ); signB = signF128UI64( uiB64 ); return (signA != signB) ? signA || ! (((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) | uiA0 | uiB0) : ((uiA64 == uiB64) && (uiA0 == uiB0)) || (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); } ================================================ FILE: vp/src/vendor/softfloat/f128_lt.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" bool f128_lt( float128_t a, float128_t b ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; union ui128_f128 uB; uint_fast64_t uiB64, uiB0; bool signA, signB; uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; uB.f = b; uiB64 = uB.ui.v64; uiB0 = uB.ui.v0; if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return false; } signA = signF128UI64( uiA64 ); signB = signF128UI64( uiB64 ); return (signA != signB) ? signA && (((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) | uiA0 | uiB0) : ((uiA64 != uiB64) || (uiA0 != uiB0)) && (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); } ================================================ FILE: vp/src/vendor/softfloat/f128_lt_quiet.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" bool f128_lt_quiet( float128_t a, float128_t b ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; union ui128_f128 uB; uint_fast64_t uiB64, uiB0; bool signA, signB; uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; uB.f = b; uiB64 = uB.ui.v64; uiB0 = uB.ui.v0; if ( isNaNF128UI( uiA64, uiA0 ) || isNaNF128UI( uiB64, uiB0 ) ) { if ( softfloat_isSigNaNF128UI( uiA64, uiA0 ) || softfloat_isSigNaNF128UI( uiB64, uiB0 ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); } return false; } signA = signF128UI64( uiA64 ); signB = signF128UI64( uiB64 ); return (signA != signB) ? signA && (((uiA64 | uiB64) & UINT64_C( 0x7FFFFFFFFFFFFFFF )) | uiA0 | uiB0) : ((uiA64 != uiB64) || (uiA0 != uiB0)) && (signA ^ softfloat_lt128( uiA64, uiA0, uiB64, uiB0 )); } ================================================ FILE: vp/src/vendor/softfloat/f128_mul.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float128_t f128_mul( float128_t a, float128_t b ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool signA; int_fast32_t expA; struct uint128 sigA; union ui128_f128 uB; uint_fast64_t uiB64, uiB0; bool signB; int_fast32_t expB; struct uint128 sigB; bool signZ; uint_fast64_t magBits; struct exp32_sig128 normExpSig; int_fast32_t expZ; uint64_t sig256Z[4]; uint_fast64_t sigZExtra; struct uint128 sigZ; struct uint128_extra sig128Extra; struct uint128 uiZ; union ui128_f128 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; signA = signF128UI64( uiA64 ); expA = expF128UI64( uiA64 ); sigA.v64 = fracF128UI64( uiA64 ); sigA.v0 = uiA0; uB.f = b; uiB64 = uB.ui.v64; uiB0 = uB.ui.v0; signB = signF128UI64( uiB64 ); expB = expF128UI64( uiB64 ); sigB.v64 = fracF128UI64( uiB64 ); sigB.v0 = uiB0; signZ = signA ^ signB; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x7FFF ) { if ( (sigA.v64 | sigA.v0) || ((expB == 0x7FFF) && (sigB.v64 | sigB.v0)) ) { goto propagateNaN; } magBits = expB | sigB.v64 | sigB.v0; goto infArg; } if ( expB == 0x7FFF ) { if ( sigB.v64 | sigB.v0 ) goto propagateNaN; magBits = expA | sigA.v64 | sigA.v0; goto infArg; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) { if ( ! (sigA.v64 | sigA.v0) ) goto zero; normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); expA = normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) { if ( ! (sigB.v64 | sigB.v0) ) goto zero; normExpSig = softfloat_normSubnormalF128Sig( sigB.v64, sigB.v0 ); expB = normExpSig.exp; sigB = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0x4000; sigA.v64 |= UINT64_C( 0x0001000000000000 ); sigB = softfloat_shortShiftLeft128( sigB.v64, sigB.v0, 16 ); softfloat_mul128To256M( sigA.v64, sigA.v0, sigB.v64, sigB.v0, sig256Z ); sigZExtra = sig256Z[indexWord( 4, 1 )] | (sig256Z[indexWord( 4, 0 )] != 0); sigZ = softfloat_add128( sig256Z[indexWord( 4, 3 )], sig256Z[indexWord( 4, 2 )], sigA.v64, sigA.v0 ); if ( UINT64_C( 0x0002000000000000 ) <= sigZ.v64 ) { ++expZ; sig128Extra = softfloat_shortShiftRightJam128Extra( sigZ.v64, sigZ.v0, sigZExtra, 1 ); sigZ = sig128Extra.v; sigZExtra = sig128Extra.extra; } return softfloat_roundPackToF128( signZ, expZ, sigZ.v64, sigZ.v0, sigZExtra ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infArg: if ( ! magBits ) { softfloat_raiseFlags( softfloat_flag_invalid ); uiZ.v64 = defaultNaNF128UI64; uiZ.v0 = defaultNaNF128UI0; goto uiZ; } uiZ.v64 = packToF128UI64( signZ, 0x7FFF, 0 ); goto uiZ0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zero: uiZ.v64 = packToF128UI64( signZ, 0, 0 ); uiZ0: uiZ.v0 = 0; uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f128_mulAdd.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "internals.h" #include "softfloat.h" float128_t f128_mulAdd( float128_t a, float128_t b, float128_t c ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; union ui128_f128 uB; uint_fast64_t uiB64, uiB0; union ui128_f128 uC; uint_fast64_t uiC64, uiC0; uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; uB.f = b; uiB64 = uB.ui.v64; uiB0 = uB.ui.v0; uC.f = c; uiC64 = uC.ui.v64; uiC0 = uC.ui.v0; return softfloat_mulAddF128( uiA64, uiA0, uiB64, uiB0, uiC64, uiC0, 0 ); } ================================================ FILE: vp/src/vendor/softfloat/f128_rem.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float128_t f128_rem( float128_t a, float128_t b ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool signA; int_fast32_t expA; struct uint128 sigA; union ui128_f128 uB; uint_fast64_t uiB64, uiB0; int_fast32_t expB; struct uint128 sigB; struct exp32_sig128 normExpSig; struct uint128 rem; int_fast32_t expDiff; uint_fast32_t q, recip32; uint_fast64_t q64; struct uint128 term, altRem, meanRem; bool signRem; struct uint128 uiZ; union ui128_f128 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; signA = signF128UI64( uiA64 ); expA = expF128UI64( uiA64 ); sigA.v64 = fracF128UI64( uiA64 ); sigA.v0 = uiA0; uB.f = b; uiB64 = uB.ui.v64; uiB0 = uB.ui.v0; expB = expF128UI64( uiB64 ); sigB.v64 = fracF128UI64( uiB64 ); sigB.v0 = uiB0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x7FFF ) { if ( (sigA.v64 | sigA.v0) || ((expB == 0x7FFF) && (sigB.v64 | sigB.v0)) ) { goto propagateNaN; } goto invalid; } if ( expB == 0x7FFF ) { if ( sigB.v64 | sigB.v0 ) goto propagateNaN; return a; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expB ) { if ( ! (sigB.v64 | sigB.v0) ) goto invalid; normExpSig = softfloat_normSubnormalF128Sig( sigB.v64, sigB.v0 ); expB = normExpSig.exp; sigB = normExpSig.sig; } if ( ! expA ) { if ( ! (sigA.v64 | sigA.v0) ) return a; normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); expA = normExpSig.exp; sigA = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sigA.v64 |= UINT64_C( 0x0001000000000000 ); sigB.v64 |= UINT64_C( 0x0001000000000000 ); rem = sigA; expDiff = expA - expB; if ( expDiff < 1 ) { if ( expDiff < -1 ) return a; if ( expDiff ) { --expB; sigB = softfloat_add128( sigB.v64, sigB.v0, sigB.v64, sigB.v0 ); q = 0; } else { q = softfloat_le128( sigB.v64, sigB.v0, rem.v64, rem.v0 ); if ( q ) { rem = softfloat_sub128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); } } } else { recip32 = softfloat_approxRecip32_1( sigB.v64>>17 ); expDiff -= 30; for (;;) { q64 = (uint_fast64_t) (uint32_t) (rem.v64>>19) * recip32; if ( expDiff < 0 ) break; q = (q64 + 0x80000000)>>32; rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); term = softfloat_mul128By32( sigB.v64, sigB.v0, q ); rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { rem = softfloat_add128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); } expDiff -= 29; } /*-------------------------------------------------------------------- | (`expDiff' cannot be less than -29 here.) *--------------------------------------------------------------------*/ q = (uint32_t) (q64>>32)>>(~expDiff & 31); rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, expDiff + 30 ); term = softfloat_mul128By32( sigB.v64, sigB.v0, q ); rem = softfloat_sub128( rem.v64, rem.v0, term.v64, term.v0 ); if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { altRem = softfloat_add128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); goto selectRem; } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ do { altRem = rem; ++q; rem = softfloat_sub128( rem.v64, rem.v0, sigB.v64, sigB.v0 ); } while ( ! (rem.v64 & UINT64_C( 0x8000000000000000 )) ); selectRem: meanRem = softfloat_add128( rem.v64, rem.v0, altRem.v64, altRem.v0 ); if ( (meanRem.v64 & UINT64_C( 0x8000000000000000 )) || (! (meanRem.v64 | meanRem.v0) && (q & 1)) ) { rem = altRem; } signRem = signA; if ( rem.v64 & UINT64_C( 0x8000000000000000 ) ) { signRem = ! signRem; rem = softfloat_sub128( 0, 0, rem.v64, rem.v0 ); } return softfloat_normRoundPackToF128( signRem, expB - 1, rem.v64, rem.v0 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ.v64 = defaultNaNF128UI64; uiZ.v0 = defaultNaNF128UI0; uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f128_roundToInt.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float128_t f128_roundToInt( float128_t a, uint_fast8_t roundingMode, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; int_fast32_t exp; struct uint128 uiZ; uint_fast64_t lastBitMask, roundBitsMask; bool roundNearEven; union ui128_f128 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; exp = expF128UI64( uiA64 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x402F <= exp ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( 0x406F <= exp ) { if ( (exp == 0x7FFF) && (fracF128UI64( uiA64 ) | uiA0) ) { uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, 0, 0 ); goto uiZ; } return a; } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ lastBitMask = (uint_fast64_t) 2<<(0x406E - exp); roundBitsMask = lastBitMask - 1; uiZ.v64 = uiA64; uiZ.v0 = uiA0; roundNearEven = (roundingMode == softfloat_round_near_even); if ( roundNearEven || (roundingMode == softfloat_round_near_maxMag) ) { if ( exp == 0x402F ) { if ( UINT64_C( 0x8000000000000000 ) <= uiZ.v0 ) { ++uiZ.v64; if ( roundNearEven && (uiZ.v0 == UINT64_C( 0x8000000000000000 )) ) { uiZ.v64 &= ~1; } } } else { uiZ = softfloat_add128( uiZ.v64, uiZ.v0, 0, lastBitMask>>1 ); if ( roundNearEven && ! (uiZ.v0 & roundBitsMask) ) { uiZ.v0 &= ~lastBitMask; } } } else if ( roundingMode == (signF128UI64( uiZ.v64 ) ? softfloat_round_min : softfloat_round_max) ) { uiZ = softfloat_add128( uiZ.v64, uiZ.v0, 0, roundBitsMask ); } uiZ.v0 &= ~roundBitsMask; } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( exp < 0x3FFF ) { if ( ! ((uiA64 & UINT64_C( 0x7FFFFFFFFFFFFFFF )) | uiA0) ) { return a; } if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; uiZ.v64 = uiA64 & packToF128UI64( 1, 0, 0 ); uiZ.v0 = 0; switch ( roundingMode ) { case softfloat_round_near_even: if ( ! (fracF128UI64( uiA64 ) | uiA0) ) break; case softfloat_round_near_maxMag: if ( exp == 0x3FFE ) uiZ.v64 |= packToF128UI64( 0, 0x3FFF, 0 ); break; case softfloat_round_min: if ( uiZ.v64 ) uiZ.v64 = packToF128UI64( 1, 0x3FFF, 0 ); break; case softfloat_round_max: if ( ! uiZ.v64 ) uiZ.v64 = packToF128UI64( 0, 0x3FFF, 0 ); break; } goto uiZ; } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ uiZ.v64 = uiA64; uiZ.v0 = 0; lastBitMask = (uint_fast64_t) 1<<(0x402F - exp); roundBitsMask = lastBitMask - 1; if ( roundingMode == softfloat_round_near_maxMag ) { uiZ.v64 += lastBitMask>>1; } else if ( roundingMode == softfloat_round_near_even ) { uiZ.v64 += lastBitMask>>1; if ( ! ((uiZ.v64 & roundBitsMask) | uiA0) ) { uiZ.v64 &= ~lastBitMask; } } else if ( roundingMode == (signF128UI64( uiZ.v64 ) ? softfloat_round_min : softfloat_round_max) ) { uiZ.v64 = (uiZ.v64 | (uiA0 != 0)) + roundBitsMask; } uiZ.v64 &= ~roundBitsMask; } if ( exact && ((uiZ.v64 != uiA64) || (uiZ.v0 != uiA0)) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f128_sqrt.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float128_t f128_sqrt( float128_t a ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool signA; int_fast32_t expA; struct uint128 sigA, uiZ; struct exp32_sig128 normExpSig; int_fast32_t expZ; uint_fast32_t sig32A, recipSqrt32, sig32Z; struct uint128 rem; uint32_t qs[3]; uint_fast32_t q; uint_fast64_t x64, sig64Z; struct uint128 y, term; uint_fast64_t sigZExtra; struct uint128 sigZ; union ui128_f128 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; signA = signF128UI64( uiA64 ); expA = expF128UI64( uiA64 ); sigA.v64 = fracF128UI64( uiA64 ); sigA.v0 = uiA0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x7FFF ) { if ( sigA.v64 | sigA.v0 ) { uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, 0, 0 ); goto uiZ; } if ( ! signA ) return a; goto invalid; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( signA ) { if ( ! (expA | sigA.v64 | sigA.v0) ) return a; goto invalid; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) { if ( ! (sigA.v64 | sigA.v0) ) return a; normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); expA = normExpSig.exp; sigA = normExpSig.sig; } /*------------------------------------------------------------------------ | (`sig32Z' is guaranteed to be a lower bound on the square root of | `sig32A', which makes `sig32Z' also a lower bound on the square root of | `sigA'.) *------------------------------------------------------------------------*/ expZ = ((expA - 0x3FFF)>>1) + 0x3FFE; expA &= 1; sigA.v64 |= UINT64_C( 0x0001000000000000 ); sig32A = sigA.v64>>17; recipSqrt32 = softfloat_approxRecipSqrt32_1( expA, sig32A ); sig32Z = ((uint_fast64_t) sig32A * recipSqrt32)>>32; if ( expA ) { sig32Z >>= 1; rem = softfloat_shortShiftLeft128( sigA.v64, sigA.v0, 12 ); } else { rem = softfloat_shortShiftLeft128( sigA.v64, sigA.v0, 13 ); } qs[2] = sig32Z; rem.v64 -= (uint_fast64_t) sig32Z * sig32Z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ q = ((uint32_t) (rem.v64>>2) * (uint_fast64_t) recipSqrt32)>>32; x64 = (uint_fast64_t) sig32Z<<32; sig64Z = x64 + ((uint_fast64_t) q<<3); y = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); /*------------------------------------------------------------------------ | (Repeating this loop is a rare occurrence.) *------------------------------------------------------------------------*/ for (;;) { term = softfloat_mul64ByShifted32To128( x64 + sig64Z, q ); rem = softfloat_sub128( y.v64, y.v0, term.v64, term.v0 ); if ( ! (rem.v64 & UINT64_C( 0x8000000000000000 )) ) break; --q; sig64Z -= 1<<3; } qs[1] = q; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ q = ((rem.v64>>2) * recipSqrt32)>>32; y = softfloat_shortShiftLeft128( rem.v64, rem.v0, 29 ); sig64Z <<= 1; /*------------------------------------------------------------------------ | (Repeating this loop is a rare occurrence.) *------------------------------------------------------------------------*/ for (;;) { term = softfloat_shortShiftLeft128( 0, sig64Z, 32 ); term = softfloat_add128( term.v64, term.v0, 0, (uint_fast64_t) q<<6 ); term = softfloat_mul128By32( term.v64, term.v0, q ); rem = softfloat_sub128( y.v64, y.v0, term.v64, term.v0 ); if ( ! (rem.v64 & UINT64_C( 0x8000000000000000 )) ) break; --q; } qs[0] = q; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ q = (((rem.v64>>2) * recipSqrt32)>>32) + 2; sigZExtra = (uint64_t) ((uint_fast64_t) q<<59); term = softfloat_shortShiftLeft128( 0, qs[1], 53 ); sigZ = softfloat_add128( (uint_fast64_t) qs[2]<<18, ((uint_fast64_t) qs[0]<<24) + (q>>5), term.v64, term.v0 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( (q & 0xF) <= 2 ) { q &= ~3; sigZExtra = (uint64_t) ((uint_fast64_t) q<<59); y = softfloat_shortShiftLeft128( sigZ.v64, sigZ.v0, 6 ); y.v0 |= sigZExtra>>58; term = softfloat_sub128( y.v64, y.v0, 0, q ); y = softfloat_mul64ByShifted32To128( term.v0, q ); term = softfloat_mul64ByShifted32To128( term.v64, q ); term = softfloat_add128( term.v64, term.v0, 0, y.v64 ); rem = softfloat_shortShiftLeft128( rem.v64, rem.v0, 20 ); term = softfloat_sub128( term.v64, term.v0, rem.v64, rem.v0 ); /*-------------------------------------------------------------------- | The concatenation of `term' and `y.v0' is now the negative remainder | (3 words altogether). *--------------------------------------------------------------------*/ if ( term.v64 & UINT64_C( 0x8000000000000000 ) ) { sigZExtra |= 1; } else { if ( term.v64 | term.v0 | y.v0 ) { if ( sigZExtra ) { --sigZExtra; } else { sigZ = softfloat_sub128( sigZ.v64, sigZ.v0, 0, 1 ); sigZExtra = ~0; } } } } return softfloat_roundPackToF128( 0, expZ, sigZ.v64, sigZ.v0, sigZExtra ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ.v64 = defaultNaNF128UI64; uiZ.v0 = defaultNaNF128UI0; uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f128_sub.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" float128_t f128_sub( float128_t a, float128_t b ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool signA; union ui128_f128 uB; uint_fast64_t uiB64, uiB0; bool signB; #if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) float128_t (*magsFuncPtr)( uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); #endif uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; signA = signF128UI64( uiA64 ); uB.f = b; uiB64 = uB.ui.v64; uiB0 = uB.ui.v0; signB = signF128UI64( uiB64 ); #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) if ( signA == signB ) { return softfloat_subMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); } else { return softfloat_addMagsF128( uiA64, uiA0, uiB64, uiB0, signA ); } #else magsFuncPtr = (signA == signB) ? softfloat_subMagsF128 : softfloat_addMagsF128; return (*magsFuncPtr)( uiA64, uiA0, uiB64, uiB0, signA ); #endif } ================================================ FILE: vp/src/vendor/softfloat/f128_to_f16.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float16_t f128_to_f16( float128_t a ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t frac64; struct commonNaN commonNaN; uint_fast16_t uiZ, frac16; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); frac64 = fracF128UI64( uiA64 ) | (uiA0 != 0); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FFF ) { if ( frac64 ) { softfloat_f128UIToCommonNaN( uiA64, uiA0, &commonNaN ); uiZ = softfloat_commonNaNToF16UI( &commonNaN ); } else { uiZ = packToF16UI( sign, 0x1F, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ frac16 = softfloat_shortShiftRightJam64( frac64, 34 ); if ( ! (exp | frac16) ) { uiZ = packToF16UI( sign, 0, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ exp -= 0x3FF1; if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { if ( exp < -0x40 ) exp = -0x40; } return softfloat_roundPackToF16( sign, exp, frac16 | 0x4000 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f128_to_f32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float32_t f128_to_f32( float128_t a ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t frac64; struct commonNaN commonNaN; uint_fast32_t uiZ, frac32; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); frac64 = fracF128UI64( uiA64 ) | (uiA0 != 0); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FFF ) { if ( frac64 ) { softfloat_f128UIToCommonNaN( uiA64, uiA0, &commonNaN ); uiZ = softfloat_commonNaNToF32UI( &commonNaN ); } else { uiZ = packToF32UI( sign, 0xFF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ frac32 = softfloat_shortShiftRightJam64( frac64, 18 ); if ( ! (exp | frac32) ) { uiZ = packToF32UI( sign, 0, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ exp -= 0x3F81; if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { if ( exp < -0x1000 ) exp = -0x1000; } return softfloat_roundPackToF32( sign, exp, frac32 | 0x40000000 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f128_to_f64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float64_t f128_to_f64( float128_t a ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t frac64, frac0; struct commonNaN commonNaN; uint_fast64_t uiZ; struct uint128 frac128; union ui64_f64 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); frac64 = fracF128UI64( uiA64 ); frac0 = uiA0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FFF ) { if ( frac64 | frac0 ) { softfloat_f128UIToCommonNaN( uiA64, uiA0, &commonNaN ); uiZ = softfloat_commonNaNToF64UI( &commonNaN ); } else { uiZ = packToF64UI( sign, 0x7FF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ frac128 = softfloat_shortShiftLeft128( frac64, frac0, 14 ); frac64 = frac128.v64 | (frac128.v0 != 0); if ( ! (exp | frac64) ) { uiZ = packToF64UI( sign, 0, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ exp -= 0x3C01; if ( sizeof (int_fast16_t) < sizeof (int_fast32_t) ) { if ( exp < -0x1000 ) exp = -0x1000; } return softfloat_roundPackToF64( sign, exp, frac64 | UINT64_C( 0x4000000000000000 ) ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f128_to_i32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast32_t f128_to_i32( float128_t a, uint_fast8_t roundingMode, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t sig64, sig0; int_fast32_t shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ); sig0 = uiA0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ #if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) if ( (exp == 0x7FFF) && (sig64 | sig0) ) { #if (i32_fromNaN == i32_fromPosOverflow) sign = 0; #elif (i32_fromNaN == i32_fromNegOverflow) sign = 1; #else softfloat_raiseFlags( softfloat_flag_invalid ); return i32_fromNaN; #endif } #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); sig64 |= (sig0 != 0); shiftDist = 0x4023 - exp; if ( 0 < shiftDist ) sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); return softfloat_roundToI32( sign, sig64, roundingMode, exact ); } ================================================ FILE: vp/src/vendor/softfloat/f128_to_i32_r_minMag.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast32_t f128_to_i32_r_minMag( float128_t a, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; int_fast32_t exp; uint_fast64_t sig64; int_fast32_t shiftDist; bool sign; int_fast32_t absZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ) | (uiA0 != 0); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x402F - exp; if ( 49 <= shiftDist ) { if ( exact && (exp | sig64) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF128UI64( uiA64 ); if ( shiftDist < 18 ) { if ( sign && (shiftDist == 17) && (sig64 < UINT64_C( 0x0000000000020000 )) ) { if ( exact && sig64 ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return -0x7FFFFFFF - 1; } softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FFF) && sig64 ? i32_fromNaN : sign ? i32_fromNegOverflow : i32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig64 |= UINT64_C( 0x0001000000000000 ); absZ = sig64>>shiftDist; if ( exact && ((uint_fast64_t) (uint_fast32_t) absZ< #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast64_t f128_to_i64( float128_t a, uint_fast8_t roundingMode, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t sig64, sig0; int_fast32_t shiftDist; struct uint128 sig128; struct uint64_extra sigExtra; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ); sig0 = uiA0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x402F - exp; if ( shiftDist <= 0 ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( shiftDist < -15 ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FFF) && (sig64 | sig0) ? i64_fromNaN : sign ? i64_fromNegOverflow : i64_fromPosOverflow; } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ sig64 |= UINT64_C( 0x0001000000000000 ); if ( shiftDist ) { sig128 = softfloat_shortShiftLeft128( sig64, sig0, -shiftDist ); sig64 = sig128.v64; sig0 = sig128.v0; } } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); sigExtra = softfloat_shiftRightJam64Extra( sig64, sig0, shiftDist ); sig64 = sigExtra.v; sig0 = sigExtra.extra; } return softfloat_roundToI64( sign, sig64, sig0, roundingMode, exact ); } ================================================ FILE: vp/src/vendor/softfloat/f128_to_i64_r_minMag.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast64_t f128_to_i64_r_minMag( float128_t a, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t sig64, sig0; int_fast32_t shiftDist; int_fast8_t negShiftDist; int_fast64_t absZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ); sig0 = uiA0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x402F - exp; if ( shiftDist < 0 ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( shiftDist < -14 ) { if ( (uiA64 == UINT64_C( 0xC03E000000000000 )) && (sig0 < UINT64_C( 0x0002000000000000 )) ) { if ( exact && sig0 ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; } softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FFF) && (sig64 | sig0) ? i64_fromNaN : sign ? i64_fromNegOverflow : i64_fromPosOverflow; } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ sig64 |= UINT64_C( 0x0001000000000000 ); negShiftDist = -shiftDist; absZ = sig64<>(shiftDist & 63); if ( exact && (uint64_t) (sig0<>shiftDist; if ( exact && (sig0 || (absZ< #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast32_t f128_to_ui32( float128_t a, uint_fast8_t roundingMode, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t sig64; int_fast32_t shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ) | (uiA0 != 0); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ #if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) if ( (exp == 0x7FFF) && sig64 ) { #if (ui32_fromNaN == ui32_fromPosOverflow) sign = 0; #elif (ui32_fromNaN == ui32_fromNegOverflow) sign = 1; #else softfloat_raiseFlags( softfloat_flag_invalid ); return ui32_fromNaN; #endif } #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); shiftDist = 0x4023 - exp; if ( 0 < shiftDist ) { sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); } return softfloat_roundToUI32( sign, sig64, roundingMode, exact ); } ================================================ FILE: vp/src/vendor/softfloat/f128_to_ui32_r_minMag.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast32_t f128_to_ui32_r_minMag( float128_t a, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; int_fast32_t exp; uint_fast64_t sig64; int_fast32_t shiftDist; bool sign; uint_fast32_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ) | (uiA0 != 0); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x402F - exp; if ( 49 <= shiftDist ) { if ( exact && (exp | sig64) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF128UI64( uiA64 ); if ( sign || (shiftDist < 17) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FFF) && sig64 ? ui32_fromNaN : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig64 |= UINT64_C( 0x0001000000000000 ); z = sig64>>shiftDist; if ( exact && ((uint_fast64_t) z< #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast64_t f128_to_ui64( float128_t a, uint_fast8_t roundingMode, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t sig64, sig0; int_fast32_t shiftDist; struct uint128 sig128; struct uint64_extra sigExtra; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ); sig0 = uiA0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x402F - exp; if ( shiftDist <= 0 ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( shiftDist < -15 ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FFF) && (sig64 | sig0) ? ui64_fromNaN : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ sig64 |= UINT64_C( 0x0001000000000000 ); if ( shiftDist ) { sig128 = softfloat_shortShiftLeft128( sig64, sig0, -shiftDist ); sig64 = sig128.v64; sig0 = sig128.v0; } } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( exp ) sig64 |= UINT64_C( 0x0001000000000000 ); sigExtra = softfloat_shiftRightJam64Extra( sig64, sig0, shiftDist ); sig64 = sigExtra.v; sig0 = sigExtra.extra; } return softfloat_roundToUI64( sign, sig64, sig0, roundingMode, exact ); } ================================================ FILE: vp/src/vendor/softfloat/f128_to_ui64_r_minMag.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast64_t f128_to_ui64_r_minMag( float128_t a, bool exact ) { union ui128_f128 uA; uint_fast64_t uiA64, uiA0; bool sign; int_fast32_t exp; uint_fast64_t sig64, sig0; int_fast32_t shiftDist; int_fast8_t negShiftDist; uint_fast64_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA64 = uA.ui.v64; uiA0 = uA.ui.v0; sign = signF128UI64( uiA64 ); exp = expF128UI64( uiA64 ); sig64 = fracF128UI64( uiA64 ); sig0 = uiA0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x402F - exp; if ( shiftDist < 0 ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( sign || (shiftDist < -15) ) goto invalid; sig64 |= UINT64_C( 0x0001000000000000 ); negShiftDist = -shiftDist; z = sig64<>(shiftDist & 63); if ( exact && (uint64_t) (sig0<>shiftDist; if ( exact && (sig0 || (z< #include #include "platform.h" #include "internals.h" #include "softfloat.h" float16_t f16_add( float16_t a, float16_t b ) { union ui16_f16 uA; uint_fast16_t uiA; union ui16_f16 uB; uint_fast16_t uiB; #if ! defined INLINE_LEVEL || (INLINE_LEVEL < 1) float16_t (*magsFuncPtr)( uint_fast16_t, uint_fast16_t ); #endif uA.f = a; uiA = uA.ui; uB.f = b; uiB = uB.ui; #if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) if ( signF16UI( uiA ^ uiB ) ) { return softfloat_subMagsF16( uiA, uiB ); } else { return softfloat_addMagsF16( uiA, uiB ); } #else magsFuncPtr = signF16UI( uiA ^ uiB ) ? softfloat_subMagsF16 : softfloat_addMagsF16; return (*magsFuncPtr)( uiA, uiB ); #endif } ================================================ FILE: vp/src/vendor/softfloat/f16_div.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" extern const uint16_t softfloat_approxRecip_1k0s[]; extern const uint16_t softfloat_approxRecip_1k1s[]; float16_t f16_div( float16_t a, float16_t b ) { union ui16_f16 uA; uint_fast16_t uiA; bool signA; int_fast8_t expA; uint_fast16_t sigA; union ui16_f16 uB; uint_fast16_t uiB; bool signB; int_fast8_t expB; uint_fast16_t sigB; bool signZ; struct exp8_sig16 normExpSig; int_fast8_t expZ; #ifdef SOFTFLOAT_FAST_DIV32TO16 uint_fast32_t sig32A; uint_fast16_t sigZ; #else int index; uint16_t r0; uint_fast16_t sigZ, rem; #endif uint_fast16_t uiZ; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; signA = signF16UI( uiA ); expA = expF16UI( uiA ); sigA = fracF16UI( uiA ); uB.f = b; uiB = uB.ui; signB = signF16UI( uiB ); expB = expF16UI( uiB ); sigB = fracF16UI( uiB ); signZ = signA ^ signB; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x1F ) { if ( sigA ) goto propagateNaN; if ( expB == 0x1F ) { if ( sigB ) goto propagateNaN; goto invalid; } goto infinity; } if ( expB == 0x1F ) { if ( sigB ) goto propagateNaN; goto zero; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expB ) { if ( ! sigB ) { if ( ! (expA | sigA) ) goto invalid; softfloat_raiseFlags( softfloat_flag_infinite ); goto infinity; } normExpSig = softfloat_normSubnormalF16Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } if ( ! expA ) { if ( ! sigA ) goto zero; normExpSig = softfloat_normSubnormalF16Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA - expB + 0xE; sigA |= 0x0400; sigB |= 0x0400; #ifdef SOFTFLOAT_FAST_DIV32TO16 if ( sigA < sigB ) { --expZ; sig32A = (uint_fast32_t) sigA<<15; } else { sig32A = (uint_fast32_t) sigA<<14; } sigZ = sig32A / sigB; if ( ! (sigZ & 7) ) sigZ |= ((uint_fast32_t) sigB * sigZ != sig32A); #else if ( sigA < sigB ) { --expZ; sigA <<= 5; } else { sigA <<= 4; } index = sigB>>6 & 0xF; r0 = softfloat_approxRecip_1k0s[index] - (((uint_fast32_t) softfloat_approxRecip_1k1s[index] * (sigB & 0x3F)) >>10); sigZ = ((uint_fast32_t) sigA * r0)>>16; rem = (sigA<<10) - sigZ * sigB; sigZ += (rem * (uint_fast32_t) r0)>>26; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ ++sigZ; if ( ! (sigZ & 7) ) { sigZ &= ~1; rem = (sigA<<10) - sigZ * sigB; if ( rem & 0x8000 ) { sigZ -= 2; } else { if ( rem ) sigZ |= 1; } } #endif return softfloat_roundPackToF16( signZ, expZ, sigZ ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF16UI; goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infinity: uiZ = packToF16UI( signZ, 0x1F, 0 ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zero: uiZ = packToF16UI( signZ, 0, 0 ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f16_eq.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" bool f16_eq( float16_t a, float16_t b ) { union ui16_f16 uA; uint_fast16_t uiA; union ui16_f16 uB; uint_fast16_t uiB; uA.f = a; uiA = uA.ui; uB.f = b; uiB = uB.ui; if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { if ( softfloat_isSigNaNF16UI( uiA ) || softfloat_isSigNaNF16UI( uiB ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); } return false; } return (uiA == uiB) || ! (uint16_t) ((uiA | uiB)<<1); } ================================================ FILE: vp/src/vendor/softfloat/f16_eq_signaling.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" bool f16_eq_signaling( float16_t a, float16_t b ) { union ui16_f16 uA; uint_fast16_t uiA; union ui16_f16 uB; uint_fast16_t uiB; uA.f = a; uiA = uA.ui; uB.f = b; uiB = uB.ui; if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return false; } return (uiA == uiB) || ! (uint16_t) ((uiA | uiB)<<1); } ================================================ FILE: vp/src/vendor/softfloat/f16_isSignalingNaN.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" bool f16_isSignalingNaN( float16_t a ) { union ui16_f16 uA; uA.f = a; return softfloat_isSigNaNF16UI( uA.ui ); } ================================================ FILE: vp/src/vendor/softfloat/f16_le.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" bool f16_le( float16_t a, float16_t b ) { union ui16_f16 uA; uint_fast16_t uiA; union ui16_f16 uB; uint_fast16_t uiB; bool signA, signB; uA.f = a; uiA = uA.ui; uB.f = b; uiB = uB.ui; if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return false; } signA = signF16UI( uiA ); signB = signF16UI( uiB ); return (signA != signB) ? signA || ! (uint16_t) ((uiA | uiB)<<1) : (uiA == uiB) || (signA ^ (uiA < uiB)); } ================================================ FILE: vp/src/vendor/softfloat/f16_le_quiet.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" bool f16_le_quiet( float16_t a, float16_t b ) { union ui16_f16 uA; uint_fast16_t uiA; union ui16_f16 uB; uint_fast16_t uiB; bool signA, signB; uA.f = a; uiA = uA.ui; uB.f = b; uiB = uB.ui; if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { if ( softfloat_isSigNaNF16UI( uiA ) || softfloat_isSigNaNF16UI( uiB ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); } return false; } signA = signF16UI( uiA ); signB = signF16UI( uiB ); return (signA != signB) ? signA || ! (uint16_t) ((uiA | uiB)<<1) : (uiA == uiB) || (signA ^ (uiA < uiB)); } ================================================ FILE: vp/src/vendor/softfloat/f16_lt.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" bool f16_lt( float16_t a, float16_t b ) { union ui16_f16 uA; uint_fast16_t uiA; union ui16_f16 uB; uint_fast16_t uiB; bool signA, signB; uA.f = a; uiA = uA.ui; uB.f = b; uiB = uB.ui; if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return false; } signA = signF16UI( uiA ); signB = signF16UI( uiB ); return (signA != signB) ? signA && ((uint16_t) ((uiA | uiB)<<1) != 0) : (uiA != uiB) && (signA ^ (uiA < uiB)); } ================================================ FILE: vp/src/vendor/softfloat/f16_lt_quiet.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" bool f16_lt_quiet( float16_t a, float16_t b ) { union ui16_f16 uA; uint_fast16_t uiA; union ui16_f16 uB; uint_fast16_t uiB; bool signA, signB; uA.f = a; uiA = uA.ui; uB.f = b; uiB = uB.ui; if ( isNaNF16UI( uiA ) || isNaNF16UI( uiB ) ) { if ( softfloat_isSigNaNF16UI( uiA ) || softfloat_isSigNaNF16UI( uiB ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); } return false; } signA = signF16UI( uiA ); signB = signF16UI( uiB ); return (signA != signB) ? signA && ((uint16_t) ((uiA | uiB)<<1) != 0) : (uiA != uiB) && (signA ^ (uiA < uiB)); } ================================================ FILE: vp/src/vendor/softfloat/f16_mul.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float16_t f16_mul( float16_t a, float16_t b ) { union ui16_f16 uA; uint_fast16_t uiA; bool signA; int_fast8_t expA; uint_fast16_t sigA; union ui16_f16 uB; uint_fast16_t uiB; bool signB; int_fast8_t expB; uint_fast16_t sigB; bool signZ; uint_fast16_t magBits; struct exp8_sig16 normExpSig; int_fast8_t expZ; uint_fast32_t sig32Z; uint_fast16_t sigZ, uiZ; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; signA = signF16UI( uiA ); expA = expF16UI( uiA ); sigA = fracF16UI( uiA ); uB.f = b; uiB = uB.ui; signB = signF16UI( uiB ); expB = expF16UI( uiB ); sigB = fracF16UI( uiB ); signZ = signA ^ signB; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x1F ) { if ( sigA || ((expB == 0x1F) && sigB) ) goto propagateNaN; magBits = expB | sigB; goto infArg; } if ( expB == 0x1F ) { if ( sigB ) goto propagateNaN; magBits = expA | sigA; goto infArg; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) { if ( ! sigA ) goto zero; normExpSig = softfloat_normSubnormalF16Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) { if ( ! sigB ) goto zero; normExpSig = softfloat_normSubnormalF16Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0xF; sigA = (sigA | 0x0400)<<4; sigB = (sigB | 0x0400)<<5; sig32Z = (uint_fast32_t) sigA * sigB; sigZ = sig32Z>>16; if ( sig32Z & 0xFFFF ) sigZ |= 1; if ( sigZ < 0x4000 ) { --expZ; sigZ <<= 1; } return softfloat_roundPackToF16( signZ, expZ, sigZ ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infArg: if ( ! magBits ) { softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF16UI; } else { uiZ = packToF16UI( signZ, 0x1F, 0 ); } goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zero: uiZ = packToF16UI( signZ, 0, 0 ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f16_mulAdd.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "internals.h" #include "softfloat.h" float16_t f16_mulAdd( float16_t a, float16_t b, float16_t c ) { union ui16_f16 uA; uint_fast16_t uiA; union ui16_f16 uB; uint_fast16_t uiB; union ui16_f16 uC; uint_fast16_t uiC; uA.f = a; uiA = uA.ui; uB.f = b; uiB = uB.ui; uC.f = c; uiC = uC.ui; return softfloat_mulAddF16( uiA, uiB, uiC, 0 ); } ================================================ FILE: vp/src/vendor/softfloat/f16_rem.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float16_t f16_rem( float16_t a, float16_t b ) { union ui16_f16 uA; uint_fast16_t uiA; bool signA; int_fast8_t expA; uint_fast16_t sigA; union ui16_f16 uB; uint_fast16_t uiB; int_fast8_t expB; uint_fast16_t sigB; struct exp8_sig16 normExpSig; uint16_t rem; int_fast8_t expDiff; uint_fast16_t q; uint32_t recip32, q32; uint16_t altRem, meanRem; bool signRem; uint_fast16_t uiZ; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; signA = signF16UI( uiA ); expA = expF16UI( uiA ); sigA = fracF16UI( uiA ); uB.f = b; uiB = uB.ui; expB = expF16UI( uiB ); sigB = fracF16UI( uiB ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x1F ) { if ( sigA || ((expB == 0x1F) && sigB) ) goto propagateNaN; goto invalid; } if ( expB == 0x1F ) { if ( sigB ) goto propagateNaN; return a; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expB ) { if ( ! sigB ) goto invalid; normExpSig = softfloat_normSubnormalF16Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } if ( ! expA ) { if ( ! sigA ) return a; normExpSig = softfloat_normSubnormalF16Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ rem = sigA | 0x0400; sigB |= 0x0400; expDiff = expA - expB; if ( expDiff < 1 ) { if ( expDiff < -1 ) return a; sigB <<= 3; if ( expDiff ) { rem <<= 2; q = 0; } else { rem <<= 3; q = (sigB <= rem); if ( q ) rem -= sigB; } } else { recip32 = softfloat_approxRecip32_1( (uint_fast32_t) sigB<<21 ); /*-------------------------------------------------------------------- | Changing the shift of `rem' here requires also changing the initial | subtraction from `expDiff'. *--------------------------------------------------------------------*/ rem <<= 4; expDiff -= 31; /*-------------------------------------------------------------------- | The scale of `sigB' affects how many bits are obtained during each | cycle of the loop. Currently this is 29 bits per loop iteration, | which is believed to be the maximum possible. *--------------------------------------------------------------------*/ sigB <<= 3; for (;;) { q32 = (rem * (uint_fast64_t) recip32)>>16; if ( expDiff < 0 ) break; rem = -((uint_fast16_t) q32 * sigB); expDiff -= 29; } /*-------------------------------------------------------------------- | (`expDiff' cannot be less than -30 here.) *--------------------------------------------------------------------*/ q32 >>= ~expDiff & 31; q = q32; rem = (rem<<(expDiff + 30)) - q * sigB; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ do { altRem = rem; ++q; rem -= sigB; } while ( ! (rem & 0x8000) ); meanRem = rem + altRem; if ( (meanRem & 0x8000) || (! meanRem && (q & 1)) ) rem = altRem; signRem = signA; if ( 0x8000 <= rem ) { signRem = ! signRem; rem = -rem; } return softfloat_normRoundPackToF16( signRem, expB, rem ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); goto uiZ; invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF16UI; uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f16_roundToInt.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float16_t f16_roundToInt( float16_t a, uint_fast8_t roundingMode, bool exact ) { union ui16_f16 uA; uint_fast16_t uiA; int_fast8_t exp; uint_fast16_t uiZ, lastBitMask, roundBitsMask; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF16UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp <= 0xE ) { if ( ! (uint16_t) (uiA<<1) ) return a; if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; uiZ = uiA & packToF16UI( 1, 0, 0 ); switch ( roundingMode ) { case softfloat_round_near_even: if ( ! fracF16UI( uiA ) ) break; case softfloat_round_near_maxMag: if ( exp == 0xE ) uiZ |= packToF16UI( 0, 0xF, 0 ); break; case softfloat_round_min: if ( uiZ ) uiZ = packToF16UI( 1, 0xF, 0 ); break; case softfloat_round_max: if ( ! uiZ ) uiZ = packToF16UI( 0, 0xF, 0 ); break; } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x19 <= exp ) { if ( (exp == 0x1F) && fracF16UI( uiA ) ) { uiZ = softfloat_propagateNaNF16UI( uiA, 0 ); goto uiZ; } return a; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ = uiA; lastBitMask = (uint_fast16_t) 1<<(0x19 - exp); roundBitsMask = lastBitMask - 1; if ( roundingMode == softfloat_round_near_maxMag ) { uiZ += lastBitMask>>1; } else if ( roundingMode == softfloat_round_near_even ) { uiZ += lastBitMask>>1; if ( ! (uiZ & roundBitsMask) ) uiZ &= ~lastBitMask; } else if ( roundingMode == (signF16UI( uiZ ) ? softfloat_round_min : softfloat_round_max) ) { uiZ += roundBitsMask; } uiZ &= ~roundBitsMask; if ( exact && (uiZ != uiA) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f16_sqrt.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" extern const uint16_t softfloat_approxRecipSqrt_1k0s[]; extern const uint16_t softfloat_approxRecipSqrt_1k1s[]; float16_t f16_sqrt( float16_t a ) { union ui16_f16 uA; uint_fast16_t uiA; bool signA; int_fast8_t expA; uint_fast16_t sigA, uiZ; struct exp8_sig16 normExpSig; int_fast8_t expZ; int index; uint_fast16_t r0; uint_fast32_t ESqrR0; uint16_t sigma0; uint_fast16_t recipSqrt16, sigZ, shiftedSigZ; uint16_t negRem; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; signA = signF16UI( uiA ); expA = expF16UI( uiA ); sigA = fracF16UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x1F ) { if ( sigA ) { uiZ = softfloat_propagateNaNF16UI( 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_normSubnormalF16Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = ((expA - 0xF)>>1) + 0xE; expA &= 1; sigA |= 0x0400; index = (sigA>>6 & 0xE) + expA; r0 = softfloat_approxRecipSqrt_1k0s[index] - (((uint_fast32_t) softfloat_approxRecipSqrt_1k1s[index] * (sigA & 0x7F)) >>11); ESqrR0 = ((uint_fast32_t) r0 * r0)>>1; if ( expA ) ESqrR0 >>= 1; sigma0 = ~(uint_fast16_t) ((ESqrR0 * sigA)>>16); recipSqrt16 = r0 + (((uint_fast32_t) r0 * sigma0)>>25); if ( ! (recipSqrt16 & 0x8000) ) recipSqrt16 = 0x8000; sigZ = ((uint_fast32_t) (sigA<<5) * recipSqrt16)>>16; if ( expA ) sigZ >>= 1; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ ++sigZ; if ( ! (sigZ & 7) ) { shiftedSigZ = sigZ>>1; negRem = shiftedSigZ * shiftedSigZ; sigZ &= ~1; if ( negRem & 0x8000 ) { sigZ |= 1; } else { if ( negRem ) --sigZ; } } return softfloat_roundPackToF16( 0, expZ, sigZ ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF16UI; uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f16_sub.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" float16_t f16_sub( float16_t a, float16_t b ) { union ui16_f16 uA; uint_fast16_t uiA; union ui16_f16 uB; uint_fast16_t uiB; #if ! defined INLINE_LEVEL || (INLINE_LEVEL < 1) float16_t (*magsFuncPtr)( uint_fast16_t, uint_fast16_t ); #endif uA.f = a; uiA = uA.ui; uB.f = b; uiB = uB.ui; #if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) if ( signF16UI( uiA ^ uiB ) ) { return softfloat_addMagsF16( uiA, uiB ); } else { return softfloat_subMagsF16( uiA, uiB ); } #else magsFuncPtr = signF16UI( uiA ^ uiB ) ? softfloat_addMagsF16 : softfloat_subMagsF16; return (*magsFuncPtr)( uiA, uiB ); #endif } ================================================ FILE: vp/src/vendor/softfloat/f16_to_f128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float128_t f16_to_f128( float16_t a ) { union ui16_f16 uA; uint_fast16_t uiA; bool sign; int_fast8_t exp; uint_fast16_t frac; struct commonNaN commonNaN; struct uint128 uiZ; struct exp8_sig16 normExpSig; union ui128_f128 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF16UI( uiA ); exp = expF16UI( uiA ); frac = fracF16UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x1F ) { if ( frac ) { softfloat_f16UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToF128UI( &commonNaN ); } else { uiZ.v64 = packToF128UI64( sign, 0x7FFF, 0 ); uiZ.v0 = 0; } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! exp ) { if ( ! frac ) { uiZ.v64 = packToF128UI64( sign, 0, 0 ); uiZ.v0 = 0; goto uiZ; } normExpSig = softfloat_normSubnormalF16Sig( frac ); exp = normExpSig.exp - 1; frac = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ.v64 = packToF128UI64( sign, exp + 0x3FF0, (uint_fast64_t) frac<<38 ); uiZ.v0 = 0; uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f16_to_f32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float32_t f16_to_f32( float16_t a ) { union ui16_f16 uA; uint_fast16_t uiA; bool sign; int_fast8_t exp; uint_fast16_t frac; struct commonNaN commonNaN; uint_fast32_t uiZ; struct exp8_sig16 normExpSig; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF16UI( uiA ); exp = expF16UI( uiA ); frac = fracF16UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x1F ) { if ( frac ) { softfloat_f16UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToF32UI( &commonNaN ); } else { uiZ = packToF32UI( sign, 0xFF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! exp ) { if ( ! frac ) { uiZ = packToF32UI( sign, 0, 0 ); goto uiZ; } normExpSig = softfloat_normSubnormalF16Sig( frac ); exp = normExpSig.exp - 1; frac = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ = packToF32UI( sign, exp + 0x70, (uint_fast32_t) frac<<13 ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f16_to_f64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float64_t f16_to_f64( float16_t a ) { union ui16_f16 uA; uint_fast16_t uiA; bool sign; int_fast8_t exp; uint_fast16_t frac; struct commonNaN commonNaN; uint_fast64_t uiZ; struct exp8_sig16 normExpSig; union ui64_f64 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF16UI( uiA ); exp = expF16UI( uiA ); frac = fracF16UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x1F ) { if ( frac ) { softfloat_f16UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToF64UI( &commonNaN ); } else { uiZ = packToF64UI( sign, 0x7FF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! exp ) { if ( ! frac ) { uiZ = packToF64UI( sign, 0, 0 ); goto uiZ; } normExpSig = softfloat_normSubnormalF16Sig( frac ); exp = normExpSig.exp - 1; frac = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ = packToF64UI( sign, exp + 0x3F0, (uint_fast64_t) frac<<42 ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f16_to_i32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast32_t f16_to_i32( float16_t a, uint_fast8_t roundingMode, bool exact ) { union ui16_f16 uA; uint_fast16_t uiA; bool sign; int_fast8_t exp; uint_fast16_t frac; int_fast32_t sig32; int_fast8_t shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF16UI( uiA ); exp = expF16UI( uiA ); frac = fracF16UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x1F ) { softfloat_raiseFlags( softfloat_flag_invalid ); return frac ? i32_fromNaN : sign ? i32_fromNegOverflow : i32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig32 = frac; if ( exp ) { sig32 |= 0x0400; shiftDist = exp - 0x19; if ( 0 <= shiftDist ) { sig32 <<= shiftDist; return sign ? -sig32 : sig32; } shiftDist = exp - 0x0D; if ( 0 < shiftDist ) sig32 <<= shiftDist; } return softfloat_roundToI32( sign, (uint_fast32_t) sig32, roundingMode, exact ); } ================================================ FILE: vp/src/vendor/softfloat/f16_to_i32_r_minMag.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast32_t f16_to_i32_r_minMag( float16_t a, bool exact ) { union ui16_f16 uA; uint_fast16_t uiA; int_fast8_t exp; uint_fast16_t frac; int_fast8_t shiftDist; bool sign; int_fast32_t alignedSig; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF16UI( uiA ); frac = fracF16UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = exp - 0x0F; if ( shiftDist < 0 ) { if ( exact && (exp | frac) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF16UI( uiA ); if ( exp == 0x1F ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x1F) && frac ? i32_fromNaN : sign ? i32_fromNegOverflow : i32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ alignedSig = (int_fast32_t) (frac | 0x0400)<>= 10; return sign ? -alignedSig : alignedSig; } ================================================ FILE: vp/src/vendor/softfloat/f16_to_i64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast64_t f16_to_i64( float16_t a, uint_fast8_t roundingMode, bool exact ) { union ui16_f16 uA; uint_fast16_t uiA; bool sign; int_fast8_t exp; uint_fast16_t frac; int_fast32_t sig32; int_fast8_t shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF16UI( uiA ); exp = expF16UI( uiA ); frac = fracF16UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x1F ) { softfloat_raiseFlags( softfloat_flag_invalid ); return frac ? i64_fromNaN : sign ? i64_fromNegOverflow : i64_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig32 = frac; if ( exp ) { sig32 |= 0x0400; shiftDist = exp - 0x19; if ( 0 <= shiftDist ) { sig32 <<= shiftDist; return sign ? -sig32 : sig32; } shiftDist = exp - 0x0D; if ( 0 < shiftDist ) sig32 <<= shiftDist; } return softfloat_roundToI32( sign, (uint_fast32_t) sig32, roundingMode, exact ); } ================================================ FILE: vp/src/vendor/softfloat/f16_to_i64_r_minMag.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast64_t f16_to_i64_r_minMag( float16_t a, bool exact ) { union ui16_f16 uA; uint_fast16_t uiA; int_fast8_t exp; uint_fast16_t frac; int_fast8_t shiftDist; bool sign; int_fast32_t alignedSig; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF16UI( uiA ); frac = fracF16UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = exp - 0x0F; if ( shiftDist < 0 ) { if ( exact && (exp | frac) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF16UI( uiA ); if ( exp == 0x1F ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x1F) && frac ? i64_fromNaN : sign ? i64_fromNegOverflow : i64_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ alignedSig = (int_fast32_t) (frac | 0x0400)<>= 10; return sign ? -alignedSig : alignedSig; } ================================================ FILE: vp/src/vendor/softfloat/f16_to_ui32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast32_t f16_to_ui32( float16_t a, uint_fast8_t roundingMode, bool exact ) { union ui16_f16 uA; uint_fast16_t uiA; bool sign; int_fast8_t exp; uint_fast16_t frac; uint_fast32_t sig32; int_fast8_t shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF16UI( uiA ); exp = expF16UI( uiA ); frac = fracF16UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x1F ) { softfloat_raiseFlags( softfloat_flag_invalid ); return frac ? ui32_fromNaN : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig32 = frac; if ( exp ) { sig32 |= 0x0400; shiftDist = exp - 0x19; if ( (0 <= shiftDist) && ! sign ) { return sig32< #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast32_t f16_to_ui32_r_minMag( float16_t a, bool exact ) { union ui16_f16 uA; uint_fast16_t uiA; int_fast8_t exp; uint_fast16_t frac; int_fast8_t shiftDist; bool sign; uint_fast32_t alignedSig; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF16UI( uiA ); frac = fracF16UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = exp - 0x0F; if ( shiftDist < 0 ) { if ( exact && (exp | frac) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF16UI( uiA ); if ( sign || (exp == 0x1F) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x1F) && frac ? ui32_fromNaN : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ alignedSig = (uint_fast32_t) (frac | 0x0400)<>10; } ================================================ FILE: vp/src/vendor/softfloat/f16_to_ui64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast64_t f16_to_ui64( float16_t a, uint_fast8_t roundingMode, bool exact ) { union ui16_f16 uA; uint_fast16_t uiA; bool sign; int_fast8_t exp; uint_fast16_t frac; uint_fast32_t sig32; int_fast8_t shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF16UI( uiA ); exp = expF16UI( uiA ); frac = fracF16UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x1F ) { softfloat_raiseFlags( softfloat_flag_invalid ); return frac ? ui64_fromNaN : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig32 = frac; if ( exp ) { sig32 |= 0x0400; shiftDist = exp - 0x19; if ( (0 <= shiftDist) && ! sign ) { return sig32< #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast64_t f16_to_ui64_r_minMag( float16_t a, bool exact ) { union ui16_f16 uA; uint_fast16_t uiA; int_fast8_t exp; uint_fast16_t frac; int_fast8_t shiftDist; bool sign; uint_fast32_t alignedSig; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF16UI( uiA ); frac = fracF16UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = exp - 0x0F; if ( shiftDist < 0 ) { if ( exact && (exp | frac) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF16UI( uiA ); if ( sign || (exp == 0x1F) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x1F) && frac ? ui64_fromNaN : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ alignedSig = (uint_fast32_t) (frac | 0x0400)<>10; } ================================================ FILE: vp/src/vendor/softfloat/f32_add.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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; union ui32_f32 uB; uint_fast32_t uiB; #if ! defined INLINE_LEVEL || (INLINE_LEVEL < 1) float32_t (*magsFuncPtr)( uint_fast32_t, uint_fast32_t ); #endif uA.f = a; uiA = uA.ui; uB.f = b; uiB = uB.ui; #if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) if ( signF32UI( uiA ^ uiB ) ) { return softfloat_subMagsF32( uiA, uiB ); } else { return softfloat_addMagsF32( uiA, uiB ); } #else magsFuncPtr = signF32UI( uiA ^ uiB ) ? softfloat_subMagsF32 : softfloat_addMagsF32; return (*magsFuncPtr)( uiA, uiB ); #endif } ================================================ FILE: vp/src/vendor/softfloat/f32_classify.c ================================================ #include #include #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 ); bool fracZero = fracF32UI( uiA ) == 0; bool isNaN = isNaNF32UI( uiA ); bool isSNaN = softfloat_isSigNaNF32UI( uiA ); return ( sign && infOrNaN && fracZero ) << 0 | ( sign && !infOrNaN && !subnormalOrZero ) << 1 | ( sign && subnormalOrZero && !fracZero ) << 2 | ( sign && subnormalOrZero && fracZero ) << 3 | ( !sign && infOrNaN && fracZero ) << 7 | ( !sign && !infOrNaN && !subnormalOrZero ) << 6 | ( !sign && subnormalOrZero && !fracZero ) << 5 | ( !sign && subnormalOrZero && fracZero ) << 4 | ( isNaN && isSNaN ) << 8 | ( isNaN && !isSNaN ) << 9; } ================================================ FILE: vp/src/vendor/softfloat/f32_div.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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; #ifdef SOFTFLOAT_FAST_DIV64TO32 uint_fast64_t sig64A; uint_fast32_t sigZ; #else uint_fast32_t sigZ; uint_fast64_t rem; #endif 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_infinite ); 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 + 0x7E; sigA |= 0x00800000; sigB |= 0x00800000; #ifdef SOFTFLOAT_FAST_DIV64TO32 if ( sigA < sigB ) { --expZ; sig64A = (uint_fast64_t) sigA<<31; } else { sig64A = (uint_fast64_t) sigA<<30; } sigZ = sig64A / sigB; if ( ! (sigZ & 0x3F) ) sigZ |= ((uint_fast64_t) sigB * sigZ != sig64A); #else if ( sigA < sigB ) { --expZ; sigA <<= 8; } else { sigA <<= 7; } sigB <<= 8; sigZ = ((uint_fast64_t) sigA * softfloat_approxRecip32_1( sigB ))>>32; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sigZ += 2; if ( (sigZ & 0x3F) < 2 ) { sigZ &= ~3; #ifdef SOFTFLOAT_FAST_INT64 rem = ((uint_fast64_t) sigA<<31) - (uint_fast64_t) sigZ * sigB; #else rem = ((uint_fast64_t) sigA<<32) - (uint_fast64_t) (sigZ<<1) * sigB; #endif if ( rem & UINT64_C( 0x8000000000000000 ) ) { sigZ -= 4; } else { if ( rem ) sigZ |= 1; } } #endif 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; } ================================================ FILE: vp/src/vendor/softfloat/f32_eq.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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 ( isNaNF32UI( uiA ) || isNaNF32UI( uiB ) ) { if ( softfloat_isSigNaNF32UI( uiA ) || softfloat_isSigNaNF32UI( uiB ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); } return false; } return (uiA == uiB) || ! (uint32_t) ((uiA | uiB)<<1); } ================================================ FILE: vp/src/vendor/softfloat/f32_eq_signaling.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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 ( isNaNF32UI( uiA ) || isNaNF32UI( uiB ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return false; } return (uiA == uiB) || ! (uint32_t) ((uiA | uiB)<<1); } ================================================ FILE: vp/src/vendor/softfloat/f32_isSignalingNaN.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #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 ); } ================================================ FILE: vp/src/vendor/softfloat/f32_le.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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 ( isNaNF32UI( uiA ) || isNaNF32UI( 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)); } ================================================ FILE: vp/src/vendor/softfloat/f32_le_quiet.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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 ( isNaNF32UI( uiA ) || isNaNF32UI( 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)); } ================================================ FILE: vp/src/vendor/softfloat/f32_lt.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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 ( isNaNF32UI( uiA ) || isNaNF32UI( 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)); } ================================================ FILE: vp/src/vendor/softfloat/f32_lt_quiet.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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 ( isNaNF32UI( uiA ) || isNaNF32UI( 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)); } ================================================ FILE: vp/src/vendor/softfloat/f32_mul.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.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_shortShiftRightJam64( (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; } ================================================ FILE: vp/src/vendor/softfloat/f32_mulAdd.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #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( uiA, uiB, uiC, 0 ); } ================================================ FILE: vp/src/vendor/softfloat/f32_rem.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.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; int_fast16_t expB; uint_fast32_t sigB; struct exp16_sig32 normExpSig; uint32_t rem; int_fast16_t expDiff; uint32_t q, recip32, altRem, meanRem; bool signRem; 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; 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; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ rem = sigA | 0x00800000; sigB |= 0x00800000; expDiff = expA - expB; if ( expDiff < 1 ) { if ( expDiff < -1 ) return a; sigB <<= 6; if ( expDiff ) { rem <<= 5; q = 0; } else { rem <<= 6; q = (sigB <= rem); if ( q ) rem -= sigB; } } else { recip32 = softfloat_approxRecip32_1( sigB<<8 ); /*-------------------------------------------------------------------- | Changing the shift of `rem' here requires also changing the initial | subtraction from `expDiff'. *--------------------------------------------------------------------*/ rem <<= 7; expDiff -= 31; /*-------------------------------------------------------------------- | The scale of `sigB' affects how many bits are obtained during each | cycle of the loop. Currently this is 29 bits per loop iteration, | which is believed to be the maximum possible. *--------------------------------------------------------------------*/ sigB <<= 6; for (;;) { q = (rem * (uint_fast64_t) recip32)>>32; if ( expDiff < 0 ) break; rem = -(q * (uint32_t) sigB); expDiff -= 29; } /*-------------------------------------------------------------------- | (`expDiff' cannot be less than -30 here.) *--------------------------------------------------------------------*/ q >>= ~expDiff & 31; rem = (rem<<(expDiff + 30)) - q * (uint32_t) sigB; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ do { altRem = rem; ++q; rem -= sigB; } while ( ! (rem & 0x80000000) ); meanRem = rem + altRem; if ( (meanRem & 0x80000000) || (! meanRem && (q & 1)) ) rem = altRem; signRem = signA; if ( 0x80000000 <= rem ) { signRem = ! signRem; rem = -rem; } return softfloat_normRoundPackToF32( signRem, expB, rem ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF32UI( uiA, uiB ); goto uiZ; invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF32UI; uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f32_roundToInt.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float32_t f32_roundToInt( float32_t a, uint_fast8_t roundingMode, bool exact ) { union ui32_f32 uA; uint_fast32_t uiA; int_fast16_t exp; uint_fast32_t uiZ, lastBitMask, roundBitsMask; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp <= 0x7E ) { if ( ! (uint32_t) (uiA<<1) ) return a; if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; uiZ = uiA & packToF32UI( 1, 0, 0 ); switch ( roundingMode ) { case softfloat_round_near_even: if ( ! fracF32UI( uiA ) ) break; case softfloat_round_near_maxMag: if ( exp == 0x7E ) uiZ |= packToF32UI( 0, 0x7F, 0 ); break; case softfloat_round_min: if ( uiZ ) uiZ = packToF32UI( 1, 0x7F, 0 ); break; case softfloat_round_max: if ( ! uiZ ) uiZ = packToF32UI( 0, 0x7F, 0 ); break; } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x96 <= exp ) { if ( (exp == 0xFF) && fracF32UI( uiA ) ) { uiZ = softfloat_propagateNaNF32UI( uiA, 0 ); goto uiZ; } return a; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ = uiA; lastBitMask = (uint_fast32_t) 1<<(0x96 - exp); roundBitsMask = lastBitMask - 1; if ( roundingMode == softfloat_round_near_maxMag ) { uiZ += lastBitMask>>1; } else if ( roundingMode == softfloat_round_near_even ) { uiZ += lastBitMask>>1; if ( ! (uiZ & roundBitsMask) ) uiZ &= ~lastBitMask; } else if ( roundingMode == (signF32UI( uiZ ) ? softfloat_round_min : softfloat_round_max) ) { uiZ += roundBitsMask; } uiZ &= ~roundBitsMask; if ( exact && (uiZ != uiA) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f32_sqrt.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.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, shiftedSigZ; uint32_t negRem; 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; expA &= 1; sigA = (sigA | 0x00800000)<<8; sigZ = ((uint_fast64_t) sigA * softfloat_approxRecipSqrt32_1( expA, sigA )) >>32; if ( expA ) sigZ >>= 1; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sigZ += 2; if ( (sigZ & 0x3F) < 2 ) { shiftedSigZ = sigZ>>2; negRem = shiftedSigZ * shiftedSigZ; sigZ &= ~3; if ( negRem & 0x80000000 ) { sigZ |= 1; } else { if ( negRem ) --sigZ; } } return softfloat_roundPackToF32( 0, expZ, sigZ ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF32UI; uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f32_sub.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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; union ui32_f32 uB; uint_fast32_t uiB; #if ! defined INLINE_LEVEL || (INLINE_LEVEL < 1) float32_t (*magsFuncPtr)( uint_fast32_t, uint_fast32_t ); #endif uA.f = a; uiA = uA.ui; uB.f = b; uiB = uB.ui; #if defined INLINE_LEVEL && (1 <= INLINE_LEVEL) if ( signF32UI( uiA ^ uiB ) ) { return softfloat_addMagsF32( uiA, uiB ); } else { return softfloat_subMagsF32( uiA, uiB ); } #else magsFuncPtr = signF32UI( uiA ^ uiB ) ? softfloat_addMagsF32 : softfloat_subMagsF32; return (*magsFuncPtr)( uiA, uiB ); #endif } ================================================ FILE: vp/src/vendor/softfloat/f32_to_f128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float128_t f32_to_f128( float32_t a ) { union ui32_f32 uA; uint_fast32_t uiA; bool sign; int_fast16_t exp; uint_fast32_t frac; struct commonNaN commonNaN; struct uint128 uiZ; struct exp16_sig32 normExpSig; union ui128_f128 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF32UI( uiA ); exp = expF32UI( uiA ); frac = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0xFF ) { if ( frac ) { softfloat_f32UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToF128UI( &commonNaN ); } else { uiZ.v64 = packToF128UI64( sign, 0x7FFF, 0 ); uiZ.v0 = 0; } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! exp ) { if ( ! frac ) { uiZ.v64 = packToF128UI64( sign, 0, 0 ); uiZ.v0 = 0; goto uiZ; } normExpSig = softfloat_normSubnormalF32Sig( frac ); exp = normExpSig.exp - 1; frac = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ.v64 = packToF128UI64( sign, exp + 0x3F80, (uint_fast64_t) frac<<25 ); uiZ.v0 = 0; uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f32_to_f16.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float16_t f32_to_f16( float32_t a ) { union ui32_f32 uA; uint_fast32_t uiA; bool sign; int_fast16_t exp; uint_fast32_t frac; struct commonNaN commonNaN; uint_fast16_t uiZ, frac16; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF32UI( uiA ); exp = expF32UI( uiA ); frac = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0xFF ) { if ( frac ) { softfloat_f32UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToF16UI( &commonNaN ); } else { uiZ = packToF16UI( sign, 0x1F, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ frac16 = frac>>9 | ((frac & 0x1FF) != 0); if ( ! (exp | frac16) ) { uiZ = packToF16UI( sign, 0, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ return softfloat_roundPackToF16( sign, exp - 0x71, frac16 | 0x4000 ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f32_to_f64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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 frac; struct commonNaN commonNaN; uint_fast64_t uiZ; struct exp16_sig32 normExpSig; union ui64_f64 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF32UI( uiA ); exp = expF32UI( uiA ); frac = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0xFF ) { if ( frac ) { softfloat_f32UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToF64UI( &commonNaN ); } else { uiZ = packToF64UI( sign, 0x7FF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! exp ) { if ( ! frac ) { uiZ = packToF64UI( sign, 0, 0 ); goto uiZ; } normExpSig = softfloat_normSubnormalF32Sig( frac ); exp = normExpSig.exp - 1; frac = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ = packToF64UI( sign, exp + 0x380, (uint_fast64_t) frac<<29 ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f32_to_i32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast32_t f32_to_i32( float32_t a, uint_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 shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF32UI( uiA ); exp = expF32UI( uiA ); sig = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ #if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) if ( (exp == 0xFF) && sig ) { #if (i32_fromNaN == i32_fromPosOverflow) sign = 0; #elif (i32_fromNaN == i32_fromNegOverflow) sign = 1; #else softfloat_raiseFlags( softfloat_flag_invalid ); return i32_fromNaN; #endif } #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig |= 0x00800000; sig64 = (uint_fast64_t) sig<<32; shiftDist = 0xAA - exp; if ( 0 < shiftDist ) sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); return softfloat_roundToI32( sign, sig64, roundingMode, exact ); } ================================================ FILE: vp/src/vendor/softfloat/f32_to_i32_r_minMag.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.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; int_fast16_t shiftDist; bool sign; int_fast32_t absZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF32UI( uiA ); sig = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x9E - exp; if ( 32 <= shiftDist ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF32UI( uiA ); if ( shiftDist <= 0 ) { if ( uiA == packToF32UI( 1, 0x9E, 0 ) ) return -0x7FFFFFFF - 1; softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0xFF) && sig ? i32_fromNaN : sign ? i32_fromNegOverflow : i32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig = (sig | 0x00800000)<<8; absZ = sig>>shiftDist; if ( exact && ((uint_fast32_t) absZ< #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast64_t f32_to_i64( float32_t a, uint_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 shiftDist; #ifdef SOFTFLOAT_FAST_INT64 uint_fast64_t sig64, extra; struct uint64_extra sig64Extra; #else uint32_t extSig[3]; #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF32UI( uiA ); exp = expF32UI( uiA ); sig = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0xBE - exp; if ( shiftDist < 0 ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0xFF) && sig ? i64_fromNaN : sign ? i64_fromNegOverflow : i64_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig |= 0x00800000; #ifdef SOFTFLOAT_FAST_INT64 sig64 = (uint_fast64_t) sig<<40; extra = 0; if ( shiftDist ) { sig64Extra = softfloat_shiftRightJam64Extra( sig64, 0, shiftDist ); sig64 = sig64Extra.v; extra = sig64Extra.extra; } return softfloat_roundToI64( sign, sig64, extra, roundingMode, exact ); #else extSig[indexWord( 3, 2 )] = sig<<8; extSig[indexWord( 3, 1 )] = 0; extSig[indexWord( 3, 0 )] = 0; if ( shiftDist ) softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); return softfloat_roundMToI64( sign, extSig, roundingMode, exact ); #endif } ================================================ FILE: vp/src/vendor/softfloat/f32_to_i64_r_minMag.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.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; int_fast16_t shiftDist; bool sign; uint_fast64_t sig64; int_fast64_t absZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF32UI( uiA ); sig = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0xBE - exp; if ( 64 <= shiftDist ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF32UI( uiA ); if ( shiftDist <= 0 ) { if ( uiA == packToF32UI( 1, 0xBE, 0 ) ) { return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; } softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0xFF) && sig ? i64_fromNaN : sign ? i64_fromNegOverflow : i64_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig |= 0x00800000; sig64 = (uint_fast64_t) sig<<40; absZ = sig64>>shiftDist; shiftDist = 40 - shiftDist; if ( exact && (shiftDist < 0) && (uint32_t) (sig<<(shiftDist & 31)) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return sign ? -absZ : absZ; } ================================================ FILE: vp/src/vendor/softfloat/f32_to_ui32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast32_t f32_to_ui32( float32_t a, uint_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 shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF32UI( uiA ); exp = expF32UI( uiA ); sig = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ #if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) if ( (exp == 0xFF) && sig ) { #if (ui32_fromNaN == ui32_fromPosOverflow) sign = 0; #elif (ui32_fromNaN == ui32_fromNegOverflow) sign = 1; #else softfloat_raiseFlags( softfloat_flag_invalid ); return ui32_fromNaN; #endif } #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig |= 0x00800000; sig64 = (uint_fast64_t) sig<<32; shiftDist = 0xAA - exp; if ( 0 < shiftDist ) sig64 = softfloat_shiftRightJam64( sig64, shiftDist ); return softfloat_roundToUI32( sign, sig64, roundingMode, exact ); } ================================================ FILE: vp/src/vendor/softfloat/f32_to_ui32_r_minMag.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.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 shiftDist; bool sign; uint_fast32_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF32UI( uiA ); sig = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x9E - exp; if ( 32 <= shiftDist ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF32UI( uiA ); if ( sign || (shiftDist < 0) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0xFF) && sig ? ui32_fromNaN : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig = (sig | 0x00800000)<<8; z = sig>>shiftDist; if ( exact && (z< #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast64_t f32_to_ui64( float32_t a, uint_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 shiftDist; #ifdef SOFTFLOAT_FAST_INT64 uint_fast64_t sig64, extra; struct uint64_extra sig64Extra; #else uint32_t extSig[3]; #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF32UI( uiA ); exp = expF32UI( uiA ); sig = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0xBE - exp; if ( shiftDist < 0 ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0xFF) && sig ? ui64_fromNaN : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig |= 0x00800000; #ifdef SOFTFLOAT_FAST_INT64 sig64 = (uint_fast64_t) sig<<40; extra = 0; if ( shiftDist ) { sig64Extra = softfloat_shiftRightJam64Extra( sig64, 0, shiftDist ); sig64 = sig64Extra.v; extra = sig64Extra.extra; } return softfloat_roundToUI64( sign, sig64, extra, roundingMode, exact ); #else extSig[indexWord( 3, 2 )] = sig<<8; extSig[indexWord( 3, 1 )] = 0; extSig[indexWord( 3, 0 )] = 0; if ( shiftDist ) softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); return softfloat_roundMToUI64( sign, extSig, roundingMode, exact ); #endif } ================================================ FILE: vp/src/vendor/softfloat/f32_to_ui64_r_minMag.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.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 shiftDist; bool sign; uint_fast64_t sig64, z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF32UI( uiA ); sig = fracF32UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0xBE - exp; if ( 64 <= shiftDist ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF32UI( uiA ); if ( sign || (shiftDist < 0) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0xFF) && sig ? ui64_fromNaN : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig |= 0x00800000; sig64 = (uint_fast64_t) sig<<40; z = sig64>>shiftDist; shiftDist = 40 - shiftDist; if ( exact && (shiftDist < 0) && (uint32_t) (sig<<(shiftDist & 31)) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return z; } ================================================ FILE: vp/src/vendor/softfloat/f64_add.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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; #if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) float64_t (*magsFuncPtr)( uint_fast64_t, uint_fast64_t, bool ); #endif uA.f = a; uiA = uA.ui; signA = signF64UI( uiA ); uB.f = b; uiB = uB.ui; signB = signF64UI( uiB ); #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) if ( signA == signB ) { return softfloat_addMagsF64( uiA, uiB, signA ); } else { return softfloat_subMagsF64( uiA, uiB, signA ); } #else magsFuncPtr = (signA == signB) ? softfloat_addMagsF64 : softfloat_subMagsF64; return (*magsFuncPtr)( uiA, uiB, signA ); #endif } ================================================ FILE: vp/src/vendor/softfloat/f64_classify.c ================================================ #include #include #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 ); bool fracZero = fracF64UI( uiA ) == 0; bool isNaN = isNaNF64UI( uiA ); bool isSNaN = softfloat_isSigNaNF64UI( uiA ); return ( sign && infOrNaN && fracZero ) << 0 | ( sign && !infOrNaN && !subnormalOrZero ) << 1 | ( sign && subnormalOrZero && !fracZero ) << 2 | ( sign && subnormalOrZero && fracZero ) << 3 | ( !sign && infOrNaN && fracZero ) << 7 | ( !sign && !infOrNaN && !subnormalOrZero ) << 6 | ( !sign && subnormalOrZero && !fracZero ) << 5 | ( !sign && subnormalOrZero && fracZero ) << 4 | ( isNaN && isSNaN ) << 8 | ( isNaN && !isSNaN ) << 9; } ================================================ FILE: vp/src/vendor/softfloat/f64_div.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.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; uint32_t recip32, sig32Z, doubleTerm; uint_fast64_t rem; uint32_t q; uint_fast64_t sigZ; 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_infinite ); 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 + 0x3FE; sigA |= UINT64_C( 0x0010000000000000 ); sigB |= UINT64_C( 0x0010000000000000 ); if ( sigA < sigB ) { --expZ; sigA <<= 11; } else { sigA <<= 10; } sigB <<= 11; recip32 = softfloat_approxRecip32_1( sigB>>32 ) - 2; sig32Z = ((uint32_t) (sigA>>32) * (uint_fast64_t) recip32)>>32; doubleTerm = sig32Z<<1; rem = ((sigA - (uint_fast64_t) doubleTerm * (uint32_t) (sigB>>32))<<28) - (uint_fast64_t) doubleTerm * ((uint32_t) sigB>>4); q = (((uint32_t) (rem>>32) * (uint_fast64_t) recip32)>>32) + 4; sigZ = ((uint_fast64_t) sig32Z<<32) + ((uint_fast64_t) q<<4); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( (sigZ & 0x1FF) < 4<<4 ) { q &= ~7; sigZ &= ~(uint_fast64_t) 0x7F; doubleTerm = q<<1; rem = ((rem - (uint_fast64_t) doubleTerm * (uint32_t) (sigB>>32))<<28) - (uint_fast64_t) doubleTerm * ((uint32_t) sigB>>4); if ( rem & UINT64_C( 0x8000000000000000 ) ) { sigZ -= 1<<7; } else { if ( rem ) sigZ |= 1; } } 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; } ================================================ FILE: vp/src/vendor/softfloat/f64_eq.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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 ( isNaNF64UI( uiA ) || isNaNF64UI( uiB ) ) { if ( softfloat_isSigNaNF64UI( uiA ) || softfloat_isSigNaNF64UI( uiB ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); } return false; } return (uiA == uiB) || ! ((uiA | uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF )); } ================================================ FILE: vp/src/vendor/softfloat/f64_eq_signaling.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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 ( isNaNF64UI( uiA ) || isNaNF64UI( uiB ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return false; } return (uiA == uiB) || ! ((uiA | uiB) & UINT64_C( 0x7FFFFFFFFFFFFFFF )); } ================================================ FILE: vp/src/vendor/softfloat/f64_isSignalingNaN.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #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 ); } ================================================ FILE: vp/src/vendor/softfloat/f64_le.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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 ( isNaNF64UI( uiA ) || isNaNF64UI( 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)); } ================================================ FILE: vp/src/vendor/softfloat/f64_le_quiet.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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 ( isNaNF64UI( uiA ) || isNaNF64UI( 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)); } ================================================ FILE: vp/src/vendor/softfloat/f64_lt.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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 ( isNaNF64UI( uiA ) || isNaNF64UI( 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)); } ================================================ FILE: vp/src/vendor/softfloat/f64_lt_quiet.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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 ( isNaNF64UI( uiA ) || isNaNF64UI( 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)); } ================================================ FILE: vp/src/vendor/softfloat/f64_mul.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.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; #ifdef SOFTFLOAT_FAST_INT64 struct uint128 sig128Z; #else uint32_t sig128Z[4]; #endif 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; #ifdef SOFTFLOAT_FAST_INT64 sig128Z = softfloat_mul64To128( sigA, sigB ); sigZ = sig128Z.v64 | (sig128Z.v0 != 0); #else softfloat_mul64To128M( sigA, sigB, sig128Z ); sigZ = (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; if ( sig128Z[indexWord( 4, 1 )] || sig128Z[indexWord( 4, 0 )] ) sigZ |= 1; #endif 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; } ================================================ FILE: vp/src/vendor/softfloat/f64_mulAdd.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #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( uiA, uiB, uiC, 0 ); } ================================================ FILE: vp/src/vendor/softfloat/f64_rem.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.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; int_fast16_t expB; uint_fast64_t sigB; struct exp16_sig64 normExpSig; uint64_t rem; int_fast16_t expDiff; uint32_t q, recip32; uint_fast64_t q64; uint64_t altRem, meanRem; bool signRem; 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; 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 ( expA < expB - 1 ) 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; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ rem = sigA | UINT64_C( 0x0010000000000000 ); sigB |= UINT64_C( 0x0010000000000000 ); expDiff = expA - expB; if ( expDiff < 1 ) { if ( expDiff < -1 ) return a; sigB <<= 9; if ( expDiff ) { rem <<= 8; q = 0; } else { rem <<= 9; q = (sigB <= rem); if ( q ) rem -= sigB; } } else { recip32 = softfloat_approxRecip32_1( sigB>>21 ); /*-------------------------------------------------------------------- | Changing the shift of `rem' here requires also changing the initial | subtraction from `expDiff'. *--------------------------------------------------------------------*/ rem <<= 9; expDiff -= 30; /*-------------------------------------------------------------------- | The scale of `sigB' affects how many bits are obtained during each | cycle of the loop. Currently this is 29 bits per loop iteration, | the maximum possible. *--------------------------------------------------------------------*/ sigB <<= 9; for (;;) { q64 = (uint32_t) (rem>>32) * (uint_fast64_t) recip32; if ( expDiff < 0 ) break; q = (q64 + 0x80000000)>>32; #ifdef SOFTFLOAT_FAST_INT64 rem <<= 29; #else rem = (uint_fast64_t) (uint32_t) (rem>>3)<<32; #endif rem -= q * (uint64_t) sigB; if ( rem & UINT64_C( 0x8000000000000000 ) ) rem += sigB; expDiff -= 29; } /*-------------------------------------------------------------------- | (`expDiff' cannot be less than -29 here.) *--------------------------------------------------------------------*/ q = (uint32_t) (q64>>32)>>(~expDiff & 31); rem = (rem<<(expDiff + 30)) - q * (uint64_t) sigB; if ( rem & UINT64_C( 0x8000000000000000 ) ) { altRem = rem + sigB; goto selectRem; } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ do { altRem = rem; ++q; rem -= sigB; } while ( ! (rem & UINT64_C( 0x8000000000000000 )) ); selectRem: meanRem = rem + altRem; if ( (meanRem & UINT64_C( 0x8000000000000000 )) || (! meanRem && (q & 1)) ) { rem = altRem; } signRem = signA; if ( rem & UINT64_C( 0x8000000000000000 ) ) { signRem = ! signRem; rem = -rem; } return softfloat_normRoundPackToF64( signRem, expB, rem ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); goto uiZ; invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF64UI; uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f64_roundToInt.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float64_t f64_roundToInt( float64_t a, uint_fast8_t roundingMode, bool exact ) { union ui64_f64 uA; uint_fast64_t uiA; int_fast16_t exp; uint_fast64_t uiZ, lastBitMask, roundBitsMask; union ui64_f64 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp <= 0x3FE ) { if ( ! (uiA & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) return a; if ( exact ) softfloat_exceptionFlags |= softfloat_flag_inexact; uiZ = uiA & packToF64UI( 1, 0, 0 ); switch ( roundingMode ) { case softfloat_round_near_even: if ( ! fracF64UI( uiA ) ) break; case softfloat_round_near_maxMag: if ( exp == 0x3FE ) uiZ |= packToF64UI( 0, 0x3FF, 0 ); break; case softfloat_round_min: if ( uiZ ) uiZ = packToF64UI( 1, 0x3FF, 0 ); break; case softfloat_round_max: if ( ! uiZ ) uiZ = packToF64UI( 0, 0x3FF, 0 ); break; } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x433 <= exp ) { if ( (exp == 0x7FF) && fracF64UI( uiA ) ) { uiZ = softfloat_propagateNaNF64UI( uiA, 0 ); goto uiZ; } return a; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uiZ = uiA; lastBitMask = (uint_fast64_t) 1<<(0x433 - exp); roundBitsMask = lastBitMask - 1; if ( roundingMode == softfloat_round_near_maxMag ) { uiZ += lastBitMask>>1; } else if ( roundingMode == softfloat_round_near_even ) { uiZ += lastBitMask>>1; if ( ! (uiZ & roundBitsMask) ) uiZ &= ~lastBitMask; } else if ( roundingMode == (signF64UI( uiZ ) ? softfloat_round_min : softfloat_round_max) ) { uiZ += roundBitsMask; } uiZ &= ~roundBitsMask; if ( exact && (uiZ != uiA) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f64_sqrt.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.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; uint32_t sig32A, recipSqrt32, sig32Z; uint_fast64_t rem; uint32_t q; uint_fast64_t sigZ, shiftedSigZ; 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; } /*------------------------------------------------------------------------ | (`sig32Z' is guaranteed to be a lower bound on the square root of | `sig32A', which makes `sig32Z' also a lower bound on the square root of | `sigA'.) *------------------------------------------------------------------------*/ expZ = ((expA - 0x3FF)>>1) + 0x3FE; expA &= 1; sigA |= UINT64_C( 0x0010000000000000 ); sig32A = sigA>>21; recipSqrt32 = softfloat_approxRecipSqrt32_1( expA, sig32A ); sig32Z = ((uint_fast64_t) sig32A * recipSqrt32)>>32; if ( expA ) { sigA <<= 8; sig32Z >>= 1; } else { sigA <<= 9; } rem = sigA - (uint_fast64_t) sig32Z * sig32Z; q = ((uint32_t) (rem>>2) * (uint_fast64_t) recipSqrt32)>>32; sigZ = ((uint_fast64_t) sig32Z<<32 | 1<<5) + ((uint_fast64_t) q<<3); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( (sigZ & 0x1FF) < 0x22 ) { sigZ &= ~(uint_fast64_t) 0x3F; shiftedSigZ = sigZ>>6; rem = (sigA<<52) - shiftedSigZ * shiftedSigZ; if ( rem & UINT64_C( 0x8000000000000000 ) ) { --sigZ; } else { if ( rem ) sigZ |= 1; } } return softfloat_roundPackToF64( 0, expZ, sigZ ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF64UI; uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f64_sub.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #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; #if ! defined INLINE_LEVEL || (INLINE_LEVEL < 2) float64_t (*magsFuncPtr)( uint_fast64_t, uint_fast64_t, bool ); #endif uA.f = a; uiA = uA.ui; signA = signF64UI( uiA ); uB.f = b; uiB = uB.ui; signB = signF64UI( uiB ); #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) if ( signA == signB ) { return softfloat_subMagsF64( uiA, uiB, signA ); } else { return softfloat_addMagsF64( uiA, uiB, signA ); } #else magsFuncPtr = (signA == signB) ? softfloat_subMagsF64 : softfloat_addMagsF64; return (*magsFuncPtr)( uiA, uiB, signA ); #endif } ================================================ FILE: vp/src/vendor/softfloat/f64_to_f128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float128_t f64_to_f128( float64_t a ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t frac; struct commonNaN commonNaN; struct uint128 uiZ; struct exp16_sig64 normExpSig; struct uint128 frac128; union ui128_f128 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); frac = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FF ) { if ( frac ) { softfloat_f64UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToF128UI( &commonNaN ); } else { uiZ.v64 = packToF128UI64( sign, 0x7FFF, 0 ); uiZ.v0 = 0; } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! exp ) { if ( ! frac ) { uiZ.v64 = packToF128UI64( sign, 0, 0 ); uiZ.v0 = 0; goto uiZ; } normExpSig = softfloat_normSubnormalF64Sig( frac ); exp = normExpSig.exp - 1; frac = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ frac128 = softfloat_shortShiftLeft128( 0, frac, 60 ); uiZ.v64 = packToF128UI64( sign, exp + 0x3C00, frac128.v64 ); uiZ.v0 = frac128.v0; uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f64_to_f16.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float16_t f64_to_f16( float64_t a ) { union ui64_f64 uA; uint_fast64_t uiA; bool sign; int_fast16_t exp; uint_fast64_t frac; struct commonNaN commonNaN; uint_fast16_t uiZ, frac16; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); frac = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FF ) { if ( frac ) { softfloat_f64UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToF16UI( &commonNaN ); } else { uiZ = packToF16UI( sign, 0x1F, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ frac16 = softfloat_shortShiftRightJam64( frac, 38 ); if ( ! (exp | frac16) ) { uiZ = packToF16UI( sign, 0, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ return softfloat_roundPackToF16( sign, exp - 0x3F1, frac16 | 0x4000 ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f64_to_f32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.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 frac; struct commonNaN commonNaN; uint_fast32_t uiZ, frac32; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); frac = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp == 0x7FF ) { if ( frac ) { softfloat_f64UIToCommonNaN( uiA, &commonNaN ); uiZ = softfloat_commonNaNToF32UI( &commonNaN ); } else { uiZ = packToF32UI( sign, 0xFF, 0 ); } goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ frac32 = softfloat_shortShiftRightJam64( frac, 22 ); if ( ! (exp | frac32) ) { uiZ = packToF32UI( sign, 0, 0 ); goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ return softfloat_roundPackToF32( sign, exp - 0x381, frac32 | 0x40000000 ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/f64_to_i32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast32_t f64_to_i32( float64_t a, uint_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 shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ #if (i32_fromNaN != i32_fromPosOverflow) || (i32_fromNaN != i32_fromNegOverflow) if ( (exp == 0x7FF) && sig ) { #if (i32_fromNaN == i32_fromPosOverflow) sign = 0; #elif (i32_fromNaN == i32_fromNegOverflow) sign = 1; #else softfloat_raiseFlags( softfloat_flag_invalid ); return i32_fromNaN; #endif } #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); shiftDist = 0x427 - exp; if ( 0 < shiftDist ) sig = softfloat_shiftRightJam64( sig, shiftDist ); return softfloat_roundToI32( sign, sig, roundingMode, exact ); } ================================================ FILE: vp/src/vendor/softfloat/f64_to_i32_r_minMag.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.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; int_fast16_t shiftDist; bool sign; int_fast32_t absZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x433 - exp; if ( 53 <= shiftDist ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF64UI( uiA ); if ( shiftDist < 22 ) { if ( sign && (exp == 0x41E) && (sig < UINT64_C( 0x0000000000200000 )) ) { if ( exact && sig ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return -0x7FFFFFFF - 1; } softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FF) && sig ? i32_fromNaN : sign ? i32_fromNegOverflow : i32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig |= UINT64_C( 0x0010000000000000 ); absZ = sig>>shiftDist; if ( exact && ((uint_fast64_t) (uint_fast32_t) absZ< #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast64_t f64_to_i64( float64_t a, uint_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 shiftDist; #ifdef SOFTFLOAT_FAST_INT64 struct uint64_extra sigExtra; #else uint32_t extSig[3]; #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); shiftDist = 0x433 - exp; #ifdef SOFTFLOAT_FAST_INT64 if ( shiftDist <= 0 ) { if ( shiftDist < -11 ) goto invalid; sigExtra.v = sig<<-shiftDist; sigExtra.extra = 0; } else { sigExtra = softfloat_shiftRightJam64Extra( sig, 0, shiftDist ); } return softfloat_roundToI64( sign, sigExtra.v, sigExtra.extra, roundingMode, exact ); #else extSig[indexWord( 3, 0 )] = 0; if ( shiftDist <= 0 ) { if ( shiftDist < -11 ) goto invalid; sig <<= -shiftDist; extSig[indexWord( 3, 2 )] = sig>>32; extSig[indexWord( 3, 1 )] = sig; } else { extSig[indexWord( 3, 2 )] = sig>>32; extSig[indexWord( 3, 1 )] = sig; softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); } return softfloat_roundMToI64( sign, extSig, roundingMode, exact ); #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FF) && fracF64UI( uiA ) ? i64_fromNaN : sign ? i64_fromNegOverflow : i64_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/f64_to_i64_r_minMag.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.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 shiftDist; int_fast64_t absZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x433 - exp; if ( shiftDist <= 0 ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( shiftDist < -10 ) { if ( uiA == packToF64UI( 1, 0x43E, 0 ) ) { return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; } softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FF) && sig ? i64_fromNaN : sign ? i64_fromNegOverflow : i64_fromPosOverflow; } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ sig |= UINT64_C( 0x0010000000000000 ); absZ = sig<<-shiftDist; } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( 53 <= shiftDist ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ sig |= UINT64_C( 0x0010000000000000 ); absZ = sig>>shiftDist; if ( exact && (absZ< #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast32_t f64_to_ui32( float64_t a, uint_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 shiftDist; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ #if (ui32_fromNaN != ui32_fromPosOverflow) || (ui32_fromNaN != ui32_fromNegOverflow) if ( (exp == 0x7FF) && sig ) { #if (ui32_fromNaN == ui32_fromPosOverflow) sign = 0; #elif (ui32_fromNaN == ui32_fromNegOverflow) sign = 1; #else softfloat_raiseFlags( softfloat_flag_invalid ); return ui32_fromNaN; #endif } #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); shiftDist = 0x427 - exp; if ( 0 < shiftDist ) sig = softfloat_shiftRightJam64( sig, shiftDist ); return softfloat_roundToUI32( sign, sig, roundingMode, exact ); } ================================================ FILE: vp/src/vendor/softfloat/f64_to_ui32_r_minMag.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.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 shiftDist; bool sign; uint_fast32_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x433 - exp; if ( 53 <= shiftDist ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF64UI( uiA ); if ( sign || (shiftDist < 21) ) { softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FF) && sig ? ui32_fromNaN : sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig |= UINT64_C( 0x0010000000000000 ); z = sig>>shiftDist; if ( exact && ((uint_fast64_t) z< #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast64_t f64_to_ui64( float64_t a, uint_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 shiftDist; #ifdef SOFTFLOAT_FAST_INT64 struct uint64_extra sigExtra; #else uint32_t extSig[3]; #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; sign = signF64UI( uiA ); exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( exp ) sig |= UINT64_C( 0x0010000000000000 ); shiftDist = 0x433 - exp; #ifdef SOFTFLOAT_FAST_INT64 if ( shiftDist <= 0 ) { if ( shiftDist < -11 ) goto invalid; sigExtra.v = sig<<-shiftDist; sigExtra.extra = 0; } else { sigExtra = softfloat_shiftRightJam64Extra( sig, 0, shiftDist ); } return softfloat_roundToUI64( sign, sigExtra.v, sigExtra.extra, roundingMode, exact ); #else extSig[indexWord( 3, 0 )] = 0; if ( shiftDist <= 0 ) { if ( shiftDist < -11 ) goto invalid; sig <<= -shiftDist; extSig[indexWord( 3, 2 )] = sig>>32; extSig[indexWord( 3, 1 )] = sig; } else { extSig[indexWord( 3, 2 )] = sig>>32; extSig[indexWord( 3, 1 )] = sig; softfloat_shiftRightJam96M( extSig, shiftDist, extSig ); } return softfloat_roundMToUI64( sign, extSig, roundingMode, exact ); #endif /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FF) && fracF64UI( uiA ) ? ui64_fromNaN : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/f64_to_ui64_r_minMag.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.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 shiftDist; bool sign; uint_fast64_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ uA.f = a; uiA = uA.ui; exp = expF64UI( uiA ); sig = fracF64UI( uiA ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 0x433 - exp; if ( 53 <= shiftDist ) { if ( exact && (exp | sig) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sign = signF64UI( uiA ); if ( sign ) goto invalid; if ( shiftDist <= 0 ) { if ( shiftDist < -11 ) goto invalid; z = (sig | UINT64_C( 0x0010000000000000 ))<<-shiftDist; } else { sig |= UINT64_C( 0x0010000000000000 ); z = sig>>shiftDist; if ( exact && (uint64_t) (sig<<(-shiftDist & 63)) ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } } return z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return (exp == 0x7FF) && sig ? ui64_fromNaN : sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/i32_to_f128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "internals.h" #include "softfloat.h" float128_t i32_to_f128( int32_t a ) { uint_fast64_t uiZ64; bool sign; uint_fast32_t absA; int_fast8_t shiftDist; union ui128_f128 uZ; uiZ64 = 0; if ( a ) { sign = (a < 0); absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; shiftDist = softfloat_countLeadingZeros32( absA ) + 17; uiZ64 = packToF128UI64( sign, 0x402E - shiftDist, (uint_fast64_t) absA< #include #include "platform.h" #include "internals.h" #include "softfloat.h" float16_t i32_to_f16( int32_t a ) { bool sign; uint_fast32_t absA; int_fast8_t shiftDist; union ui16_f16 u; uint_fast16_t sig; sign = (a < 0); absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; shiftDist = softfloat_countLeadingZeros32( absA ) - 21; if ( 0 <= shiftDist ) { u.ui = a ? packToF16UI( sign, 0x18 - shiftDist, (uint_fast16_t) absA<>(-shiftDist) | ((uint32_t) (absA<<(shiftDist & 31)) != 0) : (uint_fast16_t) absA< #include #include "platform.h" #include "internals.h" #include "softfloat.h" float32_t i32_to_f32( int32_t a ) { bool sign; union ui32_f32 uZ; uint_fast32_t absA; sign = (a < 0); if ( ! (a & 0x7FFFFFFF) ) { uZ.ui = sign ? packToF32UI( 1, 0x9E, 0 ) : 0; return uZ.f; } absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; return softfloat_normRoundPackToF32( sign, 0x9C, absA ); } ================================================ FILE: vp/src/vendor/softfloat/i32_to_f64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" float64_t i32_to_f64( int32_t a ) { uint_fast64_t uiZ; bool sign; uint_fast32_t absA; int_fast8_t shiftDist; union ui64_f64 uZ; if ( ! a ) { uiZ = 0; } else { sign = (a < 0); absA = sign ? -(uint_fast32_t) a : (uint_fast32_t) a; shiftDist = softfloat_countLeadingZeros32( absA ) + 21; uiZ = packToF64UI( sign, 0x432 - shiftDist, (uint_fast64_t) absA< #include "platform.h" #include "internals.h" #include "softfloat.h" float128_t i64_to_f128( int64_t a ) { uint_fast64_t uiZ64, uiZ0; bool sign; uint_fast64_t absA; int_fast8_t shiftDist; struct uint128 zSig; union ui128_f128 uZ; if ( ! a ) { uiZ64 = 0; uiZ0 = 0; } else { sign = (a < 0); absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; shiftDist = softfloat_countLeadingZeros64( absA ) + 49; if ( 64 <= shiftDist ) { zSig.v64 = absA<<(shiftDist - 64); zSig.v0 = 0; } else { zSig = softfloat_shortShiftLeft128( 0, absA, shiftDist ); } uiZ64 = packToF128UI64( sign, 0x406E - shiftDist, zSig.v64 ); uiZ0 = zSig.v0; } uZ.ui.v64 = uiZ64; uZ.ui.v0 = uiZ0; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/i64_to_f16.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" float16_t i64_to_f16( int64_t a ) { bool sign; uint_fast64_t absA; int_fast8_t shiftDist; union ui16_f16 u; uint_fast16_t sig; sign = (a < 0); absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; shiftDist = softfloat_countLeadingZeros64( absA ) - 53; if ( 0 <= shiftDist ) { u.ui = a ? packToF16UI( sign, 0x18 - shiftDist, (uint_fast16_t) absA< #include #include "platform.h" #include "internals.h" #include "softfloat.h" float32_t i64_to_f32( int64_t a ) { bool sign; uint_fast64_t absA; int_fast8_t shiftDist; union ui32_f32 u; uint_fast32_t sig; sign = (a < 0); absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; shiftDist = softfloat_countLeadingZeros64( absA ) - 40; if ( 0 <= shiftDist ) { u.ui = a ? packToF32UI( sign, 0x95 - shiftDist, (uint_fast32_t) absA< #include #include "platform.h" #include "internals.h" #include "softfloat.h" float64_t i64_to_f64( int64_t a ) { bool sign; union ui64_f64 uZ; uint_fast64_t absA; sign = (a < 0); if ( ! (a & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) { uZ.ui = sign ? packToF64UI( 1, 0x43E, 0 ) : 0; return uZ.f; } absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; return softfloat_normRoundPackToF64( sign, 0x43C, absA ); } ================================================ FILE: vp/src/vendor/softfloat/include/softfloat/internals.h ================================================ /*============================================================================ This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #ifndef internals_h #define internals_h 1 #include #include #include "primitives.h" #include "softfloat_types.h" #ifdef __cplusplus extern "C" { #endif union ui16_f16 { uint16_t ui; float16_t f; }; union ui32_f32 { uint32_t ui; float32_t f; }; union ui64_f64 { uint64_t ui; float64_t f; }; #ifdef SOFTFLOAT_FAST_INT64 union extF80M_extF80 { struct extFloat80M fM; extFloat80_t f; }; union ui128_f128 { struct uint128 ui; float128_t f; }; #endif enum { softfloat_mulAdd_subC = 1, softfloat_mulAdd_subProd = 2 }; /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ uint_fast32_t softfloat_roundToUI32( bool, uint_fast64_t, uint_fast8_t, bool ); #ifdef SOFTFLOAT_FAST_INT64 uint_fast64_t softfloat_roundToUI64( bool, uint_fast64_t, uint_fast64_t, uint_fast8_t, bool ); #else uint_fast64_t softfloat_roundMToUI64( bool, uint32_t *, uint_fast8_t, bool ); #endif int_fast32_t softfloat_roundToI32( bool, uint_fast64_t, uint_fast8_t, bool ); #ifdef SOFTFLOAT_FAST_INT64 int_fast64_t softfloat_roundToI64( bool, uint_fast64_t, uint_fast64_t, uint_fast8_t, bool ); #else int_fast64_t softfloat_roundMToI64( bool, uint32_t *, uint_fast8_t, bool ); #endif /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ #define signF16UI( a ) ((bool) ((uint16_t) (a)>>15)) #define expF16UI( a ) ((int_fast8_t) ((a)>>10) & 0x1F) #define fracF16UI( a ) ((a) & 0x03FF) #define packToF16UI( sign, exp, sig ) (((uint16_t) (sign)<<15) + ((uint16_t) (exp)<<10) + (sig)) #define isNaNF16UI( a ) (((~(a) & 0x7C00) == 0) && ((a) & 0x03FF)) struct exp8_sig16 { int_fast8_t exp; uint_fast16_t sig; }; struct exp8_sig16 softfloat_normSubnormalF16Sig( uint_fast16_t ); float16_t softfloat_roundPackToF16( bool, int_fast16_t, uint_fast16_t ); float16_t softfloat_normRoundPackToF16( bool, int_fast16_t, uint_fast16_t ); float16_t softfloat_addMagsF16( uint_fast16_t, uint_fast16_t ); float16_t softfloat_subMagsF16( uint_fast16_t, uint_fast16_t ); float16_t softfloat_mulAddF16( uint_fast16_t, uint_fast16_t, uint_fast16_t, uint_fast8_t ); /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ #define signF32UI( a ) ((bool) ((uint32_t) (a)>>31)) #define expF32UI( a ) ((int_fast16_t) ((a)>>23) & 0xFF) #define fracF32UI( a ) ((a) & 0x007FFFFF) #define packToF32UI( sign, exp, sig ) (((uint32_t) (sign)<<31) + ((uint32_t) (exp)<<23) + (sig)) #define isNaNF32UI( a ) (((~(a) & 0x7F800000) == 0) && ((a) & 0x007FFFFF)) struct exp16_sig32 { int_fast16_t exp; uint_fast32_t sig; }; struct exp16_sig32 softfloat_normSubnormalF32Sig( uint_fast32_t ); float32_t softfloat_roundPackToF32( bool, int_fast16_t, uint_fast32_t ); float32_t softfloat_normRoundPackToF32( bool, int_fast16_t, uint_fast32_t ); float32_t softfloat_addMagsF32( uint_fast32_t, uint_fast32_t ); float32_t softfloat_subMagsF32( uint_fast32_t, uint_fast32_t ); float32_t softfloat_mulAddF32( uint_fast32_t, uint_fast32_t, uint_fast32_t, uint_fast8_t ); /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ #define signF64UI( a ) ((bool) ((uint64_t) (a)>>63)) #define expF64UI( a ) ((int_fast16_t) ((a)>>52) & 0x7FF) #define fracF64UI( a ) ((a) & UINT64_C( 0x000FFFFFFFFFFFFF )) #define packToF64UI( sign, exp, sig ) ((uint64_t) (((uint_fast64_t) (sign)<<63) + ((uint_fast64_t) (exp)<<52) + (sig))) #define isNaNF64UI( a ) (((~(a) & UINT64_C( 0x7FF0000000000000 )) == 0) && ((a) & UINT64_C( 0x000FFFFFFFFFFFFF ))) struct exp16_sig64 { int_fast16_t exp; uint_fast64_t sig; }; struct exp16_sig64 softfloat_normSubnormalF64Sig( uint_fast64_t ); float64_t softfloat_roundPackToF64( bool, int_fast16_t, uint_fast64_t ); float64_t softfloat_normRoundPackToF64( bool, int_fast16_t, uint_fast64_t ); float64_t softfloat_addMagsF64( uint_fast64_t, uint_fast64_t, bool ); float64_t softfloat_subMagsF64( uint_fast64_t, uint_fast64_t, bool ); float64_t softfloat_mulAddF64( uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast8_t ); /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ #define signExtF80UI64( a64 ) ((bool) ((uint16_t) (a64)>>15)) #define expExtF80UI64( a64 ) ((a64) & 0x7FFF) #define packToExtF80UI64( sign, exp ) ((uint_fast16_t) (sign)<<15 | (exp)) #define isNaNExtF80UI( a64, a0 ) ((((a64) & 0x7FFF) == 0x7FFF) && ((a0) & UINT64_C( 0x7FFFFFFFFFFFFFFF ))) #ifdef SOFTFLOAT_FAST_INT64 /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ struct exp32_sig64 { int_fast32_t exp; uint64_t sig; }; struct exp32_sig64 softfloat_normSubnormalExtF80Sig( uint_fast64_t ); extFloat80_t softfloat_roundPackToExtF80( bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast8_t ); extFloat80_t softfloat_normRoundPackToExtF80( bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast8_t ); extFloat80_t softfloat_addMagsExtF80( uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool ); extFloat80_t softfloat_subMagsExtF80( uint_fast16_t, uint_fast64_t, uint_fast16_t, uint_fast64_t, bool ); /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ #define signF128UI64( a64 ) ((bool) ((uint64_t) (a64)>>63)) #define expF128UI64( a64 ) ((int_fast32_t) ((a64)>>48) & 0x7FFF) #define fracF128UI64( a64 ) ((a64) & UINT64_C( 0x0000FFFFFFFFFFFF )) #define packToF128UI64( sign, exp, sig64 ) (((uint_fast64_t) (sign)<<63) + ((uint_fast64_t) (exp)<<48) + (sig64)) #define isNaNF128UI( a64, a0 ) (((~(a64) & UINT64_C( 0x7FFF000000000000 )) == 0) && (a0 || ((a64) & UINT64_C( 0x0000FFFFFFFFFFFF )))) struct exp32_sig128 { int_fast32_t exp; struct uint128 sig; }; struct exp32_sig128 softfloat_normSubnormalF128Sig( uint_fast64_t, uint_fast64_t ); float128_t softfloat_roundPackToF128( bool, int_fast32_t, uint_fast64_t, uint_fast64_t, uint_fast64_t ); float128_t softfloat_normRoundPackToF128( bool, int_fast32_t, uint_fast64_t, uint_fast64_t ); float128_t softfloat_addMagsF128( uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); float128_t softfloat_subMagsF128( uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, bool ); float128_t softfloat_mulAddF128( uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast64_t, uint_fast8_t ); #else /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ bool softfloat_tryPropagateNaNExtF80M( const struct extFloat80M *, const struct extFloat80M *, struct extFloat80M * ); void softfloat_invalidExtF80M( struct extFloat80M * ); int softfloat_normExtF80SigM( uint64_t * ); void softfloat_roundPackMToExtF80M( bool, int32_t, uint32_t *, uint_fast8_t, struct extFloat80M * ); void softfloat_normRoundPackMToExtF80M( bool, int32_t, uint32_t *, uint_fast8_t, struct extFloat80M * ); void softfloat_addExtF80M( const struct extFloat80M *, const struct extFloat80M *, struct extFloat80M *, bool ); int softfloat_compareNonnormExtF80M( const struct extFloat80M *, const struct extFloat80M * ); /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ #define signF128UI96( a96 ) ((bool) ((uint32_t) (a96)>>31)) #define expF128UI96( a96 ) ((int32_t) ((a96)>>16) & 0x7FFF) #define fracF128UI96( a96 ) ((a96) & 0x0000FFFF) #define packToF128UI96( sign, exp, sig96 ) (((uint32_t) (sign)<<31) + ((uint32_t) (exp)<<16) + (sig96)) bool softfloat_isNaNF128M( const uint32_t * ); bool softfloat_tryPropagateNaNF128M( const uint32_t *, const uint32_t *, uint32_t * ); void softfloat_invalidF128M( uint32_t * ); int softfloat_shiftNormSigF128M( const uint32_t *, uint_fast8_t, uint32_t * ); void softfloat_roundPackMToF128M( bool, int32_t, uint32_t *, uint32_t * ); void softfloat_normRoundPackMToF128M( bool, int32_t, uint32_t *, uint32_t * ); void softfloat_addF128M( const uint32_t *, const uint32_t *, uint32_t *, bool ); void softfloat_mulAddF128M( const uint32_t *, const uint32_t *, const uint32_t *, uint32_t *, uint_fast8_t ); #endif #ifdef __cplusplus } #endif #endif ================================================ FILE: vp/src/vendor/softfloat/include/softfloat/platform.h ================================================ /*============================================================================ This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3a, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ #define LITTLEENDIAN 1 //#define INLINE_LEVEL 5 //#define SOFTFLOAT_FAST_INT64 //#define SOFTFLOAT_FAST_DIV64TO32 /*---------------------------------------------------------------------------- *----------------------------------------------------------------------------*/ #define INLINE static inline ================================================ FILE: vp/src/vendor/softfloat/include/softfloat/primitiveTypes.h ================================================ /*============================================================================ This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3a, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #ifndef primitiveTypes_h #define primitiveTypes_h 1 #include #include "platform.h" #ifdef SOFTFLOAT_FAST_INT64 #ifdef LITTLEENDIAN struct uint128 { uint64_t v0, v64; }; struct uint64_extra { uint64_t extra, v; }; struct uint128_extra { uint64_t extra; struct uint128 v; }; #else struct uint128 { uint64_t v64, v0; }; struct uint64_extra { uint64_t v, extra; }; struct uint128_extra { struct uint128 v; uint64_t extra; }; #endif #endif /*---------------------------------------------------------------------------- | These macros are used to isolate the differences in word order between big- | endian and little-endian platforms. *----------------------------------------------------------------------------*/ #ifdef LITTLEENDIAN #define wordIncr 1 #define indexWord( total, n ) (n) #define indexWordHi( total ) ((total) - 1) #define indexWordLo( total ) 0 #define indexMultiword( total, m, n ) (n) #define indexMultiwordHi( total, n ) ((total) - (n)) #define indexMultiwordLo( total, n ) 0 #define indexMultiwordHiBut( total, n ) (n) #define indexMultiwordLoBut( total, n ) 0 #define INIT_UINTM4( v3, v2, v1, v0 ) { v0, v1, v2, v3 } #else #define wordIncr -1 #define indexWord( total, n ) ((total) - 1 - (n)) #define indexWordHi( total ) 0 #define indexWordLo( total ) ((total) - 1) #define indexMultiword( total, m, n ) ((total) - 1 - (m)) #define indexMultiwordHi( total, n ) 0 #define indexMultiwordLo( total, n ) ((total) - (n)) #define indexMultiwordHiBut( total, n ) 0 #define indexMultiwordLoBut( total, n ) (n) #define INIT_UINTM4( v3, v2, v1, v0 ) { v3, v2, v1, v0 } #endif #endif ================================================ FILE: vp/src/vendor/softfloat/include/softfloat/primitives.h ================================================ /*============================================================================ This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #ifndef primitives_h #define primitives_h 1 #include #include #include "primitiveTypes.h" #ifdef __cplusplus extern "C" { #endif #ifndef softfloat_shortShiftRightJam64 /*---------------------------------------------------------------------------- | Shifts 'a' right by the number of bits given in 'dist', which must be in | the range 1 to 63. If any nonzero bits are shifted off, they are "jammed" | into the least-significant bit of the shifted value by setting the least- | significant bit to 1. This shifted-and-jammed value is returned. *----------------------------------------------------------------------------*/ #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) INLINE uint64_t softfloat_shortShiftRightJam64( uint64_t a, uint_fast8_t dist ) { return a>>dist | ((a & (((uint_fast64_t) 1<>dist | ((uint32_t) (a<<(-dist & 31)) != 0) : (a != 0); } #else uint32_t softfloat_shiftRightJam32( uint32_t a, uint_fast16_t dist ); #endif #endif #ifndef softfloat_shiftRightJam64 /*---------------------------------------------------------------------------- | Shifts 'a' right by the number of bits given in 'dist', which must not | be zero. If any nonzero bits are shifted off, they are "jammed" into the | least-significant bit of the shifted value by setting the least-significant | bit to 1. This shifted-and-jammed value is returned. | The value of 'dist' can be arbitrarily large. In particular, if 'dist' is | greater than 64, the result will be either 0 or 1, depending on whether 'a' | is zero or nonzero. *----------------------------------------------------------------------------*/ #if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) INLINE uint64_t softfloat_shiftRightJam64( uint64_t a, uint_fast32_t dist ) { return (dist < 63) ? a>>dist | ((uint64_t) (a<<(-dist & 63)) != 0) : (a != 0); } #else uint64_t softfloat_shiftRightJam64( uint64_t a, uint_fast32_t dist ); #endif #endif /*---------------------------------------------------------------------------- | A constant table that translates an 8-bit unsigned integer (the array index) | into the number of leading 0 bits before the most-significant 1 of that | integer. For integer zero (index 0), the corresponding table element is 8. *----------------------------------------------------------------------------*/ extern const uint_least8_t softfloat_countLeadingZeros8[256]; #ifndef softfloat_countLeadingZeros16 /*---------------------------------------------------------------------------- | Returns the number of leading 0 bits before the most-significant 1 bit of | 'a'. If 'a' is zero, 16 is returned. *----------------------------------------------------------------------------*/ #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) INLINE uint_fast8_t softfloat_countLeadingZeros16( uint16_t a ) { uint_fast8_t count = 8; if ( 0x100 <= a ) { count = 0; a >>= 8; } count += softfloat_countLeadingZeros8[a]; return count; } #else uint_fast8_t softfloat_countLeadingZeros16( uint16_t a ); #endif #endif #ifndef softfloat_countLeadingZeros32 /*---------------------------------------------------------------------------- | 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 && (3 <= INLINE_LEVEL) INLINE uint_fast8_t softfloat_countLeadingZeros32( uint32_t a ) { uint_fast8_t count = 0; if ( a < 0x10000 ) { count = 16; a <<= 16; } if ( a < 0x1000000 ) { count += 8; a <<= 8; } count += softfloat_countLeadingZeros8[a>>24]; return count; } #else uint_fast8_t softfloat_countLeadingZeros32( uint32_t a ); #endif #endif #ifndef softfloat_countLeadingZeros64 /*---------------------------------------------------------------------------- | Returns the number of leading 0 bits before the most-significant 1 bit of | 'a'. If 'a' is zero, 64 is returned. *----------------------------------------------------------------------------*/ uint_fast8_t softfloat_countLeadingZeros64( uint64_t a ); #endif extern const uint16_t softfloat_approxRecip_1k0s[16]; extern const uint16_t softfloat_approxRecip_1k1s[16]; #ifndef softfloat_approxRecip32_1 /*---------------------------------------------------------------------------- | Returns an approximation to the reciprocal of the number represented by 'a', | where 'a' is interpreted as an unsigned fixed-point number with one integer | bit and 31 fraction bits. The 'a' input must be "normalized", meaning that | its most-significant bit (bit 31) must be 1. Thus, if A is the value of | the fixed-point interpretation of 'a', then 1 <= A < 2. The returned value | is interpreted as a pure unsigned fraction, having no integer bits and 32 | fraction bits. The approximation returned is never greater than the true | reciprocal 1/A, and it differs from the true reciprocal by at most 2.006 ulp | (units in the last place). *----------------------------------------------------------------------------*/ #ifdef SOFTFLOAT_FAST_DIV64TO32 #define softfloat_approxRecip32_1( a ) ((uint32_t) (UINT64_C( 0x7FFFFFFFFFFFFFFF ) / (uint32_t) (a))) #else uint32_t softfloat_approxRecip32_1( uint32_t a ); #endif #endif extern const uint16_t softfloat_approxRecipSqrt_1k0s[16]; extern const uint16_t softfloat_approxRecipSqrt_1k1s[16]; #ifndef softfloat_approxRecipSqrt32_1 /*---------------------------------------------------------------------------- | Returns an approximation to the reciprocal of the square root of the number | represented by 'a', where 'a' is interpreted as an unsigned fixed-point | number either with one integer bit and 31 fraction bits or with two integer | bits and 30 fraction bits. The format of 'a' is determined by 'oddExpA', | which must be either 0 or 1. If 'oddExpA' is 1, 'a' is interpreted as | having one integer bit, and if 'oddExpA' is 0, 'a' is interpreted as having | two integer bits. The 'a' input must be "normalized", meaning that its | most-significant bit (bit 31) must be 1. Thus, if A is the value of the | fixed-point interpretation of 'a', it follows that 1 <= A < 2 when 'oddExpA' | is 1, and 2 <= A < 4 when 'oddExpA' is 0. | The returned value is interpreted as a pure unsigned fraction, having | no integer bits and 32 fraction bits. The approximation returned is never | greater than the true reciprocal 1/sqrt(A), and it differs from the true | reciprocal by at most 2.06 ulp (units in the last place). The approximation | returned is also always within the range 0.5 to 1; thus, the most- | significant bit of the result is always set. *----------------------------------------------------------------------------*/ uint32_t softfloat_approxRecipSqrt32_1( unsigned int oddExpA, uint32_t a ); #endif #ifdef SOFTFLOAT_FAST_INT64 /*---------------------------------------------------------------------------- | The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is | defined. *----------------------------------------------------------------------------*/ #ifndef softfloat_eq128 /*---------------------------------------------------------------------------- | Returns true if the 128-bit unsigned integer formed by concatenating 'a64' | and 'a0' is equal to the 128-bit unsigned integer formed by concatenating | 'b64' and 'b0'. *----------------------------------------------------------------------------*/ #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 a64, uint64_t a0, uint64_t b64, uint64_t b0 ); #endif #endif #ifndef softfloat_le128 /*---------------------------------------------------------------------------- | Returns true if the 128-bit unsigned integer formed by concatenating 'a64' | and 'a0' is less than or equal to the 128-bit unsigned integer formed by | concatenating 'b64' and 'b0'. *----------------------------------------------------------------------------*/ #if defined INLINE_LEVEL && (2 <= 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 a64, uint64_t a0, uint64_t b64, uint64_t b0 ); #endif #endif #ifndef softfloat_lt128 /*---------------------------------------------------------------------------- | Returns true if the 128-bit unsigned integer formed by concatenating 'a64' | and 'a0' is less than the 128-bit unsigned integer formed by concatenating | 'b64' and 'b0'. *----------------------------------------------------------------------------*/ #if defined INLINE_LEVEL && (2 <= 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 a64, uint64_t a0, uint64_t b64, uint64_t b0 ); #endif #endif #ifndef softfloat_shortShiftLeft128 /*---------------------------------------------------------------------------- | Shifts the 128 bits formed by concatenating 'a64' and 'a0' left by the | number of bits given in 'dist', which must be in the range 1 to 63. *----------------------------------------------------------------------------*/ #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) INLINE struct uint128 softfloat_shortShiftLeft128( uint64_t a64, uint64_t a0, uint_fast8_t dist ) { struct uint128 z; z.v64 = a64<>(-dist & 63); z.v0 = a0<>dist; z.v0 = a64<<(-dist & 63) | a0>>dist; return z; } #else struct uint128 softfloat_shortShiftRight128( uint64_t a64, uint64_t a0, uint_fast8_t dist ); #endif #endif #ifndef softfloat_shortShiftRightJam64Extra /*---------------------------------------------------------------------------- | This function is the same as 'softfloat_shiftRightJam64Extra' (below), | except that 'dist' must be in the range 1 to 63. *----------------------------------------------------------------------------*/ #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) INLINE struct uint64_extra softfloat_shortShiftRightJam64Extra( uint64_t a, uint64_t extra, uint_fast8_t dist ) { struct uint64_extra z; z.v = a>>dist; z.extra = a<<(-dist & 63) | (extra != 0); return z; } #else struct uint64_extra softfloat_shortShiftRightJam64Extra( uint64_t a, uint64_t extra, uint_fast8_t dist ); #endif #endif #ifndef softfloat_shortShiftRightJam128 /*---------------------------------------------------------------------------- | Shifts the 128 bits formed by concatenating 'a64' and 'a0' right by the | number of bits given in 'dist', which must be in the range 1 to 63. If any | nonzero bits are shifted off, they are "jammed" into the least-significant | bit of the shifted value by setting the least-significant bit to 1. This | shifted-and-jammed value is returned. *----------------------------------------------------------------------------*/ #if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) INLINE struct uint128 softfloat_shortShiftRightJam128( uint64_t a64, uint64_t a0, uint_fast8_t dist ) { uint_fast8_t negDist = -dist; struct uint128 z; z.v64 = a64>>dist; z.v0 = a64<<(negDist & 63) | a0>>dist | ((uint64_t) (a0<<(negDist & 63)) != 0); return z; } #else struct uint128 softfloat_shortShiftRightJam128( uint64_t a64, uint64_t a0, uint_fast8_t dist ); #endif #endif #ifndef softfloat_shortShiftRightJam128Extra /*---------------------------------------------------------------------------- | This function is the same as 'softfloat_shiftRightJam128Extra' (below), | except that 'dist' must be in the range 1 to 63. *----------------------------------------------------------------------------*/ #if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) INLINE struct uint128_extra softfloat_shortShiftRightJam128Extra( uint64_t a64, uint64_t a0, uint64_t extra, uint_fast8_t dist ) { uint_fast8_t negDist = -dist; struct uint128_extra z; z.v.v64 = a64>>dist; z.v.v0 = a64<<(negDist & 63) | a0>>dist; z.extra = a0<<(negDist & 63) | (extra != 0); return z; } #else struct uint128_extra softfloat_shortShiftRightJam128Extra( uint64_t a64, uint64_t a0, uint64_t extra, uint_fast8_t dist ); #endif #endif #ifndef softfloat_shiftRightJam64Extra /*---------------------------------------------------------------------------- | Shifts the 128 bits formed by concatenating 'a' and 'extra' right by 64 | _plus_ the number of bits given in 'dist', which must not be zero. This | shifted value is at most 64 nonzero bits and is returned in the 'v' field | of the 'struct uint64_extra' result. The 64-bit 'extra' field of the result | contains a value formed as follows from the bits that were shifted off: The | _last_ bit shifted off is the most-significant bit of the 'extra' field, and | the other 63 bits of the 'extra' field are all zero if and only if _all_but_ | _the_last_ bits shifted off were all zero. | (This function makes more sense if 'a' and 'extra' are considered to form | an unsigned fixed-point number with binary point between 'a' and 'extra'. | This fixed-point value is shifted right by the number of bits given in | 'dist', and the integer part of this shifted value is returned in the 'v' | field of the result. The fractional part of the shifted value is modified | as described above and returned in the 'extra' field of the result.) *----------------------------------------------------------------------------*/ #if defined INLINE_LEVEL && (4 <= INLINE_LEVEL) INLINE struct uint64_extra softfloat_shiftRightJam64Extra( uint64_t a, uint64_t extra, uint_fast32_t dist ) { struct uint64_extra z; if ( dist < 64 ) { z.v = a>>dist; z.extra = a<<(-dist & 63); } else { z.v = 0; z.extra = (dist == 64) ? a : (a != 0); } z.extra |= (extra != 0); return z; } #else struct uint64_extra softfloat_shiftRightJam64Extra( uint64_t a, uint64_t extra, uint_fast32_t dist ); #endif #endif #ifndef softfloat_shiftRightJam128 /*---------------------------------------------------------------------------- | Shifts the 128 bits formed by concatenating 'a64' and 'a0' right by the | number of bits given in 'dist', which must not be zero. If any nonzero bits | are shifted off, they are "jammed" into the least-significant bit of the | shifted value by setting the least-significant bit to 1. This shifted-and- | jammed value is returned. | The value of 'dist' can be arbitrarily large. In particular, if 'dist' is | greater than 128, the result will be either 0 or 1, depending on whether the | original 128 bits are all zeros. *----------------------------------------------------------------------------*/ struct uint128 softfloat_shiftRightJam128( uint64_t a64, uint64_t a0, uint_fast32_t dist ); #endif #ifndef softfloat_shiftRightJam128Extra /*---------------------------------------------------------------------------- | Shifts the 192 bits formed by concatenating 'a64', 'a0', and 'extra' right | by 64 _plus_ the number of bits given in 'dist', which must not be zero. | This shifted value is at most 128 nonzero bits and is returned in the 'v' | field of the 'struct uint128_extra' result. The 64-bit 'extra' field of the | result contains a value formed as follows from the bits that were shifted | off: The _last_ bit shifted off is the most-significant bit of the 'extra' | field, and the other 63 bits of the 'extra' field are all zero if and only | if _all_but_the_last_ bits shifted off were all zero. | (This function makes more sense if 'a64', 'a0', and 'extra' are considered | to form an unsigned fixed-point number with binary point between 'a0' and | 'extra'. This fixed-point value is shifted right by the number of bits | given in 'dist', and the integer part of this shifted value is returned | in the 'v' field of the result. The fractional part of the shifted value | is modified as described above and returned in the 'extra' field of the | result.) *----------------------------------------------------------------------------*/ struct uint128_extra softfloat_shiftRightJam128Extra( uint64_t a64, uint64_t a0, uint64_t extra, uint_fast32_t dist ); #endif #ifndef softfloat_shiftRightJam256M /*---------------------------------------------------------------------------- | Shifts the 256-bit unsigned integer pointed to by 'aPtr' right by the number | of bits given in 'dist', which must not be zero. If any nonzero bits are | shifted off, they are "jammed" into the least-significant bit of the shifted | value by setting the least-significant bit to 1. This shifted-and-jammed | value is stored at the location pointed to by 'zPtr'. Each of 'aPtr' and | 'zPtr' points to an array of four 64-bit elements that concatenate in the | platform's normal endian order to form a 256-bit integer. | The value of 'dist' can be arbitrarily large. In particular, if 'dist' | is greater than 256, the stored result will be either 0 or 1, depending on | whether the original 256 bits are all zeros. *----------------------------------------------------------------------------*/ void softfloat_shiftRightJam256M( const uint64_t *aPtr, uint_fast32_t dist, uint64_t *zPtr ); #endif #ifndef softfloat_add128 /*---------------------------------------------------------------------------- | Returns the sum of the 128-bit integer formed by concatenating 'a64' and | 'a0' and the 128-bit integer formed by concatenating 'b64' and 'b0'. The | addition is modulo 2^128, so any carry out is lost. *----------------------------------------------------------------------------*/ #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.v0 < a0); return z; } #else struct uint128 softfloat_add128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ); #endif #endif #ifndef softfloat_add256M /*---------------------------------------------------------------------------- | Adds the two 256-bit integers pointed to by 'aPtr' and 'bPtr'. The addition | is modulo 2^256, so any carry out is lost. The sum is stored at the | location pointed to by 'zPtr'. Each of 'aPtr', 'bPtr', and 'zPtr' points to | an array of four 64-bit elements that concatenate in the platform's normal | endian order to form a 256-bit integer. *----------------------------------------------------------------------------*/ void softfloat_add256M( const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr ); #endif #ifndef softfloat_sub128 /*---------------------------------------------------------------------------- | Returns the difference of the 128-bit integer formed by concatenating 'a64' | and 'a0' and the 128-bit integer formed by concatenating 'b64' and 'b0'. | The subtraction is modulo 2^128, so any borrow out (carry out) is lost. *----------------------------------------------------------------------------*/ #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 a64, uint64_t a0, uint64_t b64, uint64_t b0 ); #endif #endif #ifndef softfloat_sub256M /*---------------------------------------------------------------------------- | Subtracts the 256-bit integer pointed to by 'bPtr' from the 256-bit integer | pointed to by 'aPtr'. The addition is modulo 2^256, so any borrow out | (carry out) is lost. The difference is stored at the location pointed to | by 'zPtr'. Each of 'aPtr', 'bPtr', and 'zPtr' points to an array of four | 64-bit elements that concatenate in the platform's normal endian order to | form a 256-bit integer. *----------------------------------------------------------------------------*/ void softfloat_sub256M( const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr ); #endif #ifndef softfloat_mul64ByShifted32To128 /*---------------------------------------------------------------------------- | Returns the 128-bit product of 'a', 'b', and 2^32. *----------------------------------------------------------------------------*/ #if defined INLINE_LEVEL && (3 <= INLINE_LEVEL) INLINE struct uint128 softfloat_mul64ByShifted32To128( uint64_t a, uint32_t b ) { uint_fast64_t mid; struct uint128 z; mid = (uint_fast64_t) (uint32_t) a * b; z.v0 = mid<<32; z.v64 = (uint_fast64_t) (uint32_t) (a>>32) * b + (mid>>32); return z; } #else struct uint128 softfloat_mul64ByShifted32To128( uint64_t a, uint32_t b ); #endif #endif #ifndef softfloat_mul64To128 /*---------------------------------------------------------------------------- | Returns the 128-bit product of 'a' and 'b'. *----------------------------------------------------------------------------*/ struct uint128 softfloat_mul64To128( uint64_t a, uint64_t b ); #endif #ifndef softfloat_mul128By32 /*---------------------------------------------------------------------------- | Returns the product of the 128-bit integer formed by concatenating 'a64' and | 'a0', multiplied by 'b'. The multiplication is modulo 2^128; any overflow | bits are discarded. *----------------------------------------------------------------------------*/ #if defined INLINE_LEVEL && (4 <= INLINE_LEVEL) INLINE struct uint128 softfloat_mul128By32( uint64_t a64, uint64_t a0, uint32_t b ) { struct uint128 z; uint_fast64_t mid; uint_fast32_t carry; z.v0 = a0 * b; mid = (uint_fast64_t) (uint32_t) (a0>>32) * b; carry = (uint32_t) ((uint_fast32_t) (z.v0>>32) - (uint_fast32_t) mid); z.v64 = a64 * b + (uint_fast32_t) ((mid + carry)>>32); return z; } #else struct uint128 softfloat_mul128By32( uint64_t a64, uint64_t a0, uint32_t b ); #endif #endif #ifndef softfloat_mul128To256M /*---------------------------------------------------------------------------- | Multiplies the 128-bit unsigned integer formed by concatenating 'a64' and | 'a0' by the 128-bit unsigned integer formed by concatenating 'b64' and | 'b0'. The 256-bit product is stored at the location pointed to by 'zPtr'. | Argument 'zPtr' points to an array of four 64-bit elements that concatenate | in the platform's normal endian order to form a 256-bit integer. *----------------------------------------------------------------------------*/ void softfloat_mul128To256M( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0, uint64_t *zPtr ); #endif #else /*---------------------------------------------------------------------------- | The following functions are needed only when 'SOFTFLOAT_FAST_INT64' is not | defined. *----------------------------------------------------------------------------*/ #ifndef softfloat_compare96M /*---------------------------------------------------------------------------- | Compares the two 96-bit unsigned integers pointed to by 'aPtr' and 'bPtr'. | Returns -1 if the first integer (A) is less than the second (B); returns 0 | if the two integers are equal; and returns +1 if the first integer (A) | is greater than the second (B). (The result is thus the signum of A - B.) | Each of 'aPtr' and 'bPtr' points to an array of three 32-bit elements that | concatenate in the platform's normal endian order to form a 96-bit integer. *----------------------------------------------------------------------------*/ int_fast8_t softfloat_compare96M( const uint32_t *aPtr, const uint32_t *bPtr ); #endif #ifndef softfloat_compare128M /*---------------------------------------------------------------------------- | Compares the two 128-bit unsigned integers pointed to by 'aPtr' and 'bPtr'. | Returns -1 if the first integer (A) is less than the second (B); returns 0 | if the two integers are equal; and returns +1 if the first integer (A) | is greater than the second (B). (The result is thus the signum of A - B.) | Each of 'aPtr' and 'bPtr' points to an array of four 32-bit elements that | concatenate in the platform's normal endian order to form a 128-bit integer. *----------------------------------------------------------------------------*/ int_fast8_t softfloat_compare128M( const uint32_t *aPtr, const uint32_t *bPtr ); #endif #ifndef softfloat_shortShiftLeft64To96M /*---------------------------------------------------------------------------- | Extends 'a' to 96 bits and shifts the value left by the number of bits given | in 'dist', which must be in the range 1 to 31. The result is stored at the | location pointed to by 'zPtr'. Argument 'zPtr' points to an array of three | 32-bit elements that concatenate in the platform's normal endian order to | form a 96-bit integer. *----------------------------------------------------------------------------*/ #if defined INLINE_LEVEL && (2 <= INLINE_LEVEL) INLINE void softfloat_shortShiftLeft64To96M( uint64_t a, uint_fast8_t dist, uint32_t *zPtr ) { zPtr[indexWord( 3, 0 )] = (uint32_t) a<>= 32 - dist; zPtr[indexWord( 3, 2 )] = a>>32; zPtr[indexWord( 3, 1 )] = a; } #else void softfloat_shortShiftLeft64To96M( uint64_t a, uint_fast8_t dist, uint32_t *zPtr ); #endif #endif #ifndef softfloat_shortShiftLeftM /*---------------------------------------------------------------------------- | Shifts the N-bit unsigned integer pointed to by 'aPtr' left by the number | of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' | must be in the range 1 to 31. Any nonzero bits shifted off are lost. The | shifted N-bit result is stored at the location pointed to by 'zPtr'. Each | of 'aPtr' and 'zPtr' points to a 'size_words'-long array of 32-bit elements | that concatenate in the platform's normal endian order to form an N-bit | integer. *----------------------------------------------------------------------------*/ void softfloat_shortShiftLeftM( uint_fast8_t size_words, const uint32_t *aPtr, uint_fast8_t dist, uint32_t *zPtr ); #endif #ifndef softfloat_shortShiftLeft96M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_shortShiftLeftM' with | 'size_words' = 3 (N = 96). *----------------------------------------------------------------------------*/ #define softfloat_shortShiftLeft96M( aPtr, dist, zPtr ) softfloat_shortShiftLeftM( 3, aPtr, dist, zPtr ) #endif #ifndef softfloat_shortShiftLeft128M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_shortShiftLeftM' with | 'size_words' = 4 (N = 128). *----------------------------------------------------------------------------*/ #define softfloat_shortShiftLeft128M( aPtr, dist, zPtr ) softfloat_shortShiftLeftM( 4, aPtr, dist, zPtr ) #endif #ifndef softfloat_shortShiftLeft160M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_shortShiftLeftM' with | 'size_words' = 5 (N = 160). *----------------------------------------------------------------------------*/ #define softfloat_shortShiftLeft160M( aPtr, dist, zPtr ) softfloat_shortShiftLeftM( 5, aPtr, dist, zPtr ) #endif #ifndef softfloat_shiftLeftM /*---------------------------------------------------------------------------- | Shifts the N-bit unsigned integer pointed to by 'aPtr' left by the number | of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' | must not be zero. Any nonzero bits shifted off are lost. The shifted | N-bit result is stored at the location pointed to by 'zPtr'. Each of 'aPtr' | and 'zPtr' points to a 'size_words'-long array of 32-bit elements that | concatenate in the platform's normal endian order to form an N-bit integer. | The value of 'dist' can be arbitrarily large. In particular, if 'dist' is | greater than N, the stored result will be 0. *----------------------------------------------------------------------------*/ void softfloat_shiftLeftM( uint_fast8_t size_words, const uint32_t *aPtr, uint32_t dist, uint32_t *zPtr ); #endif #ifndef softfloat_shiftLeft96M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_shiftLeftM' with | 'size_words' = 3 (N = 96). *----------------------------------------------------------------------------*/ #define softfloat_shiftLeft96M( aPtr, dist, zPtr ) softfloat_shiftLeftM( 3, aPtr, dist, zPtr ) #endif #ifndef softfloat_shiftLeft128M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_shiftLeftM' with | 'size_words' = 4 (N = 128). *----------------------------------------------------------------------------*/ #define softfloat_shiftLeft128M( aPtr, dist, zPtr ) softfloat_shiftLeftM( 4, aPtr, dist, zPtr ) #endif #ifndef softfloat_shiftLeft160M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_shiftLeftM' with | 'size_words' = 5 (N = 160). *----------------------------------------------------------------------------*/ #define softfloat_shiftLeft160M( aPtr, dist, zPtr ) softfloat_shiftLeftM( 5, aPtr, dist, zPtr ) #endif #ifndef softfloat_shortShiftRightM /*---------------------------------------------------------------------------- | Shifts the N-bit unsigned integer pointed to by 'aPtr' right by the number | of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' | must be in the range 1 to 31. Any nonzero bits shifted off are lost. The | shifted N-bit result is stored at the location pointed to by 'zPtr'. Each | of 'aPtr' and 'zPtr' points to a 'size_words'-long array of 32-bit elements | that concatenate in the platform's normal endian order to form an N-bit | integer. *----------------------------------------------------------------------------*/ void softfloat_shortShiftRightM( uint_fast8_t size_words, const uint32_t *aPtr, uint_fast8_t dist, uint32_t *zPtr ); #endif #ifndef softfloat_shortShiftRight128M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_shortShiftRightM' with | 'size_words' = 4 (N = 128). *----------------------------------------------------------------------------*/ #define softfloat_shortShiftRight128M( aPtr, dist, zPtr ) softfloat_shortShiftRightM( 4, aPtr, dist, zPtr ) #endif #ifndef softfloat_shortShiftRight160M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_shortShiftRightM' with | 'size_words' = 5 (N = 160). *----------------------------------------------------------------------------*/ #define softfloat_shortShiftRight160M( aPtr, dist, zPtr ) softfloat_shortShiftRightM( 5, aPtr, dist, zPtr ) #endif #ifndef softfloat_shortShiftRightJamM /*---------------------------------------------------------------------------- | Shifts the N-bit unsigned integer pointed to by 'aPtr' right by the number | of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' | must be in the range 1 to 31. If any nonzero bits are shifted off, they are | "jammed" into the least-significant bit of the shifted value by setting the | least-significant bit to 1. This shifted-and-jammed N-bit result is stored | at the location pointed to by 'zPtr'. Each of 'aPtr' and 'zPtr' points | to a 'size_words'-long array of 32-bit elements that concatenate in the | platform's normal endian order to form an N-bit integer. *----------------------------------------------------------------------------*/ void softfloat_shortShiftRightJamM( uint_fast8_t, const uint32_t *, uint_fast8_t, uint32_t * ); #endif #ifndef softfloat_shortShiftRightJam160M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_shortShiftRightJamM' with | 'size_words' = 5 (N = 160). *----------------------------------------------------------------------------*/ #define softfloat_shortShiftRightJam160M( aPtr, dist, zPtr ) softfloat_shortShiftRightJamM( 5, aPtr, dist, zPtr ) #endif #ifndef softfloat_shiftRightM /*---------------------------------------------------------------------------- | Shifts the N-bit unsigned integer pointed to by 'aPtr' right by the number | of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' | must not be zero. Any nonzero bits shifted off are lost. The shifted | N-bit result is stored at the location pointed to by 'zPtr'. Each of 'aPtr' | and 'zPtr' points to a 'size_words'-long array of 32-bit elements that | concatenate in the platform's normal endian order to form an N-bit integer. | The value of 'dist' can be arbitrarily large. In particular, if 'dist' is | greater than N, the stored result will be 0. *----------------------------------------------------------------------------*/ void softfloat_shiftRightM( uint_fast8_t size_words, const uint32_t *aPtr, uint32_t dist, uint32_t *zPtr ); #endif #ifndef softfloat_shiftRight96M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_shiftRightM' with | 'size_words' = 3 (N = 96). *----------------------------------------------------------------------------*/ #define softfloat_shiftRight96M( aPtr, dist, zPtr ) softfloat_shiftRightM( 3, aPtr, dist, zPtr ) #endif #ifndef softfloat_shiftRightJamM /*---------------------------------------------------------------------------- | Shifts the N-bit unsigned integer pointed to by 'aPtr' right by the number | of bits given in 'dist', where N = 'size_words' * 32. The value of 'dist' | must not be zero. If any nonzero bits are shifted off, they are "jammed" | into the least-significant bit of the shifted value by setting the least- | significant bit to 1. This shifted-and-jammed N-bit result is stored | at the location pointed to by 'zPtr'. Each of 'aPtr' and 'zPtr' points | to a 'size_words'-long array of 32-bit elements that concatenate in the | platform's normal endian order to form an N-bit integer. | The value of 'dist' can be arbitrarily large. In particular, if 'dist' | is greater than N, the stored result will be either 0 or 1, depending on | whether the original N bits are all zeros. *----------------------------------------------------------------------------*/ void softfloat_shiftRightJamM( uint_fast8_t size_words, const uint32_t *aPtr, uint32_t dist, uint32_t *zPtr ); #endif #ifndef softfloat_shiftRightJam96M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_shiftRightJamM' with | 'size_words' = 3 (N = 96). *----------------------------------------------------------------------------*/ #define softfloat_shiftRightJam96M( aPtr, dist, zPtr ) softfloat_shiftRightJamM( 3, aPtr, dist, zPtr ) #endif #ifndef softfloat_shiftRightJam128M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_shiftRightJamM' with | 'size_words' = 4 (N = 128). *----------------------------------------------------------------------------*/ #define softfloat_shiftRightJam128M( aPtr, dist, zPtr ) softfloat_shiftRightJamM( 4, aPtr, dist, zPtr ) #endif #ifndef softfloat_shiftRightJam160M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_shiftRightJamM' with | 'size_words' = 5 (N = 160). *----------------------------------------------------------------------------*/ #define softfloat_shiftRightJam160M( aPtr, dist, zPtr ) softfloat_shiftRightJamM( 5, aPtr, dist, zPtr ) #endif #ifndef softfloat_addM /*---------------------------------------------------------------------------- | Adds the two N-bit integers pointed to by 'aPtr' and 'bPtr', where N = | 'size_words' * 32. The addition is modulo 2^N, so any carry out is lost. | The N-bit sum is stored at the location pointed to by 'zPtr'. Each of | 'aPtr', 'bPtr', and 'zPtr' points to a 'size_words'-long array of 32-bit | elements that concatenate in the platform's normal endian order to form an | N-bit integer. *----------------------------------------------------------------------------*/ void softfloat_addM( uint_fast8_t size_words, const uint32_t *aPtr, const uint32_t *bPtr, uint32_t *zPtr ); #endif #ifndef softfloat_add96M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_addM' with 'size_words' | = 3 (N = 96). *----------------------------------------------------------------------------*/ #define softfloat_add96M( aPtr, bPtr, zPtr ) softfloat_addM( 3, aPtr, bPtr, zPtr ) #endif #ifndef softfloat_add128M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_addM' with 'size_words' | = 4 (N = 128). *----------------------------------------------------------------------------*/ #define softfloat_add128M( aPtr, bPtr, zPtr ) softfloat_addM( 4, aPtr, bPtr, zPtr ) #endif #ifndef softfloat_add160M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_addM' with 'size_words' | = 5 (N = 160). *----------------------------------------------------------------------------*/ #define softfloat_add160M( aPtr, bPtr, zPtr ) softfloat_addM( 5, aPtr, bPtr, zPtr ) #endif #ifndef softfloat_addCarryM /*---------------------------------------------------------------------------- | Adds the two N-bit unsigned integers pointed to by 'aPtr' and 'bPtr', where | N = 'size_words' * 32, plus 'carry', which must be either 0 or 1. The N-bit | sum (modulo 2^N) is stored at the location pointed to by 'zPtr', and any | carry out is returned as the result. Each of 'aPtr', 'bPtr', and 'zPtr' | points to a 'size_words'-long array of 32-bit elements that concatenate in | the platform's normal endian order to form an N-bit integer. *----------------------------------------------------------------------------*/ uint_fast8_t softfloat_addCarryM( uint_fast8_t size_words, const uint32_t *aPtr, const uint32_t *bPtr, uint_fast8_t carry, uint32_t *zPtr ); #endif #ifndef softfloat_addComplCarryM /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_addCarryM', except that | the value of the unsigned integer pointed to by 'bPtr' is bit-wise completed | before the addition. *----------------------------------------------------------------------------*/ uint_fast8_t softfloat_addComplCarryM( uint_fast8_t size_words, const uint32_t *aPtr, const uint32_t *bPtr, uint_fast8_t carry, uint32_t *zPtr ); #endif #ifndef softfloat_addComplCarry96M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_addComplCarryM' with | 'size_words' = 3 (N = 96). *----------------------------------------------------------------------------*/ #define softfloat_addComplCarry96M( aPtr, bPtr, carry, zPtr ) softfloat_addComplCarryM( 3, aPtr, bPtr, carry, zPtr ) #endif #ifndef softfloat_negXM /*---------------------------------------------------------------------------- | Replaces the N-bit unsigned integer pointed to by 'zPtr' by the | 2s-complement of itself, where N = 'size_words' * 32. Argument 'zPtr' | points to a 'size_words'-long array of 32-bit elements that concatenate in | the platform's normal endian order to form an N-bit integer. *----------------------------------------------------------------------------*/ void softfloat_negXM( uint_fast8_t size_words, uint32_t *zPtr ); #endif #ifndef softfloat_negX96M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_negXM' with 'size_words' | = 3 (N = 96). *----------------------------------------------------------------------------*/ #define softfloat_negX96M( zPtr ) softfloat_negXM( 3, zPtr ) #endif #ifndef softfloat_negX128M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_negXM' with 'size_words' | = 4 (N = 128). *----------------------------------------------------------------------------*/ #define softfloat_negX128M( zPtr ) softfloat_negXM( 4, zPtr ) #endif #ifndef softfloat_negX160M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_negXM' with 'size_words' | = 5 (N = 160). *----------------------------------------------------------------------------*/ #define softfloat_negX160M( zPtr ) softfloat_negXM( 5, zPtr ) #endif #ifndef softfloat_negX256M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_negXM' with 'size_words' | = 8 (N = 256). *----------------------------------------------------------------------------*/ #define softfloat_negX256M( zPtr ) softfloat_negXM( 8, zPtr ) #endif #ifndef softfloat_sub1XM /*---------------------------------------------------------------------------- | Subtracts 1 from the N-bit integer pointed to by 'zPtr', where N = | 'size_words' * 32. The subtraction is modulo 2^N, so any borrow out (carry | out) is lost. Argument 'zPtr' points to a 'size_words'-long array of 32-bit | elements that concatenate in the platform's normal endian order to form an | N-bit integer. *----------------------------------------------------------------------------*/ void softfloat_sub1XM( uint_fast8_t size_words, uint32_t *zPtr ); #endif #ifndef softfloat_sub1X96M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_sub1XM' with 'size_words' | = 3 (N = 96). *----------------------------------------------------------------------------*/ #define softfloat_sub1X96M( zPtr ) softfloat_sub1XM( 3, zPtr ) #endif #ifndef softfloat_sub1X160M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_sub1XM' with 'size_words' | = 5 (N = 160). *----------------------------------------------------------------------------*/ #define softfloat_sub1X160M( zPtr ) softfloat_sub1XM( 5, zPtr ) #endif #ifndef softfloat_subM /*---------------------------------------------------------------------------- | Subtracts the two N-bit integers pointed to by 'aPtr' and 'bPtr', where N = | 'size_words' * 32. The subtraction is modulo 2^N, so any borrow out (carry | out) is lost. The N-bit difference is stored at the location pointed to by | 'zPtr'. Each of 'aPtr', 'bPtr', and 'zPtr' points to a 'size_words'-long | array of 32-bit elements that concatenate in the platform's normal endian | order to form an N-bit integer. *----------------------------------------------------------------------------*/ void softfloat_subM( uint_fast8_t size_words, const uint32_t *aPtr, const uint32_t *bPtr, uint32_t *zPtr ); #endif #ifndef softfloat_sub96M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_subM' with 'size_words' | = 3 (N = 96). *----------------------------------------------------------------------------*/ #define softfloat_sub96M( aPtr, bPtr, zPtr ) softfloat_subM( 3, aPtr, bPtr, zPtr ) #endif #ifndef softfloat_sub128M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_subM' with 'size_words' | = 4 (N = 128). *----------------------------------------------------------------------------*/ #define softfloat_sub128M( aPtr, bPtr, zPtr ) softfloat_subM( 4, aPtr, bPtr, zPtr ) #endif #ifndef softfloat_sub160M /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_subM' with 'size_words' | = 5 (N = 160). *----------------------------------------------------------------------------*/ #define softfloat_sub160M( aPtr, bPtr, zPtr ) softfloat_subM( 5, aPtr, bPtr, zPtr ) #endif #ifndef softfloat_mul64To128M /*---------------------------------------------------------------------------- | Multiplies 'a' and 'b' and stores the 128-bit product at the location | pointed to by 'zPtr'. Argument 'zPtr' points to an array of four 32-bit | elements that concatenate in the platform's normal endian order to form a | 128-bit integer. *----------------------------------------------------------------------------*/ void softfloat_mul64To128M( uint64_t a, uint64_t b, uint32_t *zPtr ); #endif #ifndef softfloat_mul128MTo256M /*---------------------------------------------------------------------------- | Multiplies the two 128-bit unsigned integers pointed to by 'aPtr' and | 'bPtr', and stores the 256-bit product at the location pointed to by 'zPtr'. | Each of 'aPtr' and 'bPtr' points to an array of four 32-bit elements that | concatenate in the platform's normal endian order to form a 128-bit integer. | Argument 'zPtr' points to an array of eight 32-bit elements that concatenate | to form a 256-bit integer. *----------------------------------------------------------------------------*/ void softfloat_mul128MTo256M( const uint32_t *aPtr, const uint32_t *bPtr, uint32_t *zPtr ); #endif #ifndef softfloat_remStepMBy32 /*---------------------------------------------------------------------------- | Performs a "remainder reduction step" as follows: Arguments 'remPtr' and | 'bPtr' both point to N-bit unsigned integers, where N = 'size_words' * 32. | Defining R and B as the values of those integers, the expression (R<<'dist') | - B * q is computed modulo 2^N, and the N-bit result is stored at the | location pointed to by 'zPtr'. Each of 'remPtr', 'bPtr', and 'zPtr' points | to a 'size_words'-long array of 32-bit elements that concatenate in the | platform's normal endian order to form an N-bit integer. *----------------------------------------------------------------------------*/ void softfloat_remStepMBy32( uint_fast8_t size_words, const uint32_t *remPtr, uint_fast8_t dist, const uint32_t *bPtr, uint32_t q, uint32_t *zPtr ); #endif #ifndef softfloat_remStep96MBy32 /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_remStepMBy32' with | 'size_words' = 3 (N = 96). *----------------------------------------------------------------------------*/ #define softfloat_remStep96MBy32( remPtr, dist, bPtr, q, zPtr ) softfloat_remStepMBy32( 3, remPtr, dist, bPtr, q, zPtr ) #endif #ifndef softfloat_remStep128MBy32 /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_remStepMBy32' with | 'size_words' = 4 (N = 128). *----------------------------------------------------------------------------*/ #define softfloat_remStep128MBy32( remPtr, dist, bPtr, q, zPtr ) softfloat_remStepMBy32( 4, remPtr, dist, bPtr, q, zPtr ) #endif #ifndef softfloat_remStep160MBy32 /*---------------------------------------------------------------------------- | This function or macro is the same as 'softfloat_remStepMBy32' with | 'size_words' = 5 (N = 160). *----------------------------------------------------------------------------*/ #define softfloat_remStep160MBy32( remPtr, dist, bPtr, q, zPtr ) softfloat_remStepMBy32( 5, remPtr, dist, bPtr, q, zPtr ) #endif #endif #ifdef __cplusplus } #endif #endif ================================================ FILE: vp/src/vendor/softfloat/include/softfloat/softfloat.h ================================================ /*============================================================================ This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ /*============================================================================ | Note: If SoftFloat is made available as a general library for programs to | use, it is strongly recommended that a platform-specific version of this | header, "softfloat.h", be created that folds in "softfloat_types.h" and that | eliminates all dependencies on compile-time macros. *============================================================================*/ #ifndef softfloat_h #define softfloat_h 1 #include #include #include "softfloat_types.h" #ifndef THREAD_LOCAL #define THREAD_LOCAL #endif #ifdef __cplusplus extern "C" { #endif /*---------------------------------------------------------------------------- | Software floating-point underflow tininess-detection mode. *----------------------------------------------------------------------------*/ extern THREAD_LOCAL uint_fast8_t softfloat_detectTininess; enum { softfloat_tininess_beforeRounding = 0, softfloat_tininess_afterRounding = 1 }; /*---------------------------------------------------------------------------- | Software floating-point rounding mode. (Mode "odd" is supported only if | SoftFloat is compiled with macro 'SOFTFLOAT_ROUND_ODD' defined.) *----------------------------------------------------------------------------*/ extern THREAD_LOCAL uint_fast8_t softfloat_roundingMode; enum { softfloat_round_near_even = 0, softfloat_round_minMag = 1, softfloat_round_min = 2, softfloat_round_max = 3, softfloat_round_near_maxMag = 4, softfloat_round_odd = 5 }; /*---------------------------------------------------------------------------- | Software floating-point exception flags. *----------------------------------------------------------------------------*/ extern THREAD_LOCAL uint_fast8_t softfloat_exceptionFlags; enum { softfloat_flag_inexact = 1, softfloat_flag_underflow = 2, softfloat_flag_overflow = 4, softfloat_flag_infinite = 8, softfloat_flag_invalid = 16 }; /*---------------------------------------------------------------------------- | Routine to raise any or all of the software floating-point exception flags. *----------------------------------------------------------------------------*/ void softfloat_raiseFlags( uint_fast8_t ); /*---------------------------------------------------------------------------- | Integer-to-floating-point conversion routines. *----------------------------------------------------------------------------*/ float16_t ui32_to_f16( uint32_t ); float32_t ui32_to_f32( uint32_t ); float64_t ui32_to_f64( uint32_t ); #ifdef SOFTFLOAT_FAST_INT64 extFloat80_t ui32_to_extF80( uint32_t ); float128_t ui32_to_f128( uint32_t ); #endif void ui32_to_extF80M( uint32_t, extFloat80_t * ); void ui32_to_f128M( uint32_t, float128_t * ); float16_t ui64_to_f16( uint64_t ); float32_t ui64_to_f32( uint64_t ); float64_t ui64_to_f64( uint64_t ); #ifdef SOFTFLOAT_FAST_INT64 extFloat80_t ui64_to_extF80( uint64_t ); float128_t ui64_to_f128( uint64_t ); #endif void ui64_to_extF80M( uint64_t, extFloat80_t * ); void ui64_to_f128M( uint64_t, float128_t * ); float16_t i32_to_f16( int32_t ); float32_t i32_to_f32( int32_t ); float64_t i32_to_f64( int32_t ); #ifdef SOFTFLOAT_FAST_INT64 extFloat80_t i32_to_extF80( int32_t ); float128_t i32_to_f128( int32_t ); #endif void i32_to_extF80M( int32_t, extFloat80_t * ); void i32_to_f128M( int32_t, float128_t * ); float16_t i64_to_f16( int64_t ); float32_t i64_to_f32( int64_t ); float64_t i64_to_f64( int64_t ); #ifdef SOFTFLOAT_FAST_INT64 extFloat80_t i64_to_extF80( int64_t ); float128_t i64_to_f128( int64_t ); #endif void i64_to_extF80M( int64_t, extFloat80_t * ); void i64_to_f128M( int64_t, float128_t * ); /*---------------------------------------------------------------------------- | 16-bit (half-precision) floating-point operations. *----------------------------------------------------------------------------*/ uint_fast32_t f16_to_ui32( float16_t, uint_fast8_t, bool ); uint_fast64_t f16_to_ui64( float16_t, uint_fast8_t, bool ); int_fast32_t f16_to_i32( float16_t, uint_fast8_t, bool ); int_fast64_t f16_to_i64( float16_t, uint_fast8_t, bool ); uint_fast32_t f16_to_ui32_r_minMag( float16_t, bool ); uint_fast64_t f16_to_ui64_r_minMag( float16_t, bool ); int_fast32_t f16_to_i32_r_minMag( float16_t, bool ); int_fast64_t f16_to_i64_r_minMag( float16_t, bool ); float32_t f16_to_f32( float16_t ); float64_t f16_to_f64( float16_t ); #ifdef SOFTFLOAT_FAST_INT64 extFloat80_t f16_to_extF80( float16_t ); float128_t f16_to_f128( float16_t ); #endif void f16_to_extF80M( float16_t, extFloat80_t * ); void f16_to_f128M( float16_t, float128_t * ); float16_t f16_roundToInt( float16_t, uint_fast8_t, bool ); float16_t f16_add( float16_t, float16_t ); float16_t f16_sub( float16_t, float16_t ); float16_t f16_mul( float16_t, float16_t ); float16_t f16_mulAdd( float16_t, float16_t, float16_t ); float16_t f16_div( float16_t, float16_t ); float16_t f16_rem( float16_t, float16_t ); float16_t f16_sqrt( float16_t ); bool f16_eq( float16_t, float16_t ); bool f16_le( float16_t, float16_t ); bool f16_lt( float16_t, float16_t ); bool f16_eq_signaling( float16_t, float16_t ); bool f16_le_quiet( float16_t, float16_t ); bool f16_lt_quiet( float16_t, float16_t ); bool f16_isSignalingNaN( float16_t ); /*---------------------------------------------------------------------------- | 32-bit (single-precision) floating-point operations. *----------------------------------------------------------------------------*/ uint_fast32_t f32_to_ui32( float32_t, uint_fast8_t, bool ); uint_fast64_t f32_to_ui64( float32_t, uint_fast8_t, bool ); int_fast32_t f32_to_i32( float32_t, uint_fast8_t, bool ); int_fast64_t f32_to_i64( float32_t, uint_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 ); float16_t f32_to_f16( float32_t ); float64_t f32_to_f64( float32_t ); #ifdef SOFTFLOAT_FAST_INT64 extFloat80_t f32_to_extF80( float32_t ); float128_t f32_to_f128( float32_t ); #endif void f32_to_extF80M( float32_t, extFloat80_t * ); void f32_to_f128M( float32_t, float128_t * ); float32_t f32_roundToInt( float32_t, uint_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, uint_fast8_t, bool ); uint_fast64_t f64_to_ui64( float64_t, uint_fast8_t, bool ); int_fast32_t f64_to_i32( float64_t, uint_fast8_t, bool ); int_fast64_t f64_to_i64( float64_t, uint_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 ); float16_t f64_to_f16( float64_t ); float32_t f64_to_f32( float64_t ); #ifdef SOFTFLOAT_FAST_INT64 extFloat80_t f64_to_extF80( float64_t ); float128_t f64_to_f128( float64_t ); #endif void f64_to_extF80M( float64_t, extFloat80_t * ); void f64_to_f128M( float64_t, float128_t * ); float64_t f64_roundToInt( float64_t, uint_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 ); /*---------------------------------------------------------------------------- | Rounding precision for 80-bit extended double-precision floating-point. | Valid values are 32, 64, and 80. *----------------------------------------------------------------------------*/ extern THREAD_LOCAL uint_fast8_t extF80_roundingPrecision; /*---------------------------------------------------------------------------- | 80-bit extended double-precision floating-point operations. *----------------------------------------------------------------------------*/ #ifdef SOFTFLOAT_FAST_INT64 uint_fast32_t extF80_to_ui32( extFloat80_t, uint_fast8_t, bool ); uint_fast64_t extF80_to_ui64( extFloat80_t, uint_fast8_t, bool ); int_fast32_t extF80_to_i32( extFloat80_t, uint_fast8_t, bool ); int_fast64_t extF80_to_i64( extFloat80_t, uint_fast8_t, bool ); uint_fast32_t extF80_to_ui32_r_minMag( extFloat80_t, bool ); uint_fast64_t extF80_to_ui64_r_minMag( extFloat80_t, bool ); int_fast32_t extF80_to_i32_r_minMag( extFloat80_t, bool ); int_fast64_t extF80_to_i64_r_minMag( extFloat80_t, bool ); float16_t extF80_to_f16( extFloat80_t ); float32_t extF80_to_f32( extFloat80_t ); float64_t extF80_to_f64( extFloat80_t ); float128_t extF80_to_f128( extFloat80_t ); extFloat80_t extF80_roundToInt( extFloat80_t, uint_fast8_t, bool ); extFloat80_t extF80_add( extFloat80_t, extFloat80_t ); extFloat80_t extF80_sub( extFloat80_t, extFloat80_t ); extFloat80_t extF80_mul( extFloat80_t, extFloat80_t ); extFloat80_t extF80_div( extFloat80_t, extFloat80_t ); extFloat80_t extF80_rem( extFloat80_t, extFloat80_t ); extFloat80_t extF80_sqrt( extFloat80_t ); bool extF80_eq( extFloat80_t, extFloat80_t ); bool extF80_le( extFloat80_t, extFloat80_t ); bool extF80_lt( extFloat80_t, extFloat80_t ); bool extF80_eq_signaling( extFloat80_t, extFloat80_t ); bool extF80_le_quiet( extFloat80_t, extFloat80_t ); bool extF80_lt_quiet( extFloat80_t, extFloat80_t ); bool extF80_isSignalingNaN( extFloat80_t ); #endif uint_fast32_t extF80M_to_ui32( const extFloat80_t *, uint_fast8_t, bool ); uint_fast64_t extF80M_to_ui64( const extFloat80_t *, uint_fast8_t, bool ); int_fast32_t extF80M_to_i32( const extFloat80_t *, uint_fast8_t, bool ); int_fast64_t extF80M_to_i64( const extFloat80_t *, uint_fast8_t, bool ); uint_fast32_t extF80M_to_ui32_r_minMag( const extFloat80_t *, bool ); uint_fast64_t extF80M_to_ui64_r_minMag( const extFloat80_t *, bool ); int_fast32_t extF80M_to_i32_r_minMag( const extFloat80_t *, bool ); int_fast64_t extF80M_to_i64_r_minMag( const extFloat80_t *, bool ); float16_t extF80M_to_f16( const extFloat80_t * ); float32_t extF80M_to_f32( const extFloat80_t * ); float64_t extF80M_to_f64( const extFloat80_t * ); void extF80M_to_f128M( const extFloat80_t *, float128_t * ); void extF80M_roundToInt( const extFloat80_t *, uint_fast8_t, bool, extFloat80_t * ); void extF80M_add( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); void extF80M_sub( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); void extF80M_mul( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); void extF80M_div( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); void extF80M_rem( const extFloat80_t *, const extFloat80_t *, extFloat80_t * ); void extF80M_sqrt( const extFloat80_t *, extFloat80_t * ); bool extF80M_eq( const extFloat80_t *, const extFloat80_t * ); bool extF80M_le( const extFloat80_t *, const extFloat80_t * ); bool extF80M_lt( const extFloat80_t *, const extFloat80_t * ); bool extF80M_eq_signaling( const extFloat80_t *, const extFloat80_t * ); bool extF80M_le_quiet( const extFloat80_t *, const extFloat80_t * ); bool extF80M_lt_quiet( const extFloat80_t *, const extFloat80_t * ); bool extF80M_isSignalingNaN( const extFloat80_t * ); /*---------------------------------------------------------------------------- | 128-bit (quadruple-precision) floating-point operations. *----------------------------------------------------------------------------*/ #ifdef SOFTFLOAT_FAST_INT64 uint_fast32_t f128_to_ui32( float128_t, uint_fast8_t, bool ); uint_fast64_t f128_to_ui64( float128_t, uint_fast8_t, bool ); int_fast32_t f128_to_i32( float128_t, uint_fast8_t, bool ); int_fast64_t f128_to_i64( float128_t, uint_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 ); float16_t f128_to_f16( float128_t ); float32_t f128_to_f32( float128_t ); float64_t f128_to_f64( float128_t ); extFloat80_t f128_to_extF80( float128_t ); float128_t f128_roundToInt( float128_t, uint_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 ); uint_fast16_t f128_classify( float128_t ); #endif uint_fast32_t f128M_to_ui32( const float128_t *, uint_fast8_t, bool ); uint_fast64_t f128M_to_ui64( const float128_t *, uint_fast8_t, bool ); int_fast32_t f128M_to_i32( const float128_t *, uint_fast8_t, bool ); int_fast64_t f128M_to_i64( const float128_t *, uint_fast8_t, bool ); uint_fast32_t f128M_to_ui32_r_minMag( const float128_t *, bool ); uint_fast64_t f128M_to_ui64_r_minMag( const float128_t *, bool ); int_fast32_t f128M_to_i32_r_minMag( const float128_t *, bool ); int_fast64_t f128M_to_i64_r_minMag( const float128_t *, bool ); float16_t f128M_to_f16( const float128_t * ); float32_t f128M_to_f32( const float128_t * ); float64_t f128M_to_f64( const float128_t * ); void f128M_to_extF80M( const float128_t *, extFloat80_t * ); void f128M_roundToInt( const float128_t *, uint_fast8_t, bool, float128_t * ); void f128M_add( const float128_t *, const float128_t *, float128_t * ); void f128M_sub( const float128_t *, const float128_t *, float128_t * ); void f128M_mul( const float128_t *, const float128_t *, float128_t * ); void f128M_mulAdd( const float128_t *, const float128_t *, const float128_t *, float128_t * ); void f128M_div( const float128_t *, const float128_t *, float128_t * ); void f128M_rem( const float128_t *, const float128_t *, float128_t * ); void f128M_sqrt( const float128_t *, float128_t * ); bool f128M_eq( const float128_t *, const float128_t * ); bool f128M_le( const float128_t *, const float128_t * ); bool f128M_lt( const float128_t *, const float128_t * ); bool f128M_eq_signaling( const float128_t *, const float128_t * ); bool f128M_le_quiet( const float128_t *, const float128_t * ); bool f128M_lt_quiet( const float128_t *, const float128_t * ); bool f128M_isSignalingNaN( const float128_t * ); #ifdef __cplusplus } #endif #endif ================================================ FILE: vp/src/vendor/softfloat/include/softfloat/softfloat.hpp ================================================ #pragma once extern "C" { #include "softfloat.h" } ================================================ FILE: vp/src/vendor/softfloat/include/softfloat/softfloat_types.h ================================================ /*============================================================================ This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #ifndef softfloat_types_h #define softfloat_types_h 1 #include /*---------------------------------------------------------------------------- | Types used to pass 16-bit, 32-bit, 64-bit, and 128-bit floating-point | arguments and results to/from functions. These types must be exactly | 16 bits, 32 bits, 64 bits, and 128 bits in size, respectively. Where a | platform has "native" support for IEEE-Standard floating-point formats, | the types below may, if desired, be defined as aliases for the native types | (typically 'float' and 'double', and possibly 'long double'). *----------------------------------------------------------------------------*/ typedef struct { uint16_t v; } float16_t; typedef struct { uint32_t v; } float32_t; typedef struct { uint64_t v; } float64_t; typedef struct { uint64_t v[2]; } float128_t; /*---------------------------------------------------------------------------- | The format of an 80-bit extended floating-point number in memory. This | structure must contain a 16-bit field named 'signExp' and a 64-bit field | named 'signif'. *----------------------------------------------------------------------------*/ #ifdef LITTLEENDIAN struct extFloat80M { uint64_t signif; uint16_t signExp; }; #else struct extFloat80M { uint16_t signExp; uint64_t signif; }; #endif /*---------------------------------------------------------------------------- | The type used to pass 80-bit extended floating-point arguments and | results to/from functions. This type must have size identical to | 'struct extFloat80M'. Type 'extFloat80_t' can be defined as an alias for | 'struct extFloat80M'. Alternatively, if a platform has "native" support | for IEEE-Standard 80-bit extended floating-point, it may be possible, | if desired, to define 'extFloat80_t' as an alias for the native type | (presumably either 'long double' or a nonstandard compiler-intrinsic type). | In that case, the 'signif' and 'signExp' fields of 'struct extFloat80M' | must align exactly with the locations in memory of the sign, exponent, and | significand of the native type. *----------------------------------------------------------------------------*/ typedef struct extFloat80M extFloat80_t; #endif ================================================ FILE: vp/src/vendor/softfloat/include/softfloat/specialize.h ================================================ /*============================================================================ This C header file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #ifndef specialize_h #define specialize_h 1 #include #include #include "primitiveTypes.h" #include "softfloat.h" #ifdef __cplusplus extern "C" { #endif /*---------------------------------------------------------------------------- | Default value for `softfloat_detectTininess'. *----------------------------------------------------------------------------*/ #define init_detectTininess softfloat_tininess_afterRounding /*---------------------------------------------------------------------------- | The values to return on conversions to 32-bit integer formats that raise an | invalid exception. *----------------------------------------------------------------------------*/ #define ui32_fromPosOverflow 0xFFFFFFFF #define ui32_fromNegOverflow 0 #define ui32_fromNaN 0xFFFFFFFF #define i32_fromPosOverflow 0x7FFFFFFF #define i32_fromNegOverflow (-0x7FFFFFFF - 1) #define i32_fromNaN 0x7FFFFFFF /*---------------------------------------------------------------------------- | The values to return on conversions to 64-bit integer formats that raise an | invalid exception. *----------------------------------------------------------------------------*/ #define ui64_fromPosOverflow UINT64_C( 0xFFFFFFFFFFFFFFFF ) #define ui64_fromNegOverflow 0 #define ui64_fromNaN UINT64_C( 0xFFFFFFFFFFFFFFFF ) #define i64_fromPosOverflow UINT64_C( 0x7FFFFFFFFFFFFFFF ) #define i64_fromNegOverflow (-UINT64_C( 0x7FFFFFFFFFFFFFFF ) - 1) #define i64_fromNaN UINT64_C( 0x7FFFFFFFFFFFFFFF ) /*---------------------------------------------------------------------------- | "Common NaN" structure, used to transfer NaN representations from one format | to another. *----------------------------------------------------------------------------*/ struct commonNaN { char _unused; }; /*---------------------------------------------------------------------------- | The bit pattern for a default generated 16-bit floating-point NaN. *----------------------------------------------------------------------------*/ #define defaultNaNF16UI 0x7E00 /*---------------------------------------------------------------------------- | Returns true when 16-bit unsigned integer `uiA' has the bit pattern of a | 16-bit floating-point signaling NaN. | Note: This macro evaluates its argument more than once. *----------------------------------------------------------------------------*/ #define softfloat_isSigNaNF16UI( uiA ) ((((uiA) & 0x7E00) == 0x7C00) && ((uiA) & 0x01FF)) /*---------------------------------------------------------------------------- | Assuming `uiA' has the bit pattern of a 16-bit floating-point NaN, converts | this NaN to the common NaN form, and stores the resulting common NaN at the | location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid | exception is raised. *----------------------------------------------------------------------------*/ #define softfloat_f16UIToCommonNaN( uiA, zPtr ) if ( ! ((uiA) & 0x0200) ) softfloat_raiseFlags( softfloat_flag_invalid ) /*---------------------------------------------------------------------------- | Converts the common NaN pointed to by `aPtr' into a 16-bit floating-point | NaN, and returns the bit pattern of this value as an unsigned integer. *----------------------------------------------------------------------------*/ #define softfloat_commonNaNToF16UI( aPtr ) ((uint_fast16_t) defaultNaNF16UI) /*---------------------------------------------------------------------------- | Interpreting `uiA' and `uiB' as the bit patterns of two 16-bit floating- | point values, at least one of which is a NaN, returns the bit pattern of | the combined NaN result. If either `uiA' or `uiB' has the pattern of a | signaling NaN, the invalid exception is raised. *----------------------------------------------------------------------------*/ uint_fast16_t softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ); /*---------------------------------------------------------------------------- | The bit pattern for a default generated 32-bit floating-point NaN. *----------------------------------------------------------------------------*/ #define defaultNaNF32UI 0x7FC00000 /*---------------------------------------------------------------------------- | Returns true when 32-bit unsigned integer `uiA' has the bit pattern of a | 32-bit floating-point signaling NaN. | Note: This macro evaluates its argument more than once. *----------------------------------------------------------------------------*/ #define softfloat_isSigNaNF32UI( uiA ) ((((uiA) & 0x7FC00000) == 0x7F800000) && ((uiA) & 0x003FFFFF)) /*---------------------------------------------------------------------------- | Assuming `uiA' has the bit pattern of a 32-bit floating-point NaN, converts | this NaN to the common NaN form, and stores the resulting common NaN at the | location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid | exception is raised. *----------------------------------------------------------------------------*/ #define softfloat_f32UIToCommonNaN( uiA, zPtr ) if ( ! ((uiA) & 0x00400000) ) softfloat_raiseFlags( softfloat_flag_invalid ) /*---------------------------------------------------------------------------- | Converts the common NaN pointed to by `aPtr' into a 32-bit floating-point | NaN, and returns the bit pattern of this value as an unsigned integer. *----------------------------------------------------------------------------*/ #define softfloat_commonNaNToF32UI( aPtr ) ((uint_fast32_t) defaultNaNF32UI) /*---------------------------------------------------------------------------- | Interpreting `uiA' and `uiB' as the bit patterns of two 32-bit floating- | point values, at least one of which is a NaN, returns the bit pattern of | the combined NaN result. If either `uiA' or `uiB' has the pattern of a | signaling NaN, the invalid exception is raised. *----------------------------------------------------------------------------*/ uint_fast32_t softfloat_propagateNaNF32UI( uint_fast32_t uiA, uint_fast32_t uiB ); /*---------------------------------------------------------------------------- | The bit pattern for a default generated 64-bit floating-point NaN. *----------------------------------------------------------------------------*/ #define defaultNaNF64UI UINT64_C( 0x7FF8000000000000 ) /*---------------------------------------------------------------------------- | Returns true when 64-bit unsigned integer `uiA' has the bit pattern of a | 64-bit floating-point signaling NaN. | Note: This macro evaluates its argument more than once. *----------------------------------------------------------------------------*/ #define softfloat_isSigNaNF64UI( uiA ) ((((uiA) & UINT64_C( 0x7FF8000000000000 )) == UINT64_C( 0x7FF0000000000000 )) && ((uiA) & UINT64_C( 0x0007FFFFFFFFFFFF ))) /*---------------------------------------------------------------------------- | Assuming `uiA' has the bit pattern of a 64-bit floating-point NaN, converts | this NaN to the common NaN form, and stores the resulting common NaN at the | location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid | exception is raised. *----------------------------------------------------------------------------*/ #define softfloat_f64UIToCommonNaN( uiA, zPtr ) if ( ! ((uiA) & UINT64_C( 0x0008000000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) /*---------------------------------------------------------------------------- | Converts the common NaN pointed to by `aPtr' into a 64-bit floating-point | NaN, and returns the bit pattern of this value as an unsigned integer. *----------------------------------------------------------------------------*/ #define softfloat_commonNaNToF64UI( aPtr ) ((uint_fast64_t) defaultNaNF64UI) /*---------------------------------------------------------------------------- | Interpreting `uiA' and `uiB' as the bit patterns of two 64-bit floating- | point values, at least one of which is a NaN, returns the bit pattern of | the combined NaN result. If either `uiA' or `uiB' has the pattern of a | signaling NaN, the invalid exception is raised. *----------------------------------------------------------------------------*/ uint_fast64_t softfloat_propagateNaNF64UI( uint_fast64_t uiA, uint_fast64_t uiB ); /*---------------------------------------------------------------------------- | The bit pattern for a default generated 80-bit extended floating-point NaN. *----------------------------------------------------------------------------*/ #define defaultNaNExtF80UI64 0x7FFF #define defaultNaNExtF80UI0 UINT64_C( 0xC000000000000000 ) /*---------------------------------------------------------------------------- | Returns true when the 80-bit unsigned integer formed from concatenating | 16-bit `uiA64' and 64-bit `uiA0' has the bit pattern of an 80-bit extended | floating-point signaling NaN. | Note: This macro evaluates its arguments more than once. *----------------------------------------------------------------------------*/ #define softfloat_isSigNaNExtF80UI( uiA64, uiA0 ) ((((uiA64) & 0x7FFF) == 0x7FFF) && ! ((uiA0) & UINT64_C( 0x4000000000000000 )) && ((uiA0) & UINT64_C( 0x3FFFFFFFFFFFFFFF ))) #ifdef SOFTFLOAT_FAST_INT64 /*---------------------------------------------------------------------------- | The following functions are needed only when `SOFTFLOAT_FAST_INT64' is | defined. *----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------- | Assuming the unsigned integer formed from concatenating `uiA64' and `uiA0' | has the bit pattern of an 80-bit extended floating-point NaN, converts | this NaN to the common NaN form, and stores the resulting common NaN at the | location pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid | exception is raised. *----------------------------------------------------------------------------*/ #define softfloat_extF80UIToCommonNaN( uiA64, uiA0, zPtr ) if ( ! ((uiA0) & UINT64_C( 0x4000000000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) /*---------------------------------------------------------------------------- | Converts the common NaN pointed to by `aPtr' into an 80-bit extended | floating-point NaN, and returns the bit pattern of this value as an unsigned | integer. *----------------------------------------------------------------------------*/ #if defined INLINE && ! defined softfloat_commonNaNToExtF80UI INLINE struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ) { struct uint128 uiZ; uiZ.v64 = defaultNaNExtF80UI64; uiZ.v0 = defaultNaNExtF80UI0; return uiZ; } #else struct uint128 softfloat_commonNaNToExtF80UI( const struct commonNaN *aPtr ); #endif /*---------------------------------------------------------------------------- | Interpreting the unsigned integer formed from concatenating `uiA64' and | `uiA0' as an 80-bit extended floating-point value, and likewise interpreting | the unsigned integer formed from concatenating `uiB64' and `uiB0' as another | 80-bit extended floating-point value, and assuming at least on of these | floating-point values is a NaN, returns the bit pattern of the combined NaN | result. If either original floating-point value is a signaling NaN, the | invalid exception is raised. *----------------------------------------------------------------------------*/ struct uint128 softfloat_propagateNaNExtF80UI( uint_fast16_t uiA64, uint_fast64_t uiA0, uint_fast16_t uiB64, uint_fast64_t uiB0 ); /*---------------------------------------------------------------------------- | The bit pattern for a default generated 128-bit floating-point NaN. *----------------------------------------------------------------------------*/ #define defaultNaNF128UI64 UINT64_C( 0x7FFF800000000000 ) #define defaultNaNF128UI0 UINT64_C( 0 ) /*---------------------------------------------------------------------------- | Returns true when the 128-bit unsigned integer formed from concatenating | 64-bit `uiA64' and 64-bit `uiA0' has the bit pattern of a 128-bit floating- | point signaling NaN. | Note: This macro evaluates its arguments more than once. *----------------------------------------------------------------------------*/ #define softfloat_isSigNaNF128UI( uiA64, uiA0 ) ((((uiA64) & UINT64_C( 0x7FFF800000000000 )) == UINT64_C( 0x7FFF000000000000 )) && ((uiA0) || ((uiA64) & UINT64_C( 0x00007FFFFFFFFFFF )))) /*---------------------------------------------------------------------------- | Assuming the unsigned integer formed from concatenating `uiA64' and `uiA0' | has the bit pattern of a 128-bit floating-point NaN, converts this NaN to | the common NaN form, and stores the resulting common NaN at the location | pointed to by `zPtr'. If the NaN is a signaling NaN, the invalid exception | is raised. *----------------------------------------------------------------------------*/ #define softfloat_f128UIToCommonNaN( uiA64, uiA0, zPtr ) if ( ! ((uiA64) & UINT64_C( 0x0000800000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) /*---------------------------------------------------------------------------- | Converts the common NaN pointed to by `aPtr' into a 128-bit floating-point | NaN, and returns the bit pattern of this value as an unsigned integer. *----------------------------------------------------------------------------*/ #if defined INLINE && ! defined softfloat_commonNaNToF128UI INLINE struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr ) { struct uint128 uiZ; uiZ.v64 = defaultNaNF128UI64; uiZ.v0 = defaultNaNF128UI0; return uiZ; } #else struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN * ); #endif /*---------------------------------------------------------------------------- | Interpreting the unsigned integer formed from concatenating `uiA64' and | `uiA0' as a 128-bit floating-point value, and likewise interpreting the | unsigned integer formed from concatenating `uiB64' and `uiB0' as another | 128-bit floating-point value, and assuming at least on of these floating- | point values is a NaN, returns the bit pattern of the combined NaN result. | If either original floating-point value is a signaling NaN, the invalid | exception is raised. *----------------------------------------------------------------------------*/ struct uint128 softfloat_propagateNaNF128UI( uint_fast64_t uiA64, uint_fast64_t uiA0, uint_fast64_t uiB64, uint_fast64_t uiB0 ); #else /*---------------------------------------------------------------------------- | The following functions are needed only when `SOFTFLOAT_FAST_INT64' is not | defined. *----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------- | Assuming the 80-bit extended floating-point value pointed to by `aSPtr' is | a NaN, converts this NaN to the common NaN form, and stores the resulting | common NaN at the location pointed to by `zPtr'. If the NaN is a signaling | NaN, the invalid exception is raised. *----------------------------------------------------------------------------*/ #define softfloat_extF80MToCommonNaN( aSPtr, zPtr ) if ( ! ((aSPtr)->signif & UINT64_C( 0x4000000000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) /*---------------------------------------------------------------------------- | Converts the common NaN pointed to by `aPtr' into an 80-bit extended | floating-point NaN, and stores this NaN at the location pointed to by | `zSPtr'. *----------------------------------------------------------------------------*/ #if defined INLINE && ! defined softfloat_commonNaNToExtF80M INLINE void softfloat_commonNaNToExtF80M( const struct commonNaN *aPtr, struct extFloat80M *zSPtr ) { zSPtr->signExp = defaultNaNExtF80UI64; zSPtr->signif = defaultNaNExtF80UI0; } #else void softfloat_commonNaNToExtF80M( const struct commonNaN *aPtr, struct extFloat80M *zSPtr ); #endif /*---------------------------------------------------------------------------- | Assuming at least one of the two 80-bit extended floating-point values | pointed to by `aSPtr' and `bSPtr' is a NaN, stores the combined NaN result | at the location pointed to by `zSPtr'. If either original floating-point | value is a signaling NaN, the invalid exception is raised. *----------------------------------------------------------------------------*/ void softfloat_propagateNaNExtF80M( const struct extFloat80M *aSPtr, const struct extFloat80M *bSPtr, struct extFloat80M *zSPtr ); /*---------------------------------------------------------------------------- | The bit pattern for a default generated 128-bit floating-point NaN. *----------------------------------------------------------------------------*/ #define defaultNaNF128UI96 0x7FFF8000 #define defaultNaNF128UI64 0 #define defaultNaNF128UI32 0 #define defaultNaNF128UI0 0 /*---------------------------------------------------------------------------- | Assuming the 128-bit floating-point value pointed to by `aWPtr' is a NaN, | converts this NaN to the common NaN form, and stores the resulting common | NaN at the location pointed to by `zPtr'. If the NaN is a signaling NaN, | the invalid exception is raised. Argument `aWPtr' points to an array of | four 32-bit elements that concatenate in the platform's normal endian order | to form a 128-bit floating-point value. *----------------------------------------------------------------------------*/ #define softfloat_f128MToCommonNaN( aWPtr, zPtr ) if ( ! ((aWPtr)[indexWordHi( 4 )] & UINT64_C( 0x0000800000000000 )) ) softfloat_raiseFlags( softfloat_flag_invalid ) /*---------------------------------------------------------------------------- | Converts the common NaN pointed to by `aPtr' into a 128-bit floating-point | NaN, and stores this NaN at the location pointed to by `zWPtr'. Argument | `zWPtr' points to an array of four 32-bit elements that concatenate in the | platform's normal endian order to form a 128-bit floating-point value. *----------------------------------------------------------------------------*/ #if defined INLINE && ! defined softfloat_commonNaNToF128M INLINE void softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ) { zWPtr[indexWord( 4, 3 )] = defaultNaNF128UI96; zWPtr[indexWord( 4, 2 )] = defaultNaNF128UI64; zWPtr[indexWord( 4, 1 )] = defaultNaNF128UI32; zWPtr[indexWord( 4, 0 )] = defaultNaNF128UI0; } #else void softfloat_commonNaNToF128M( const struct commonNaN *aPtr, uint32_t *zWPtr ); #endif /*---------------------------------------------------------------------------- | Assuming at least one of the two 128-bit floating-point values pointed to by | `aWPtr' and `bWPtr' is a NaN, stores the combined NaN result at the location | pointed to by `zWPtr'. If either original floating-point value is a | signaling NaN, the invalid exception is raised. Each of `aWPtr', `bWPtr', | and `zWPtr' points to an array of four 32-bit elements that concatenate in | the platform's normal endian order to form a 128-bit floating-point value. *----------------------------------------------------------------------------*/ void softfloat_propagateNaNF128M( const uint32_t *aWPtr, const uint32_t *bWPtr, uint32_t *zWPtr ); #endif #ifdef __cplusplus } #endif #endif ================================================ FILE: vp/src/vendor/softfloat/s_add128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_add128 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.v0 < a0); return z; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_add256M.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_add256M void softfloat_add256M( const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr ) { unsigned int index; uint_fast8_t carry; uint64_t wordA, wordZ; index = indexWordLo( 4 ); carry = 0; for (;;) { wordA = aPtr[index]; wordZ = wordA + bPtr[index] + carry; zPtr[index] = wordZ; if ( index == indexWordHi( 4 ) ) break; if ( wordZ != wordA ) carry = (wordZ < wordA); index += wordIncr; } } #endif ================================================ FILE: vp/src/vendor/softfloat/s_addCarryM.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_addCarryM uint_fast8_t softfloat_addCarryM( uint_fast8_t size_words, const uint32_t *aPtr, const uint32_t *bPtr, uint_fast8_t carry, uint32_t *zPtr ) { unsigned int index, lastIndex; uint32_t wordA, wordZ; index = indexWordLo( size_words ); lastIndex = indexWordHi( size_words ); for (;;) { wordA = aPtr[index]; wordZ = wordA + bPtr[index] + carry; zPtr[index] = wordZ; if ( wordZ != wordA ) carry = (wordZ < wordA); if ( index == lastIndex ) break; index += wordIncr; } return carry; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_addComplCarryM.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_addComplCarryM uint_fast8_t softfloat_addComplCarryM( uint_fast8_t size_words, const uint32_t *aPtr, const uint32_t *bPtr, uint_fast8_t carry, uint32_t *zPtr ) { unsigned int index, lastIndex; uint32_t wordA, wordZ; index = indexWordLo( size_words ); lastIndex = indexWordHi( size_words ); for (;;) { wordA = aPtr[index]; wordZ = wordA + ~bPtr[index] + carry; zPtr[index] = wordZ; if ( wordZ != wordA ) carry = (wordZ < wordA); if ( index == lastIndex ) break; index += wordIncr; } return carry; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_addM.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_addM void softfloat_addM( uint_fast8_t size_words, const uint32_t *aPtr, const uint32_t *bPtr, uint32_t *zPtr ) { unsigned int index, lastIndex; uint_fast8_t carry; uint32_t wordA, wordZ; index = indexWordLo( size_words ); lastIndex = indexWordHi( size_words ); carry = 0; for (;;) { wordA = aPtr[index]; wordZ = wordA + bPtr[index] + carry; zPtr[index] = wordZ; if ( index == lastIndex ) break; if ( wordZ != wordA ) carry = (wordZ < wordA); index += wordIncr; } } #endif ================================================ FILE: vp/src/vendor/softfloat/s_addMagsF128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" float128_t softfloat_addMagsF128( uint_fast64_t uiA64, uint_fast64_t uiA0, uint_fast64_t uiB64, uint_fast64_t uiB0, bool signZ ) { int_fast32_t expA; struct uint128 sigA; int_fast32_t expB; struct uint128 sigB; int_fast32_t expDiff; struct uint128 uiZ, sigZ; int_fast32_t expZ; uint_fast64_t sigZExtra; struct uint128_extra sig128Extra; union ui128_f128 uZ; expA = expF128UI64( uiA64 ); sigA.v64 = fracF128UI64( uiA64 ); sigA.v0 = uiA0; expB = expF128UI64( uiB64 ); sigB.v64 = fracF128UI64( uiB64 ); sigB.v0 = uiB0; expDiff = expA - expB; if ( ! expDiff ) { if ( expA == 0x7FFF ) { if ( sigA.v64 | sigA.v0 | sigB.v64 | sigB.v0 ) goto propagateNaN; uiZ.v64 = uiA64; uiZ.v0 = uiA0; goto uiZ; } sigZ = softfloat_add128( sigA.v64, sigA.v0, sigB.v64, sigB.v0 ); if ( ! expA ) { uiZ.v64 = packToF128UI64( signZ, 0, sigZ.v64 ); uiZ.v0 = sigZ.v0; goto uiZ; } expZ = expA; sigZ.v64 |= UINT64_C( 0x0002000000000000 ); sigZExtra = 0; goto shiftRight1; } if ( expDiff < 0 ) { if ( expB == 0x7FFF ) { if ( sigB.v64 | sigB.v0 ) goto propagateNaN; uiZ.v64 = packToF128UI64( signZ, 0x7FFF, 0 ); uiZ.v0 = 0; goto uiZ; } expZ = expB; if ( expA ) { sigA.v64 |= UINT64_C( 0x0001000000000000 ); } else { ++expDiff; sigZExtra = 0; if ( ! expDiff ) goto newlyAligned; } sig128Extra = softfloat_shiftRightJam128Extra( sigA.v64, sigA.v0, 0, -expDiff ); sigA = sig128Extra.v; sigZExtra = sig128Extra.extra; } else { if ( expA == 0x7FFF ) { if ( sigA.v64 | sigA.v0 ) goto propagateNaN; uiZ.v64 = uiA64; uiZ.v0 = uiA0; goto uiZ; } expZ = expA; if ( expB ) { sigB.v64 |= UINT64_C( 0x0001000000000000 ); } else { --expDiff; sigZExtra = 0; if ( ! expDiff ) goto newlyAligned; } sig128Extra = softfloat_shiftRightJam128Extra( sigB.v64, sigB.v0, 0, expDiff ); sigB = sig128Extra.v; sigZExtra = sig128Extra.extra; } newlyAligned: sigZ = softfloat_add128( sigA.v64 | UINT64_C( 0x0001000000000000 ), sigA.v0, sigB.v64, sigB.v0 ); --expZ; if ( sigZ.v64 < UINT64_C( 0x0002000000000000 ) ) goto roundAndPack; ++expZ; shiftRight1: sig128Extra = softfloat_shortShiftRightJam128Extra( sigZ.v64, sigZ.v0, sigZExtra, 1 ); sigZ = sig128Extra.v; sigZExtra = sig128Extra.extra; roundAndPack: return softfloat_roundPackToF128( signZ, expZ, sigZ.v64, sigZ.v0, sigZExtra ); propagateNaN: uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/s_addMagsF16.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float16_t softfloat_addMagsF16( uint_fast16_t uiA, uint_fast16_t uiB ) { int_fast8_t expA; uint_fast16_t sigA; int_fast8_t expB; uint_fast16_t sigB; int_fast8_t expDiff; uint_fast16_t uiZ; bool signZ; int_fast8_t expZ; uint_fast16_t sigZ; uint_fast16_t sigX, sigY; int_fast8_t shiftDist; uint_fast32_t sig32Z; int_fast8_t roundingMode; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expA = expF16UI( uiA ); sigA = fracF16UI( uiA ); expB = expF16UI( uiB ); sigB = fracF16UI( uiB ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expA - expB; if ( ! expDiff ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( ! expA ) { uiZ = uiA + sigB; goto uiZ; } if ( expA == 0x1F ) { if ( sigA | sigB ) goto propagateNaN; uiZ = uiA; goto uiZ; } signZ = signF16UI( uiA ); expZ = expA; sigZ = 0x0800 + sigA + sigB; if ( ! (sigZ & 1) && (expZ < 0x1E) ) { sigZ >>= 1; goto pack; } sigZ <<= 3; } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ signZ = signF16UI( uiA ); if ( expDiff < 0 ) { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ if ( expB == 0x1F ) { if ( sigB ) goto propagateNaN; uiZ = packToF16UI( signZ, 0x1F, 0 ); goto uiZ; } if ( expDiff <= -13 ) { uiZ = packToF16UI( signZ, expB, sigB ); if ( expA | sigA ) goto addEpsilon; goto uiZ; } expZ = expB; sigX = sigB | 0x0400; sigY = sigA + (expA ? 0x0400 : sigA); shiftDist = 19 + expDiff; } else { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ uiZ = uiA; if ( expA == 0x1F ) { if ( sigA ) goto propagateNaN; goto uiZ; } if ( 13 <= expDiff ) { if ( expB | sigB ) goto addEpsilon; goto uiZ; } expZ = expA; sigX = sigA | 0x0400; sigY = sigB + (expB ? 0x0400 : sigB); shiftDist = 19 - expDiff; } sig32Z = ((uint_fast32_t) sigX<<19) + ((uint_fast32_t) sigY<>16; if ( sig32Z & 0xFFFF ) { sigZ |= 1; } else { if ( ! (sigZ & 0xF) && (expZ < 0x1E) ) { sigZ >>= 4; goto pack; } } } return softfloat_roundPackToF16( signZ, expZ, sigZ ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ addEpsilon: roundingMode = softfloat_roundingMode; if ( roundingMode != softfloat_round_near_even ) { if ( roundingMode == (signF16UI( uiZ ) ? softfloat_round_min : softfloat_round_max) ) { ++uiZ; if ( (uint16_t) (uiZ<<1) == 0xF800 ) { softfloat_raiseFlags( softfloat_flag_overflow | softfloat_flag_inexact ); } } #ifdef SOFTFLOAT_ROUND_ODD else if ( roundingMode == softfloat_round_odd ) { uiZ |= 1; } #endif } softfloat_exceptionFlags |= softfloat_flag_inexact; goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ pack: uiZ = packToF16UI( signZ, expZ, sigZ ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/s_addMagsF32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" float32_t softfloat_addMagsF32( uint_fast32_t uiA, uint_fast32_t uiB ) { int_fast16_t expA; uint_fast32_t sigA; int_fast16_t expB; uint_fast32_t sigB; int_fast16_t expDiff; uint_fast32_t uiZ; bool signZ; 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; if ( ! expDiff ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( ! expA ) { uiZ = uiA + sigB; goto uiZ; } if ( expA == 0xFF ) { if ( sigA | sigB ) goto propagateNaN; uiZ = uiA; goto uiZ; } signZ = signF32UI( uiA ); expZ = expA; sigZ = 0x01000000 + sigA + sigB; if ( ! (sigZ & 1) && (expZ < 0xFE) ) { uiZ = packToF32UI( signZ, expZ, sigZ>>1 ); goto uiZ; } sigZ <<= 6; } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ signZ = signF32UI( uiA ); sigA <<= 6; sigB <<= 6; 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_shiftRightJam32( sigA, -expDiff ); } else { if ( expA == 0xFF ) { if ( sigA ) goto propagateNaN; uiZ = uiA; goto uiZ; } expZ = expA; sigB += expB ? 0x20000000 : sigB; sigB = softfloat_shiftRightJam32( 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; } ================================================ FILE: vp/src/vendor/softfloat/s_addMagsF64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.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; if ( ! expDiff ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( ! expA ) { uiZ = uiA + sigB; goto uiZ; } if ( expA == 0x7FF ) { if ( sigA | sigB ) goto propagateNaN; uiZ = uiA; goto uiZ; } expZ = expA; sigZ = UINT64_C( 0x0020000000000000 ) + sigA + sigB; sigZ <<= 9; } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ sigA <<= 9; sigB <<= 9; if ( expDiff < 0 ) { if ( expB == 0x7FF ) { if ( sigB ) goto propagateNaN; uiZ = packToF64UI( signZ, 0x7FF, 0 ); goto uiZ; } expZ = expB; if ( expA ) { sigA += UINT64_C( 0x2000000000000000 ); } else { sigA <<= 1; } sigA = softfloat_shiftRightJam64( sigA, -expDiff ); } else { if ( expA == 0x7FF ) { if ( sigA ) goto propagateNaN; uiZ = uiA; goto uiZ; } expZ = expA; if ( expB ) { sigB += UINT64_C( 0x2000000000000000 ); } else { sigB <<= 1; } sigB = softfloat_shiftRightJam64( 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; } ================================================ FILE: vp/src/vendor/softfloat/s_approxRecip32_1.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #ifndef softfloat_approxRecip32_1 extern const uint16_t softfloat_approxRecip_1k0s[16]; extern const uint16_t softfloat_approxRecip_1k1s[16]; uint32_t softfloat_approxRecip32_1( uint32_t a ) { int index; uint16_t eps, r0; uint32_t sigma0; uint_fast32_t r; uint32_t sqrSigma0; index = a>>27 & 0xF; eps = (uint16_t) (a>>11); r0 = softfloat_approxRecip_1k0s[index] - ((softfloat_approxRecip_1k1s[index] * (uint_fast32_t) eps)>>20); sigma0 = ~(uint_fast32_t) ((r0 * (uint_fast64_t) a)>>7); r = ((uint_fast32_t) r0<<16) + ((r0 * (uint_fast64_t) sigma0)>>24); sqrSigma0 = ((uint_fast64_t) sigma0 * sigma0)>>32; r += ((uint32_t) r * (uint_fast64_t) sqrSigma0)>>48; return r; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_approxRecipSqrt32_1.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #ifndef softfloat_approxRecipSqrt32_1 extern const uint16_t softfloat_approxRecipSqrt_1k0s[]; extern const uint16_t softfloat_approxRecipSqrt_1k1s[]; uint32_t softfloat_approxRecipSqrt32_1( unsigned int oddExpA, uint32_t a ) { int index; uint16_t eps, r0; uint_fast32_t ESqrR0; uint32_t sigma0; uint_fast32_t r; uint32_t sqrSigma0; index = (a>>27 & 0xE) + oddExpA; eps = (uint16_t) (a>>12); r0 = softfloat_approxRecipSqrt_1k0s[index] - ((softfloat_approxRecipSqrt_1k1s[index] * (uint_fast32_t) eps) >>20); ESqrR0 = (uint_fast32_t) r0 * r0; if ( ! oddExpA ) ESqrR0 <<= 1; sigma0 = ~(uint_fast32_t) (((uint32_t) ESqrR0 * (uint_fast64_t) a)>>23); r = ((uint_fast32_t) r0<<16) + ((r0 * (uint_fast64_t) sigma0)>>25); sqrSigma0 = ((uint_fast64_t) sigma0 * sigma0)>>32; r += ((uint32_t) ((r>>1) + (r>>3) - ((uint_fast32_t) r0<<14)) * (uint_fast64_t) sqrSigma0) >>48; if ( ! (r & 0x80000000) ) r = 0x80000000; return r; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_approxRecipSqrt_1Ks.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitives.h" const uint16_t softfloat_approxRecipSqrt_1k0s[16] = { 0xB4C9, 0xFFAB, 0xAA7D, 0xF11C, 0xA1C5, 0xE4C7, 0x9A43, 0xDA29, 0x93B5, 0xD0E5, 0x8DED, 0xC8B7, 0x88C6, 0xC16D, 0x8424, 0xBAE1 }; const uint16_t softfloat_approxRecipSqrt_1k1s[16] = { 0xA5A5, 0xEA42, 0x8C21, 0xC62D, 0x788F, 0xAA7F, 0x6928, 0x94B6, 0x5CC7, 0x8335, 0x52A6, 0x74E2, 0x4A3E, 0x68FE, 0x432B, 0x5EFD }; ================================================ FILE: vp/src/vendor/softfloat/s_approxRecip_1Ks.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitives.h" const uint16_t softfloat_approxRecip_1k0s[16] = { 0xFFC4, 0xF0BE, 0xE363, 0xD76F, 0xCCAD, 0xC2F0, 0xBA16, 0xB201, 0xAA97, 0xA3C6, 0x9D7A, 0x97A6, 0x923C, 0x8D32, 0x887E, 0x8417 }; const uint16_t softfloat_approxRecip_1k1s[16] = { 0xF0F1, 0xD62C, 0xBFA1, 0xAC77, 0x9C0A, 0x8DDB, 0x8185, 0x76BA, 0x6D3B, 0x64D4, 0x5D5C, 0x56B1, 0x50B6, 0x4B55, 0x4679, 0x4211 }; ================================================ FILE: vp/src/vendor/softfloat/s_commonNaNToF128UI.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include "platform.h" #include "primitiveTypes.h" #define softfloat_commonNaNToF128UI softfloat_commonNaNToF128UI #include "specialize.h" /*---------------------------------------------------------------------------- | Converts the common NaN pointed to by `aPtr' into a 128-bit floating-point | NaN, and returns the bit pattern of this value as an unsigned integer. *----------------------------------------------------------------------------*/ struct uint128 softfloat_commonNaNToF128UI( const struct commonNaN *aPtr ) { struct uint128 uiZ; uiZ.v64 = defaultNaNF128UI64; uiZ.v0 = defaultNaNF128UI0; return uiZ; } ================================================ FILE: vp/src/vendor/softfloat/s_commonNaNToF16UI.c ================================================ /*---------------------------------------------------------------------------- | This file intentionally contains no code. *----------------------------------------------------------------------------*/ ================================================ FILE: vp/src/vendor/softfloat/s_commonNaNToF32UI.c ================================================ /*---------------------------------------------------------------------------- | This file intentionally contains no code. *----------------------------------------------------------------------------*/ ================================================ FILE: vp/src/vendor/softfloat/s_commonNaNToF64UI.c ================================================ /*---------------------------------------------------------------------------- | This file intentionally contains no code. *----------------------------------------------------------------------------*/ ================================================ FILE: vp/src/vendor/softfloat/s_compare128M.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_compare128M int_fast8_t softfloat_compare128M( const uint32_t *aPtr, const uint32_t *bPtr ) { unsigned int index, lastIndex; uint32_t wordA, wordB; index = indexWordHi( 4 ); lastIndex = indexWordLo( 4 ); for (;;) { wordA = aPtr[index]; wordB = bPtr[index]; if ( wordA != wordB ) return (wordA < wordB) ? -1 : 1; if ( index == lastIndex ) break; index -= wordIncr; } return 0; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_compare96M.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_compare96M int_fast8_t softfloat_compare96M( const uint32_t *aPtr, const uint32_t *bPtr ) { unsigned int index, lastIndex; uint32_t wordA, wordB; index = indexWordHi( 3 ); lastIndex = indexWordLo( 3 ); for (;;) { wordA = aPtr[index]; wordB = bPtr[index]; if ( wordA != wordB ) return (wordA < wordB) ? -1 : 1; if ( index == lastIndex ) break; index -= wordIncr; } return 0; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_countLeadingZeros16.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #ifndef softfloat_countLeadingZeros16 #define softfloat_countLeadingZeros16 softfloat_countLeadingZeros16 #include "primitives.h" uint_fast8_t softfloat_countLeadingZeros16( uint16_t a ) { uint_fast8_t count; count = 8; if ( 0x100 <= a ) { count = 0; a >>= 8; } count += softfloat_countLeadingZeros8[a]; return count; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_countLeadingZeros32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #ifndef softfloat_countLeadingZeros32 #define softfloat_countLeadingZeros32 softfloat_countLeadingZeros32 #include "primitives.h" uint_fast8_t softfloat_countLeadingZeros32( uint32_t a ) { uint_fast8_t count; count = 0; if ( a < 0x10000 ) { count = 16; a <<= 16; } if ( a < 0x1000000 ) { count += 8; a <<= 8; } count += softfloat_countLeadingZeros8[a>>24]; return count; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_countLeadingZeros64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #ifndef softfloat_countLeadingZeros64 #define softfloat_countLeadingZeros64 softfloat_countLeadingZeros64 #include "primitives.h" uint_fast8_t softfloat_countLeadingZeros64( uint64_t a ) { uint_fast8_t count; uint32_t a32; count = 0; a32 = a>>32; if ( ! a32 ) { count = 32; a32 = a; } /*------------------------------------------------------------------------ | 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; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_countLeadingZeros8.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitives.h" const uint_least8_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 }; ================================================ FILE: vp/src/vendor/softfloat/s_eq128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #ifndef softfloat_eq128 bool softfloat_eq128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) { return (a64 == b64) && (a0 == b0); } #endif ================================================ FILE: vp/src/vendor/softfloat/s_f128UIToCommonNaN.c ================================================ /*---------------------------------------------------------------------------- | This file intentionally contains no code. *----------------------------------------------------------------------------*/ ================================================ FILE: vp/src/vendor/softfloat/s_f16UIToCommonNaN.c ================================================ /*---------------------------------------------------------------------------- | This file intentionally contains no code. *----------------------------------------------------------------------------*/ ================================================ FILE: vp/src/vendor/softfloat/s_f32UIToCommonNaN.c ================================================ /*---------------------------------------------------------------------------- | This file intentionally contains no code. *----------------------------------------------------------------------------*/ ================================================ FILE: vp/src/vendor/softfloat/s_f64UIToCommonNaN.c ================================================ /*---------------------------------------------------------------------------- | This file intentionally contains no code. *----------------------------------------------------------------------------*/ ================================================ FILE: vp/src/vendor/softfloat/s_le128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #ifndef softfloat_le128 bool softfloat_le128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) { return (a64 < b64) || ((a64 == b64) && (a0 <= b0)); } #endif ================================================ FILE: vp/src/vendor/softfloat/s_lt128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #ifndef softfloat_lt128 bool softfloat_lt128( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0 ) { return (a64 < b64) || ((a64 == b64) && (a0 < b0)); } #endif ================================================ FILE: vp/src/vendor/softfloat/s_mul128By32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_mul128By32 struct uint128 softfloat_mul128By32( uint64_t a64, uint64_t a0, uint32_t b ) { struct uint128 z; uint_fast64_t mid; uint_fast32_t carry; z.v0 = a0 * b; mid = (uint_fast64_t) (uint32_t) (a0>>32) * b; carry = (uint32_t) ((uint_fast32_t) (z.v0>>32) - (uint_fast32_t) mid); z.v64 = a64 * b + (uint_fast32_t) ((mid + carry)>>32); return z; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_mul128MTo256M.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_mul128MTo256M void softfloat_mul128MTo256M( const uint32_t *aPtr, const uint32_t *bPtr, uint32_t *zPtr ) { uint32_t *lastZPtr, wordB; uint64_t dwordProd; uint32_t wordZ; uint_fast8_t carry; bPtr += indexWordLo( 4 ); lastZPtr = zPtr + indexMultiwordHi( 8, 5 ); zPtr += indexMultiwordLo( 8, 5 ); wordB = *bPtr; dwordProd = (uint64_t) aPtr[indexWord( 4, 0 )] * wordB; zPtr[indexWord( 5, 0 )] = dwordProd; dwordProd = (uint64_t) aPtr[indexWord( 4, 1 )] * wordB + (dwordProd>>32); zPtr[indexWord( 5, 1 )] = dwordProd; dwordProd = (uint64_t) aPtr[indexWord( 4, 2 )] * wordB + (dwordProd>>32); zPtr[indexWord( 5, 2 )] = dwordProd; dwordProd = (uint64_t) aPtr[indexWord( 4, 3 )] * wordB + (dwordProd>>32); zPtr[indexWord( 5, 3 )] = dwordProd; zPtr[indexWord( 5, 4 )] = dwordProd>>32; do { bPtr += wordIncr; zPtr += wordIncr; wordB = *bPtr; dwordProd = (uint64_t) aPtr[indexWord( 4, 0 )] * wordB; wordZ = zPtr[indexWord( 5, 0 )] + (uint32_t) dwordProd; zPtr[indexWord( 5, 0 )] = wordZ; carry = (wordZ < (uint32_t) dwordProd); dwordProd = (uint64_t) aPtr[indexWord( 4, 1 )] * wordB + (dwordProd>>32); wordZ = zPtr[indexWord( 5, 1 )] + (uint32_t) dwordProd + carry; zPtr[indexWord( 5, 1 )] = wordZ; if ( wordZ != (uint32_t) dwordProd ) { carry = (wordZ < (uint32_t) dwordProd); } dwordProd = (uint64_t) aPtr[indexWord( 4, 2 )] * wordB + (dwordProd>>32); wordZ = zPtr[indexWord( 5, 2 )] + (uint32_t) dwordProd + carry; zPtr[indexWord( 5, 2 )] = wordZ; if ( wordZ != (uint32_t) dwordProd ) { carry = (wordZ < (uint32_t) dwordProd); } dwordProd = (uint64_t) aPtr[indexWord( 4, 3 )] * wordB + (dwordProd>>32); wordZ = zPtr[indexWord( 5, 3 )] + (uint32_t) dwordProd + carry; zPtr[indexWord( 5, 3 )] = wordZ; if ( wordZ != (uint32_t) dwordProd ) { carry = (wordZ < (uint32_t) dwordProd); } zPtr[indexWord( 5, 4 )] = (dwordProd>>32) + carry; } while ( zPtr != lastZPtr ); } #endif ================================================ FILE: vp/src/vendor/softfloat/s_mul128To256M.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #ifndef softfloat_mul128To256M #define softfloat_mul128To256M softfloat_mul128To256M #include "primitives.h" void softfloat_mul128To256M( uint64_t a64, uint64_t a0, uint64_t b64, uint64_t b0, uint64_t *zPtr ) { struct uint128 p0, p64, p128; uint_fast64_t z64, z128, z192; p0 = softfloat_mul64To128( a0, b0 ); zPtr[indexWord( 4, 0 )] = p0.v0; p64 = softfloat_mul64To128( a64, b0 ); z64 = p64.v0 + p0.v64; z128 = p64.v64 + (z64 < p64.v0); p128 = softfloat_mul64To128( a64, b64 ); z128 += p128.v0; z192 = p128.v64 + (z128 < p128.v0); p64 = softfloat_mul64To128( a0, b64 ); z64 += p64.v0; zPtr[indexWord( 4, 1 )] = z64; p64.v64 += (z64 < p64.v0); z128 += p64.v64; zPtr[indexWord( 4, 2 )] = z128; zPtr[indexWord( 4, 3 )] = z192 + (z128 < p64.v64); } #endif ================================================ FILE: vp/src/vendor/softfloat/s_mul64ByShifted32To128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_mul64ByShifted32To128 struct uint128 softfloat_mul64ByShifted32To128( uint64_t a, uint32_t b ) { uint_fast64_t mid; struct uint128 z; mid = (uint_fast64_t) (uint32_t) a * b; z.v0 = mid<<32; z.v64 = (uint_fast64_t) (uint32_t) (a>>32) * b + (mid>>32); return z; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_mul64To128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_mul64To128 struct uint128 softfloat_mul64To128( uint64_t a, uint64_t b ) { uint32_t a32, a0, b32, b0; struct uint128 z; uint64_t mid1, mid; a32 = a>>32; a0 = a; b32 = b>>32; b0 = b; z.v0 = (uint_fast64_t) a0 * b0; mid1 = (uint_fast64_t) a32 * b0; mid = mid1 + (uint_fast64_t) a0 * b32; z.v64 = (uint_fast64_t) a32 * b32; z.v64 += (uint_fast64_t) (mid < mid1)<<32 | mid>>32; mid <<= 32; z.v0 += mid; z.v64 += (z.v0 < mid); return z; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_mul64To128M.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_mul64To128M void softfloat_mul64To128M( uint64_t a, uint64_t b, uint32_t *zPtr ) { uint32_t a32, a0, b32, b0; uint64_t z0, mid1, z64, mid; a32 = a>>32; a0 = a; b32 = b>>32; b0 = b; z0 = (uint64_t) a0 * b0; mid1 = (uint64_t) a32 * b0; mid = mid1 + (uint64_t) a0 * b32; z64 = (uint64_t) a32 * b32; z64 += (uint64_t) (mid < mid1)<<32 | mid>>32; mid <<= 32; z0 += mid; zPtr[indexWord( 4, 1 )] = z0>>32; zPtr[indexWord( 4, 0 )] = z0; z64 += (z0 < mid); zPtr[indexWord( 4, 3 )] = z64>>32; zPtr[indexWord( 4, 2 )] = z64; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_mulAddF128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float128_t softfloat_mulAddF128( uint_fast64_t uiA64, uint_fast64_t uiA0, uint_fast64_t uiB64, uint_fast64_t uiB0, uint_fast64_t uiC64, uint_fast64_t uiC0, uint_fast8_t op ) { bool signA; int_fast32_t expA; struct uint128 sigA; bool signB; int_fast32_t expB; struct uint128 sigB; bool signC; int_fast32_t expC; struct uint128 sigC; bool signZ; uint_fast64_t magBits; struct uint128 uiZ; struct exp32_sig128 normExpSig; int_fast32_t expZ; uint64_t sig256Z[4]; struct uint128 sigZ; int_fast32_t shiftDist, expDiff; struct uint128 x128; uint64_t sig256C[4]; static uint64_t zero256[4] = INIT_UINTM4( 0, 0, 0, 0 ); uint_fast64_t sigZExtra, sig256Z0; union ui128_f128 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ signA = signF128UI64( uiA64 ); expA = expF128UI64( uiA64 ); sigA.v64 = fracF128UI64( uiA64 ); sigA.v0 = uiA0; signB = signF128UI64( uiB64 ); expB = expF128UI64( uiB64 ); sigB.v64 = fracF128UI64( uiB64 ); sigB.v0 = uiB0; signC = signF128UI64( uiC64 ) ^ (op == softfloat_mulAdd_subC); expC = expF128UI64( uiC64 ); sigC.v64 = fracF128UI64( uiC64 ); sigC.v0 = uiC0; signZ = signA ^ signB ^ (op == softfloat_mulAdd_subProd); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x7FFF ) { if ( (sigA.v64 | sigA.v0) || ((expB == 0x7FFF) && (sigB.v64 | sigB.v0)) ) { goto propagateNaN_ABC; } magBits = expB | sigB.v64 | sigB.v0; goto infProdArg; } if ( expB == 0x7FFF ) { if ( sigB.v64 | sigB.v0 ) goto propagateNaN_ABC; magBits = expA | sigA.v64 | sigA.v0; goto infProdArg; } if ( expC == 0x7FFF ) { if ( sigC.v64 | sigC.v0 ) { uiZ.v64 = 0; uiZ.v0 = 0; goto propagateNaN_ZC; } uiZ.v64 = uiC64; uiZ.v0 = uiC0; goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) { if ( ! (sigA.v64 | sigA.v0) ) goto zeroProd; normExpSig = softfloat_normSubnormalF128Sig( sigA.v64, sigA.v0 ); expA = normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) { if ( ! (sigB.v64 | sigB.v0) ) goto zeroProd; normExpSig = softfloat_normSubnormalF128Sig( sigB.v64, sigB.v0 ); expB = normExpSig.exp; sigB = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0x3FFE; sigA.v64 |= UINT64_C( 0x0001000000000000 ); sigB.v64 |= UINT64_C( 0x0001000000000000 ); sigA = softfloat_shortShiftLeft128( sigA.v64, sigA.v0, 8 ); sigB = softfloat_shortShiftLeft128( sigB.v64, sigB.v0, 15 ); softfloat_mul128To256M( sigA.v64, sigA.v0, sigB.v64, sigB.v0, sig256Z ); sigZ.v64 = sig256Z[indexWord( 4, 3 )]; sigZ.v0 = sig256Z[indexWord( 4, 2 )]; shiftDist = 0; if ( ! (sigZ.v64 & UINT64_C( 0x0100000000000000 )) ) { --expZ; shiftDist = -1; } if ( ! expC ) { if ( ! (sigC.v64 | sigC.v0) ) { shiftDist += 8; goto sigZ; } normExpSig = softfloat_normSubnormalF128Sig( sigC.v64, sigC.v0 ); expC = normExpSig.exp; sigC = normExpSig.sig; } sigC.v64 |= UINT64_C( 0x0001000000000000 ); sigC = softfloat_shortShiftLeft128( sigC.v64, sigC.v0, 8 ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expZ - expC; if ( expDiff < 0 ) { expZ = expC; if ( (signZ == signC) || (expDiff < -1) ) { shiftDist -= expDiff; if ( shiftDist ) { sigZ = softfloat_shiftRightJam128( sigZ.v64, sigZ.v0, shiftDist ); } } else { if ( ! shiftDist ) { x128 = softfloat_shortShiftRight128( sig256Z[indexWord( 4, 1 )], sig256Z[indexWord( 4, 0 )], 1 ); sig256Z[indexWord( 4, 1 )] = (sigZ.v0<<63) | x128.v64; sig256Z[indexWord( 4, 0 )] = x128.v0; sigZ = softfloat_shortShiftRight128( sigZ.v64, sigZ.v0, 1 ); sig256Z[indexWord( 4, 3 )] = sigZ.v64; sig256Z[indexWord( 4, 2 )] = sigZ.v0; } } } else { if ( shiftDist ) softfloat_add256M( sig256Z, sig256Z, sig256Z ); if ( ! expDiff ) { sigZ.v64 = sig256Z[indexWord( 4, 3 )]; sigZ.v0 = sig256Z[indexWord( 4, 2 )]; } else { sig256C[indexWord( 4, 3 )] = sigC.v64; sig256C[indexWord( 4, 2 )] = sigC.v0; sig256C[indexWord( 4, 1 )] = 0; sig256C[indexWord( 4, 0 )] = 0; softfloat_shiftRightJam256M( sig256C, expDiff, sig256C ); } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ shiftDist = 8; if ( signZ == signC ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expDiff <= 0 ) { sigZ = softfloat_add128( sigC.v64, sigC.v0, sigZ.v64, sigZ.v0 ); } else { softfloat_add256M( sig256Z, sig256C, sig256Z ); sigZ.v64 = sig256Z[indexWord( 4, 3 )]; sigZ.v0 = sig256Z[indexWord( 4, 2 )]; } if ( sigZ.v64 & UINT64_C( 0x0200000000000000 ) ) { ++expZ; shiftDist = 9; } } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expDiff < 0 ) { signZ = signC; if ( expDiff < -1 ) { sigZ = softfloat_sub128( sigC.v64, sigC.v0, sigZ.v64, sigZ.v0 ); sigZExtra = sig256Z[indexWord( 4, 1 )] | sig256Z[indexWord( 4, 0 )]; if ( sigZExtra ) { sigZ = softfloat_sub128( sigZ.v64, sigZ.v0, 0, 1 ); } if ( ! (sigZ.v64 & UINT64_C( 0x0100000000000000 )) ) { --expZ; shiftDist = 7; } goto shiftRightRoundPack; } else { sig256C[indexWord( 4, 3 )] = sigC.v64; sig256C[indexWord( 4, 2 )] = sigC.v0; sig256C[indexWord( 4, 1 )] = 0; sig256C[indexWord( 4, 0 )] = 0; softfloat_sub256M( sig256C, sig256Z, sig256Z ); } } else if ( ! expDiff ) { sigZ = softfloat_sub128( sigZ.v64, sigZ.v0, sigC.v64, sigC.v0 ); if ( ! (sigZ.v64 | sigZ.v0) && ! sig256Z[indexWord( 4, 1 )] && ! sig256Z[indexWord( 4, 0 )] ) { goto completeCancellation; } sig256Z[indexWord( 4, 3 )] = sigZ.v64; sig256Z[indexWord( 4, 2 )] = sigZ.v0; if ( sigZ.v64 & UINT64_C( 0x8000000000000000 ) ) { signZ = ! signZ; softfloat_sub256M( zero256, sig256Z, sig256Z ); } } else { softfloat_sub256M( sig256Z, sig256C, sig256Z ); if ( 1 < expDiff ) { sigZ.v64 = sig256Z[indexWord( 4, 3 )]; sigZ.v0 = sig256Z[indexWord( 4, 2 )]; if ( ! (sigZ.v64 & UINT64_C( 0x0100000000000000 )) ) { --expZ; shiftDist = 7; } goto sigZ; } } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ sigZ.v64 = sig256Z[indexWord( 4, 3 )]; sigZ.v0 = sig256Z[indexWord( 4, 2 )]; sigZExtra = sig256Z[indexWord( 4, 1 )]; sig256Z0 = sig256Z[indexWord( 4, 0 )]; if ( sigZ.v64 ) { if ( sig256Z0 ) sigZExtra |= 1; } else { expZ -= 64; sigZ.v64 = sigZ.v0; sigZ.v0 = sigZExtra; sigZExtra = sig256Z0; if ( ! sigZ.v64 ) { expZ -= 64; sigZ.v64 = sigZ.v0; sigZ.v0 = sigZExtra; sigZExtra = 0; if ( ! sigZ.v64 ) { expZ -= 64; sigZ.v64 = sigZ.v0; sigZ.v0 = 0; } } } shiftDist = softfloat_countLeadingZeros64( sigZ.v64 ); expZ += 7 - shiftDist; shiftDist = 15 - shiftDist; if ( 0 < shiftDist ) goto shiftRightRoundPack; if ( shiftDist ) { shiftDist = -shiftDist; sigZ = softfloat_shortShiftLeft128( sigZ.v64, sigZ.v0, shiftDist ); x128 = softfloat_shortShiftLeft128( 0, sigZExtra, shiftDist ); sigZ.v0 |= x128.v64; sigZExtra = x128.v0; } goto roundPack; } sigZ: sigZExtra = sig256Z[indexWord( 4, 1 )] | sig256Z[indexWord( 4, 0 )]; shiftRightRoundPack: sigZExtra = (uint64_t) (sigZ.v0<<(64 - shiftDist)) | (sigZExtra != 0); sigZ = softfloat_shortShiftRight128( sigZ.v64, sigZ.v0, shiftDist ); roundPack: return softfloat_roundPackToF128( signZ, expZ - 1, sigZ.v64, sigZ.v0, sigZExtra ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN_ABC: uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); goto propagateNaN_ZC; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infProdArg: if ( magBits ) { uiZ.v64 = packToF128UI64( signZ, 0x7FFF, 0 ); uiZ.v0 = 0; if ( expC != 0x7FFF ) goto uiZ; if ( sigC.v64 | sigC.v0 ) goto propagateNaN_ZC; if ( signZ == signC ) goto uiZ; } softfloat_raiseFlags( softfloat_flag_invalid ); uiZ.v64 = defaultNaNF128UI64; uiZ.v0 = defaultNaNF128UI0; propagateNaN_ZC: uiZ = softfloat_propagateNaNF128UI( uiZ.v64, uiZ.v0, uiC64, uiC0 ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zeroProd: uiZ.v64 = uiC64; uiZ.v0 = uiC0; if ( ! (expC | sigC.v64 | sigC.v0) && (signZ != signC) ) { completeCancellation: uiZ.v64 = packToF128UI64( (softfloat_roundingMode == softfloat_round_min), 0, 0 ); uiZ.v0 = 0; } uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/s_mulAddF16.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float16_t softfloat_mulAddF16( uint_fast16_t uiA, uint_fast16_t uiB, uint_fast16_t uiC, uint_fast8_t op ) { bool signA; int_fast8_t expA; uint_fast16_t sigA; bool signB; int_fast8_t expB; uint_fast16_t sigB; bool signC; int_fast8_t expC; uint_fast16_t sigC; bool signProd; uint_fast16_t magBits, uiZ; struct exp8_sig16 normExpSig; int_fast8_t expProd; uint_fast32_t sigProd; bool signZ; int_fast8_t expZ; uint_fast16_t sigZ; int_fast8_t expDiff; uint_fast32_t sig32Z, sig32C; int_fast8_t shiftDist; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ signA = signF16UI( uiA ); expA = expF16UI( uiA ); sigA = fracF16UI( uiA ); signB = signF16UI( uiB ); expB = expF16UI( uiB ); sigB = fracF16UI( uiB ); signC = signF16UI( uiC ) ^ (op == softfloat_mulAdd_subC); expC = expF16UI( uiC ); sigC = fracF16UI( uiC ); signProd = signA ^ signB ^ (op == softfloat_mulAdd_subProd); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( expA == 0x1F ) { if ( sigA || ((expB == 0x1F) && sigB) ) goto propagateNaN_ABC; magBits = expB | sigB; goto infProdArg; } if ( expB == 0x1F ) { if ( sigB ) goto propagateNaN_ABC; magBits = expA | sigA; goto infProdArg; } if ( expC == 0x1F ) { if ( sigC ) { uiZ = 0; goto propagateNaN_ZC; } uiZ = uiC; goto uiZ; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( ! expA ) { if ( ! sigA ) goto zeroProd; normExpSig = softfloat_normSubnormalF16Sig( sigA ); expA = normExpSig.exp; sigA = normExpSig.sig; } if ( ! expB ) { if ( ! sigB ) goto zeroProd; normExpSig = softfloat_normSubnormalF16Sig( sigB ); expB = normExpSig.exp; sigB = normExpSig.sig; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expProd = expA + expB - 0xE; sigA = (sigA | 0x0400)<<4; sigB = (sigB | 0x0400)<<4; sigProd = (uint_fast32_t) sigA * sigB; if ( sigProd < 0x20000000 ) { --expProd; sigProd <<= 1; } signZ = signProd; if ( ! expC ) { if ( ! sigC ) { expZ = expProd - 1; sigZ = sigProd>>15 | ((sigProd & 0x7FFF) != 0); goto roundPack; } normExpSig = softfloat_normSubnormalF16Sig( sigC ); expC = normExpSig.exp; sigC = normExpSig.sig; } sigC = (sigC | 0x0400)<<3; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expProd - expC; if ( signProd == signC ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expDiff <= 0 ) { expZ = expC; sigZ = sigC + softfloat_shiftRightJam32( sigProd, 16 - expDiff ); } else { expZ = expProd; sig32Z = sigProd + softfloat_shiftRightJam32( (uint_fast32_t) sigC<<16, expDiff ); sigZ = sig32Z>>16 | ((sig32Z & 0xFFFF) != 0 ); } if ( sigZ < 0x4000 ) { --expZ; sigZ <<= 1; } } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ sig32C = (uint_fast32_t) sigC<<16; if ( expDiff < 0 ) { signZ = signC; expZ = expC; sig32Z = sig32C - softfloat_shiftRightJam32( sigProd, -expDiff ); } else if ( ! expDiff ) { expZ = expProd; sig32Z = sigProd - sig32C; if ( ! sig32Z ) goto completeCancellation; if ( sig32Z & 0x80000000 ) { signZ = ! signZ; sig32Z = -sig32Z; } } else { expZ = expProd; sig32Z = sigProd - softfloat_shiftRightJam32( sig32C, expDiff ); } shiftDist = softfloat_countLeadingZeros32( sig32Z ) - 1; expZ -= shiftDist; shiftDist -= 16; if ( shiftDist < 0 ) { sigZ = sig32Z>>(-shiftDist) | ((uint32_t) (sig32Z<<(shiftDist & 31)) != 0); } else { sigZ = (uint_fast16_t) sig32Z< #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float32_t softfloat_mulAddF32( uint_fast32_t uiA, uint_fast32_t uiB, uint_fast32_t uiC, uint_fast8_t op ) { 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 sig64Z, sig64C; int_fast8_t shiftDist; 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_shortShiftRightJam64( 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_shiftRightJam64( sigProd, 32 - expDiff ); } else { expZ = expProd; sig64Z = sigProd + softfloat_shiftRightJam64( (uint_fast64_t) sigC<<32, expDiff ); sigZ = softfloat_shortShiftRightJam64( sig64Z, 32 ); } if ( sigZ < 0x40000000 ) { --expZ; sigZ <<= 1; } } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ sig64C = (uint_fast64_t) sigC<<32; if ( expDiff < 0 ) { signZ = signC; expZ = expC; sig64Z = sig64C - softfloat_shiftRightJam64( sigProd, -expDiff ); } else if ( ! expDiff ) { expZ = expProd; sig64Z = sigProd - sig64C; if ( ! sig64Z ) goto completeCancellation; if ( sig64Z & UINT64_C( 0x8000000000000000 ) ) { signZ = ! signZ; sig64Z = -sig64Z; } } else { expZ = expProd; sig64Z = sigProd - softfloat_shiftRightJam64( sig64C, expDiff ); } shiftDist = softfloat_countLeadingZeros64( sig64Z ) - 1; expZ -= shiftDist; shiftDist -= 32; if ( shiftDist < 0 ) { sigZ = softfloat_shortShiftRightJam64( sig64Z, -shiftDist ); } else { sigZ = (uint_fast32_t) sig64Z< #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" #ifdef SOFTFLOAT_FAST_INT64 float64_t softfloat_mulAddF64( uint_fast64_t uiA, uint_fast64_t uiB, uint_fast64_t uiC, uint_fast8_t op ) { 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 signZ; uint_fast64_t magBits, uiZ; struct exp16_sig64 normExpSig; int_fast16_t expZ; struct uint128 sig128Z; uint_fast64_t sigZ; int_fast16_t expDiff; struct uint128 sig128C; int_fast8_t shiftDist; 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 ); signZ = 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; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0x3FE; sigA = (sigA | UINT64_C( 0x0010000000000000 ))<<10; sigB = (sigB | UINT64_C( 0x0010000000000000 ))<<10; sig128Z = softfloat_mul64To128( sigA, sigB ); if ( sig128Z.v64 < UINT64_C( 0x2000000000000000 ) ) { --expZ; sig128Z = softfloat_add128( sig128Z.v64, sig128Z.v0, sig128Z.v64, sig128Z.v0 ); } if ( ! expC ) { if ( ! sigC ) { --expZ; sigZ = sig128Z.v64<<1 | (sig128Z.v0 != 0); goto roundPack; } normExpSig = softfloat_normSubnormalF64Sig( sigC ); expC = normExpSig.exp; sigC = normExpSig.sig; } sigC = (sigC | UINT64_C( 0x0010000000000000 ))<<9; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expZ - expC; if ( expDiff < 0 ) { expZ = expC; if ( (signZ == signC) || (expDiff < -1) ) { sig128Z.v64 = softfloat_shiftRightJam64( sig128Z.v64, -expDiff ); } else { sig128Z = softfloat_shortShiftRightJam128( sig128Z.v64, sig128Z.v0, 1 ); } } else if ( expDiff ) { sig128C = softfloat_shiftRightJam128( sigC, 0, expDiff ); } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( signZ == signC ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expDiff <= 0 ) { sigZ = (sigC + sig128Z.v64) | (sig128Z.v0 != 0); } else { sig128Z = softfloat_add128( sig128Z.v64, sig128Z.v0, sig128C.v64, sig128C.v0 ); sigZ = sig128Z.v64 | (sig128Z.v0 != 0); } if ( sigZ < UINT64_C( 0x4000000000000000 ) ) { --expZ; sigZ <<= 1; } } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expDiff < 0 ) { signZ = signC; sig128Z = softfloat_sub128( sigC, 0, sig128Z.v64, sig128Z.v0 ); } else if ( ! expDiff ) { sig128Z.v64 = sig128Z.v64 - sigC; if ( ! (sig128Z.v64 | sig128Z.v0) ) goto completeCancellation; if ( sig128Z.v64 & UINT64_C( 0x8000000000000000 ) ) { signZ = ! signZ; sig128Z = softfloat_sub128( 0, 0, sig128Z.v64, sig128Z.v0 ); } } else { sig128Z = softfloat_sub128( sig128Z.v64, sig128Z.v0, sig128C.v64, sig128C.v0 ); } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( ! sig128Z.v64 ) { expZ -= 64; sig128Z.v64 = sig128Z.v0; sig128Z.v0 = 0; } shiftDist = softfloat_countLeadingZeros64( sig128Z.v64 ) - 1; expZ -= shiftDist; if ( shiftDist < 0 ) { sigZ = softfloat_shortShiftRightJam64( sig128Z.v64, -shiftDist ); } else { sig128Z = softfloat_shortShiftLeft128( sig128Z.v64, sig128Z.v0, shiftDist ); sigZ = sig128Z.v64; } sigZ |= (sig128Z.v0 != 0); } roundPack: return softfloat_roundPackToF64( signZ, expZ, sigZ ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN_ABC: uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); goto propagateNaN_ZC; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infProdArg: if ( magBits ) { uiZ = packToF64UI( signZ, 0x7FF, 0 ); if ( expC != 0x7FF ) goto uiZ; if ( sigC ) goto propagateNaN_ZC; if ( signZ == signC ) goto uiZ; } softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF64UI; propagateNaN_ZC: uiZ = softfloat_propagateNaNF64UI( uiZ, uiC ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zeroProd: uiZ = uiC; if ( ! (expC | sigC) && (signZ != signC) ) { completeCancellation: uiZ = packToF64UI( (softfloat_roundingMode == softfloat_round_min), 0, 0 ); } uiZ: uZ.ui = uiZ; return uZ.f; } #else float64_t softfloat_mulAddF64( uint_fast64_t uiA, uint_fast64_t uiB, uint_fast64_t uiC, uint_fast8_t op ) { bool signA; int_fast16_t expA; uint64_t sigA; bool signB; int_fast16_t expB; uint64_t sigB; bool signC; int_fast16_t expC; uint64_t sigC; bool signZ; uint64_t magBits, uiZ; struct exp16_sig64 normExpSig; int_fast16_t expZ; uint32_t sig128Z[4]; uint64_t sigZ; int_fast16_t shiftDist, expDiff; uint32_t sig128C[4]; 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 ); signZ = 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; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expZ = expA + expB - 0x3FE; sigA = (sigA | UINT64_C( 0x0010000000000000 ))<<10; sigB = (sigB | UINT64_C( 0x0010000000000000 ))<<11; softfloat_mul64To128M( sigA, sigB, sig128Z ); sigZ = (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; shiftDist = 0; if ( ! (sigZ & UINT64_C( 0x4000000000000000 )) ) { --expZ; shiftDist = -1; } if ( ! expC ) { if ( ! sigC ) { if ( shiftDist ) sigZ <<= 1; goto sigZ; } normExpSig = softfloat_normSubnormalF64Sig( sigC ); expC = normExpSig.exp; sigC = normExpSig.sig; } sigC = (sigC | UINT64_C( 0x0010000000000000 ))<<10; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expZ - expC; if ( expDiff < 0 ) { expZ = expC; if ( (signZ == signC) || (expDiff < -1) ) { shiftDist -= expDiff; if ( shiftDist) { sigZ = softfloat_shiftRightJam64( sigZ, shiftDist ); } } else { if ( ! shiftDist ) { softfloat_shortShiftRight128M( sig128Z, 1, sig128Z ); } } } else { if ( shiftDist ) softfloat_add128M( sig128Z, sig128Z, sig128Z ); if ( ! expDiff ) { sigZ = (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; } else { sig128C[indexWord( 4, 3 )] = sigC>>32; sig128C[indexWord( 4, 2 )] = sigC; sig128C[indexWord( 4, 1 )] = 0; sig128C[indexWord( 4, 0 )] = 0; softfloat_shiftRightJam128M( sig128C, expDiff, sig128C ); } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( signZ == signC ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expDiff <= 0 ) { sigZ += sigC; } else { softfloat_add128M( sig128Z, sig128C, sig128Z ); sigZ = (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; } if ( sigZ & UINT64_C( 0x8000000000000000 ) ) { ++expZ; sigZ = softfloat_shortShiftRightJam64( sigZ, 1 ); } } else { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expDiff < 0 ) { signZ = signC; if ( expDiff < -1 ) { sigZ = sigC - sigZ; if ( sig128Z[indexWord( 4, 1 )] || sig128Z[indexWord( 4, 0 )] ) { sigZ = (sigZ - 1) | 1; } if ( ! (sigZ & UINT64_C( 0x4000000000000000 )) ) { --expZ; sigZ <<= 1; } goto roundPack; } else { sig128C[indexWord( 4, 3 )] = sigC>>32; sig128C[indexWord( 4, 2 )] = sigC; sig128C[indexWord( 4, 1 )] = 0; sig128C[indexWord( 4, 0 )] = 0; softfloat_sub128M( sig128C, sig128Z, sig128Z ); } } else if ( ! expDiff ) { sigZ -= sigC; if ( ! sigZ && ! sig128Z[indexWord( 4, 1 )] && ! sig128Z[indexWord( 4, 0 )] ) { goto completeCancellation; } sig128Z[indexWord( 4, 3 )] = sigZ>>32; sig128Z[indexWord( 4, 2 )] = sigZ; if ( sigZ & UINT64_C( 0x8000000000000000 ) ) { signZ = ! signZ; softfloat_negX128M( sig128Z ); } } else { softfloat_sub128M( sig128Z, sig128C, sig128Z ); if ( 1 < expDiff ) { sigZ = (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; if ( ! (sigZ & UINT64_C( 0x4000000000000000 )) ) { --expZ; sigZ <<= 1; } goto sigZ; } } /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ shiftDist = 0; sigZ = (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; if ( ! sigZ ) { shiftDist = 64; sigZ = (uint64_t) sig128Z[indexWord( 4, 1 )]<<32 | sig128Z[indexWord( 4, 0 )]; } shiftDist += softfloat_countLeadingZeros64( sigZ ) - 1; if ( shiftDist ) { expZ -= shiftDist; softfloat_shiftLeft128M( sig128Z, shiftDist, sig128Z ); sigZ = (uint64_t) sig128Z[indexWord( 4, 3 )]<<32 | sig128Z[indexWord( 4, 2 )]; } } sigZ: if ( sig128Z[indexWord( 4, 1 )] || sig128Z[indexWord( 4, 0 )] ) sigZ |= 1; roundPack: return softfloat_roundPackToF64( signZ, expZ - 1, sigZ ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN_ABC: uiZ = softfloat_propagateNaNF64UI( uiA, uiB ); goto propagateNaN_ZC; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ infProdArg: if ( magBits ) { uiZ = packToF64UI( signZ, 0x7FF, 0 ); if ( expC != 0x7FF ) goto uiZ; if ( sigC ) goto propagateNaN_ZC; if ( signZ == signC ) goto uiZ; } softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF64UI; propagateNaN_ZC: uiZ = softfloat_propagateNaNF64UI( uiZ, uiC ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ zeroProd: uiZ = uiC; if ( ! (expC | sigC) && (signZ != signC) ) { completeCancellation: uiZ = packToF64UI( (softfloat_roundingMode == softfloat_round_min), 0, 0 ); } uiZ: uZ.ui = uiZ; return uZ.f; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_negXM.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_negXM void softfloat_negXM( uint_fast8_t size_words, uint32_t *zPtr ) { unsigned int index, lastIndex; uint_fast8_t carry; uint32_t word; index = indexWordLo( size_words ); lastIndex = indexWordHi( size_words ); carry = 1; for (;;) { word = ~zPtr[index] + carry; zPtr[index] = word; if ( index == lastIndex ) break; index += wordIncr; if ( word ) carry = 0; } } #endif ================================================ FILE: vp/src/vendor/softfloat/s_normRoundPackToF128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" float128_t softfloat_normRoundPackToF128( bool sign, int_fast32_t exp, uint_fast64_t sig64, uint_fast64_t sig0 ) { int_fast8_t shiftDist; struct uint128 sig128; union ui128_f128 uZ; uint_fast64_t sigExtra; struct uint128_extra sig128Extra; if ( ! sig64 ) { exp -= 64; sig64 = sig0; sig0 = 0; } shiftDist = softfloat_countLeadingZeros64( sig64 ) - 15; exp -= shiftDist; if ( 0 <= shiftDist ) { if ( shiftDist ) { sig128 = softfloat_shortShiftLeft128( sig64, sig0, shiftDist ); sig64 = sig128.v64; sig0 = sig128.v0; } if ( (uint32_t) exp < 0x7FFD ) { uZ.ui.v64 = packToF128UI64( sign, sig64 | sig0 ? exp : 0, sig64 ); uZ.ui.v0 = sig0; return uZ.f; } sigExtra = 0; } else { sig128Extra = softfloat_shortShiftRightJam128Extra( sig64, sig0, 0, -shiftDist ); sig64 = sig128Extra.v.v64; sig0 = sig128Extra.v.v0; sigExtra = sig128Extra.extra; } return softfloat_roundPackToF128( sign, exp, sig64, sig0, sigExtra ); } ================================================ FILE: vp/src/vendor/softfloat/s_normRoundPackToF16.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" float16_t softfloat_normRoundPackToF16( bool sign, int_fast16_t exp, uint_fast16_t sig ) { int_fast8_t shiftDist; union ui16_f16 uZ; shiftDist = softfloat_countLeadingZeros16( sig ) - 1; exp -= shiftDist; if ( (4 <= shiftDist) && ((unsigned int) exp < 0x1D) ) { uZ.ui = packToF16UI( sign, sig ? exp : 0, sig<<(shiftDist - 4) ); return uZ.f; } else { return softfloat_roundPackToF16( sign, exp, sig< #include #include "platform.h" #include "internals.h" float32_t softfloat_normRoundPackToF32( bool sign, int_fast16_t exp, uint_fast32_t sig ) { int_fast8_t shiftDist; union ui32_f32 uZ; shiftDist = softfloat_countLeadingZeros32( sig ) - 1; exp -= shiftDist; if ( (7 <= shiftDist) && ((unsigned int) exp < 0xFD) ) { uZ.ui = packToF32UI( sign, sig ? exp : 0, sig<<(shiftDist - 7) ); return uZ.f; } else { return softfloat_roundPackToF32( sign, exp, sig< #include #include "platform.h" #include "internals.h" float64_t softfloat_normRoundPackToF64( bool sign, int_fast16_t exp, uint_fast64_t sig ) { int_fast8_t shiftDist; union ui64_f64 uZ; shiftDist = softfloat_countLeadingZeros64( sig ) - 1; exp -= shiftDist; if ( (10 <= shiftDist) && ((unsigned int) exp < 0x7FD) ) { uZ.ui = packToF64UI( sign, sig ? exp : 0, sig<<(shiftDist - 10) ); return uZ.f; } else { return softfloat_roundPackToF64( sign, exp, sig< #include "platform.h" #include "internals.h" struct exp32_sig128 softfloat_normSubnormalF128Sig( uint_fast64_t sig64, uint_fast64_t sig0 ) { int_fast8_t shiftDist; struct exp32_sig128 z; if ( ! sig64 ) { shiftDist = softfloat_countLeadingZeros64( sig0 ) - 15; z.exp = -63 - shiftDist; if ( shiftDist < 0 ) { z.sig.v64 = sig0>>-shiftDist; z.sig.v0 = sig0<<(shiftDist & 63); } else { z.sig.v64 = sig0< #include "platform.h" #include "internals.h" struct exp8_sig16 softfloat_normSubnormalF16Sig( uint_fast16_t sig ) { int_fast8_t shiftDist; struct exp8_sig16 z; shiftDist = softfloat_countLeadingZeros16( sig ) - 5; z.exp = 1 - shiftDist; z.sig = sig< #include "platform.h" #include "internals.h" struct exp16_sig32 softfloat_normSubnormalF32Sig( uint_fast32_t sig ) { int_fast8_t shiftDist; struct exp16_sig32 z; shiftDist = softfloat_countLeadingZeros32( sig ) - 8; z.exp = 1 - shiftDist; z.sig = sig< #include "platform.h" #include "internals.h" struct exp16_sig64 softfloat_normSubnormalF64Sig( uint_fast64_t sig ) { int_fast8_t shiftDist; struct exp16_sig64 z; shiftDist = softfloat_countLeadingZeros64( sig ) - 11; z.exp = 1 - shiftDist; z.sig = sig< #include "platform.h" #include "primitiveTypes.h" #include "specialize.h" #include "softfloat.h" /*---------------------------------------------------------------------------- | Interpreting the unsigned integer formed from concatenating `uiA64' and | `uiA0' as a 128-bit floating-point value, and likewise interpreting the | unsigned integer formed from concatenating `uiB64' and `uiB0' as another | 128-bit floating-point value, and assuming at least on of these floating- | point values is a NaN, returns the bit pattern of the combined NaN result. | If either original floating-point value is a signaling NaN, the invalid | exception is raised. *----------------------------------------------------------------------------*/ struct uint128 softfloat_propagateNaNF128UI( uint_fast64_t uiA64, uint_fast64_t uiA0, uint_fast64_t uiB64, uint_fast64_t uiB0 ) { struct uint128 uiZ; if ( softfloat_isSigNaNF128UI( uiA64, uiA0 ) || softfloat_isSigNaNF128UI( uiB64, uiB0 ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); } uiZ.v64 = defaultNaNF128UI64; uiZ.v0 = defaultNaNF128UI0; return uiZ; } ================================================ FILE: vp/src/vendor/softfloat/s_propagateNaNF16UI.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "specialize.h" #include "softfloat.h" /*---------------------------------------------------------------------------- | Interpreting `uiA' and `uiB' as the bit patterns of two 16-bit floating- | point values, at least one of which is a NaN, returns the bit pattern of | the combined NaN result. If either `uiA' or `uiB' has the pattern of a | signaling NaN, the invalid exception is raised. *----------------------------------------------------------------------------*/ uint_fast16_t softfloat_propagateNaNF16UI( uint_fast16_t uiA, uint_fast16_t uiB ) { if ( softfloat_isSigNaNF16UI( uiA ) || softfloat_isSigNaNF16UI( uiB ) ) { softfloat_raiseFlags( softfloat_flag_invalid ); } return defaultNaNF16UI; } ================================================ FILE: vp/src/vendor/softfloat/s_propagateNaNF32UI.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "specialize.h" #include "softfloat.h" /*---------------------------------------------------------------------------- | Interpreting `uiA' and `uiB' as the bit patterns of two 32-bit floating- | point values, at least one of which is a NaN, returns the bit pattern of | the combined NaN result. If either `uiA' or `uiB' has the pattern of 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; } ================================================ FILE: vp/src/vendor/softfloat/s_propagateNaNF64UI.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "specialize.h" #include "softfloat.h" /*---------------------------------------------------------------------------- | Interpreting `uiA' and `uiB' as the bit patterns of two 64-bit floating- | point values, at least one of which is a NaN, returns the bit pattern of | the combined NaN result. If either `uiA' or `uiB' has the pattern of 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; } ================================================ FILE: vp/src/vendor/softfloat/s_remStepMBy32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_remStepMBy32 void softfloat_remStepMBy32( uint_fast8_t size_words, const uint32_t *remPtr, uint_fast8_t dist, const uint32_t *bPtr, uint32_t q, uint32_t *zPtr ) { unsigned int index, lastIndex; uint64_t dwordProd; uint32_t wordRem, wordShiftedRem, wordProd; uint_fast8_t uNegDist, borrow; index = indexWordLo( size_words ); lastIndex = indexWordHi( size_words ); dwordProd = (uint64_t) bPtr[index] * q; wordRem = remPtr[index]; wordShiftedRem = wordRem<>(uNegDist & 31); index += wordIncr; dwordProd = (uint64_t) bPtr[index] * q + (dwordProd>>32); wordRem = remPtr[index]; wordShiftedRem |= wordRem< #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast64_t softfloat_roundMToI64( bool sign, uint32_t *extSigPtr, uint_fast8_t roundingMode, bool exact ) { bool roundNearEven; uint32_t sigExtra; bool doIncrement; uint64_t sig; union { uint64_t ui; int64_t i; } uZ; int64_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundNearEven = (roundingMode == softfloat_round_near_even); sigExtra = extSigPtr[indexWordLo( 3 )]; doIncrement = (0x80000000 <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } sig = (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 | extSigPtr[indexWord( 3, 1 )]; if ( doIncrement ) { ++sig; if ( ! sig ) goto invalid; if ( ! (sigExtra & 0x7FFFFFFF) && roundNearEven ) sig &= ~1; } uZ.ui = sign ? -sig : sig; z = uZ.i; if ( z && ((z < 0) ^ sign) ) goto invalid; if ( exact && sigExtra ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return sign ? i64_fromNegOverflow : i64_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/s_roundMToUI64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast64_t softfloat_roundMToUI64( bool sign, uint32_t *extSigPtr, uint_fast8_t roundingMode, bool exact ) { bool roundNearEven; uint32_t sigExtra; bool doIncrement; uint64_t sig; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundNearEven = (roundingMode == softfloat_round_near_even); sigExtra = extSigPtr[indexWordLo( 3 )]; doIncrement = (0x80000000 <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } sig = (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 | extSigPtr[indexWord( 3, 1 )]; if ( doIncrement ) { ++sig; if ( ! sig ) goto invalid; if ( ! (sigExtra & 0x7FFFFFFF) && roundNearEven ) sig &= ~1; } if ( sign && sig ) goto invalid; if ( exact && sigExtra ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return sig; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/s_roundPackMToI64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3a+, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast64_t softfloat_roundPackMToI64( bool sign, uint32_t *extSigPtr, uint_fast8_t roundingMode, bool exact ) { bool roundNearEven; uint32_t sigExtra; bool doIncrement; uint64_t sig; union { uint64_t ui; int64_t i; } uZ; int64_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundNearEven = (roundingMode == softfloat_round_near_even); sigExtra = extSigPtr[indexWordLo( 3 )]; doIncrement = (0x80000000 <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } sig = (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 | extSigPtr[indexWord( 3, 1 )]; if ( doIncrement ) { ++sig; if ( ! sig ) goto invalid; if ( ! (sigExtra & 0x7FFFFFFF) && roundNearEven ) sig &= ~1; } uZ.ui = sign ? -sig : sig; z = uZ.i; if ( z && ((z < 0) ^ sign) ) goto invalid; if ( exact && sigExtra ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return sign ? i64_fromNegOverflow : i64_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/s_roundPackMToUI64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3a+, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast64_t softfloat_roundPackMToUI64( bool sign, uint32_t *extSigPtr, uint_fast8_t roundingMode, bool exact ) { bool roundNearEven; uint32_t sigExtra; bool doIncrement; uint64_t sig; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundNearEven = (roundingMode == softfloat_round_near_even); sigExtra = extSigPtr[indexWordLo( 3 )]; doIncrement = (0x80000000 <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } sig = (uint64_t) extSigPtr[indexWord( 3, 2 )]<<32 | extSigPtr[indexWord( 3, 1 )]; if ( doIncrement ) { ++sig; if ( ! sig ) goto invalid; if ( ! (sigExtra & 0x7FFFFFFF) && roundNearEven ) sig &= ~1; } if ( sign && sig ) goto invalid; if ( exact && sigExtra ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return sig; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/s_roundPackToF128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" float128_t softfloat_roundPackToF128( bool sign, int_fast32_t exp, uint_fast64_t sig64, uint_fast64_t sig0, uint_fast64_t sigExtra ) { uint_fast8_t roundingMode; bool roundNearEven, doIncrement, isTiny; struct uint128_extra sig128Extra; uint_fast64_t uiZ64, uiZ0; struct uint128 sig128; union ui128_f128 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundingMode = softfloat_roundingMode; roundNearEven = (roundingMode == softfloat_round_near_even); doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x7FFD <= (uint32_t) exp ) { if ( exp < 0 ) { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ isTiny = (softfloat_detectTininess == softfloat_tininess_beforeRounding) || (exp < -1) || ! doIncrement || softfloat_lt128( sig64, sig0, UINT64_C( 0x0001FFFFFFFFFFFF ), UINT64_C( 0xFFFFFFFFFFFFFFFF ) ); sig128Extra = softfloat_shiftRightJam128Extra( sig64, sig0, sigExtra, -exp ); sig64 = sig128Extra.v.v64; sig0 = sig128Extra.v.v0; sigExtra = sig128Extra.extra; exp = 0; if ( isTiny && sigExtra ) { softfloat_raiseFlags( softfloat_flag_underflow ); } doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } } else if ( (0x7FFD < exp) || ((exp == 0x7FFD) && softfloat_eq128( sig64, sig0, UINT64_C( 0x0001FFFFFFFFFFFF ), UINT64_C( 0xFFFFFFFFFFFFFFFF ) ) && doIncrement) ) { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ softfloat_raiseFlags( softfloat_flag_overflow | softfloat_flag_inexact ); if ( roundNearEven || (roundingMode == softfloat_round_near_maxMag) || (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ) { uiZ64 = packToF128UI64( sign, 0x7FFF, 0 ); uiZ0 = 0; } else { uiZ64 = packToF128UI64( sign, 0x7FFE, UINT64_C( 0x0000FFFFFFFFFFFF ) ); uiZ0 = UINT64_C( 0xFFFFFFFFFFFFFFFF ); } goto uiZ; } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( sigExtra ) { softfloat_exceptionFlags |= softfloat_flag_inexact; #ifdef SOFTFLOAT_ROUND_ODD if ( roundingMode == softfloat_round_odd ) { sig0 |= 1; goto packReturn; } #endif } if ( doIncrement ) { sig128 = softfloat_add128( sig64, sig0, 0, 1 ); sig64 = sig128.v64; sig0 = sig128.v0 & ~(uint64_t) (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) & roundNearEven); } else { if ( ! (sig64 | sig0) ) exp = 0; } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ packReturn: uiZ64 = packToF128UI64( sign, exp, sig64 ); uiZ0 = sig0; uiZ: uZ.ui.v64 = uiZ64; uZ.ui.v0 = uiZ0; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/s_roundPackToF16.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" float16_t softfloat_roundPackToF16( bool sign, int_fast16_t exp, uint_fast16_t sig ) { uint_fast8_t roundingMode; bool roundNearEven; uint_fast8_t roundIncrement, roundBits; bool isTiny; uint_fast16_t uiZ; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundingMode = softfloat_roundingMode; roundNearEven = (roundingMode == softfloat_round_near_even); roundIncrement = 0x8; if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { roundIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ? 0xF : 0; } roundBits = sig & 0xF; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0x1D <= (unsigned int) exp ) { if ( exp < 0 ) { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ isTiny = (softfloat_detectTininess == softfloat_tininess_beforeRounding) || (exp < -1) || (sig + roundIncrement < 0x8000); sig = softfloat_shiftRightJam32( sig, -exp ); exp = 0; roundBits = sig & 0xF; if ( isTiny && roundBits ) { softfloat_raiseFlags( softfloat_flag_underflow ); } } else if ( (0x1D < exp) || (0x8000 <= sig + roundIncrement) ) { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ softfloat_raiseFlags( softfloat_flag_overflow | softfloat_flag_inexact ); uiZ = packToF16UI( sign, 0x1F, 0 ) - ! roundIncrement; goto uiZ; } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig = (sig + roundIncrement)>>4; if ( roundBits ) { softfloat_exceptionFlags |= softfloat_flag_inexact; #ifdef SOFTFLOAT_ROUND_ODD if ( roundingMode == softfloat_round_odd ) { sig |= 1; goto packReturn; } #endif } sig &= ~(uint_fast16_t) (! (roundBits ^ 8) & roundNearEven); if ( ! sig ) exp = 0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ packReturn: uiZ = packToF16UI( sign, exp, sig ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/s_roundPackToF32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" float32_t softfloat_roundPackToF32( bool sign, int_fast16_t exp, uint_fast32_t sig ) { uint_fast8_t roundingMode; bool roundNearEven; uint_fast8_t roundIncrement, roundBits; bool isTiny; uint_fast32_t uiZ; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundingMode = softfloat_roundingMode; roundNearEven = (roundingMode == softfloat_round_near_even); roundIncrement = 0x40; if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { roundIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ? 0x7F : 0; } roundBits = sig & 0x7F; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ if ( 0xFD <= (unsigned int) exp ) { if ( exp < 0 ) { /*---------------------------------------------------------------- *----------------------------------------------------------------*/ isTiny = (softfloat_detectTininess == softfloat_tininess_beforeRounding) || (exp < -1) || (sig + roundIncrement < 0x80000000); sig = softfloat_shiftRightJam32( 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; } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig = (sig + roundIncrement)>>7; if ( roundBits ) { softfloat_exceptionFlags |= softfloat_flag_inexact; #ifdef SOFTFLOAT_ROUND_ODD if ( roundingMode == softfloat_round_odd ) { sig |= 1; goto packReturn; } #endif } sig &= ~(uint_fast32_t) (! (roundBits ^ 0x40) & roundNearEven); if ( ! sig ) exp = 0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ packReturn: uiZ = packToF32UI( sign, exp, sig ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/s_roundPackToF64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "softfloat.h" float64_t softfloat_roundPackToF64( bool sign, int_fast16_t exp, uint_fast64_t sig ) { uint_fast8_t roundingMode; bool roundNearEven; uint_fast16_t roundIncrement, roundBits; bool isTiny; uint_fast64_t uiZ; union ui64_f64 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundingMode = softfloat_roundingMode; roundNearEven = (roundingMode == softfloat_round_near_even); roundIncrement = 0x200; if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { roundIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ? 0x3FF : 0; } 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_shiftRightJam64( 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; } } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ sig = (sig + roundIncrement)>>10; if ( roundBits ) { softfloat_exceptionFlags |= softfloat_flag_inexact; #ifdef SOFTFLOAT_ROUND_ODD if ( roundingMode == softfloat_round_odd ) { sig |= 1; goto packReturn; } #endif } sig &= ~(uint_fast64_t) (! (roundBits ^ 0x200) & roundNearEven); if ( ! sig ) exp = 0; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ packReturn: uiZ = packToF64UI( sign, exp, sig ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/s_roundPackToI32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3a+, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast32_t softfloat_roundPackToI32( bool sign, uint_fast64_t sig, uint_fast8_t roundingMode, bool exact ) { bool roundNearEven; uint_fast8_t roundIncrement, roundBits; uint_fast32_t sig32; union { uint32_t ui; int32_t i; } uZ; int_fast32_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundNearEven = (roundingMode == softfloat_round_near_even); roundIncrement = 0x40; if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { roundIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ? 0x7F : 0; } roundBits = sig & 0x7F; sig += roundIncrement; if ( sig & UINT64_C( 0xFFFFFF8000000000 ) ) goto invalid; sig32 = sig>>7; sig32 &= ~(uint_fast32_t) (! (roundBits ^ 0x40) & roundNearEven); 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 ? i32_fromNegOverflow : i32_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/s_roundPackToI64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3a+, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast64_t softfloat_roundPackToI64( bool sign, uint_fast64_t sig, uint_fast64_t sigExtra, uint_fast8_t roundingMode, bool exact ) { bool roundNearEven, doIncrement; union { uint64_t ui; int64_t i; } uZ; int_fast64_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundNearEven = (roundingMode == softfloat_round_near_even); doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } if ( doIncrement ) { ++sig; if ( ! sig ) goto invalid; sig &= ~(uint_fast64_t) (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) & roundNearEven); } uZ.ui = sign ? -sig : sig; z = uZ.i; if ( z && ((z < 0) ^ sign) ) goto invalid; if ( exact && sigExtra ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return sign ? i64_fromNegOverflow : i64_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/s_roundPackToUI32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3a+, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast32_t softfloat_roundPackToUI32( bool sign, uint_fast64_t sig, uint_fast8_t roundingMode, bool exact ) { bool roundNearEven; uint_fast8_t roundIncrement, roundBits; uint_fast32_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundNearEven = (roundingMode == softfloat_round_near_even); roundIncrement = 0x40; if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { roundIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ? 0x7F : 0; } roundBits = sig & 0x7F; sig += roundIncrement; if ( sig & UINT64_C( 0xFFFFFF8000000000 ) ) goto invalid; z = sig>>7; z &= ~(uint_fast32_t) (! (roundBits ^ 0x40) & roundNearEven); if ( sign && z ) goto invalid; if ( exact && roundBits ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/s_roundPackToUI64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3a+, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast64_t softfloat_roundPackToUI64( bool sign, uint_fast64_t sig, uint_fast64_t sigExtra, uint_fast8_t roundingMode, bool exact ) { bool roundNearEven, doIncrement; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundNearEven = (roundingMode == softfloat_round_near_even); doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } if ( doIncrement ) { ++sig; if ( ! sig ) goto invalid; sig &= ~(uint_fast64_t) (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) & roundNearEven); } if ( sign && sig ) goto invalid; if ( exact && sigExtra ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return sig; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/s_roundToI32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast32_t softfloat_roundToI32( bool sign, uint_fast64_t sig, uint_fast8_t roundingMode, bool exact ) { bool roundNearEven; uint_fast16_t roundIncrement, roundBits; uint_fast32_t sig32; union { uint32_t ui; int32_t i; } uZ; int_fast32_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundNearEven = (roundingMode == softfloat_round_near_even); roundIncrement = 0x800; if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { roundIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ? 0xFFF : 0; } roundBits = sig & 0xFFF; sig += roundIncrement; if ( sig & UINT64_C( 0xFFFFF00000000000 ) ) goto invalid; sig32 = sig>>12; sig32 &= ~(uint_fast32_t) (! (roundBits ^ 0x800) & roundNearEven); 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 ? i32_fromNegOverflow : i32_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/s_roundToI64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" int_fast64_t softfloat_roundToI64( bool sign, uint_fast64_t sig, uint_fast64_t sigExtra, uint_fast8_t roundingMode, bool exact ) { bool roundNearEven, doIncrement; union { uint64_t ui; int64_t i; } uZ; int_fast64_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundNearEven = (roundingMode == softfloat_round_near_even); doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } if ( doIncrement ) { ++sig; if ( ! sig ) goto invalid; sig &= ~(uint_fast64_t) (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) & roundNearEven); } uZ.ui = sign ? -sig : sig; z = uZ.i; if ( z && ((z < 0) ^ sign) ) goto invalid; if ( exact && sigExtra ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return sign ? i64_fromNegOverflow : i64_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/s_roundToUI32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast32_t softfloat_roundToUI32( bool sign, uint_fast64_t sig, uint_fast8_t roundingMode, bool exact ) { bool roundNearEven; uint_fast16_t roundIncrement, roundBits; uint_fast32_t z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundNearEven = (roundingMode == softfloat_round_near_even); roundIncrement = 0x800; if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { roundIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) ? 0xFFF : 0; } roundBits = sig & 0xFFF; sig += roundIncrement; if ( sig & UINT64_C( 0xFFFFF00000000000 ) ) goto invalid; z = sig>>12; z &= ~(uint_fast32_t) (! (roundBits ^ 0x800) & roundNearEven); if ( sign && z ) goto invalid; if ( exact && roundBits ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return z; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return sign ? ui32_fromNegOverflow : ui32_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/s_roundToUI64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" uint_fast64_t softfloat_roundToUI64( bool sign, uint_fast64_t sig, uint_fast64_t sigExtra, uint_fast8_t roundingMode, bool exact ) { bool roundNearEven, doIncrement; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ roundNearEven = (roundingMode == softfloat_round_near_even); doIncrement = (UINT64_C( 0x8000000000000000 ) <= sigExtra); if ( ! roundNearEven && (roundingMode != softfloat_round_near_maxMag) ) { doIncrement = (roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra; } if ( doIncrement ) { ++sig; if ( ! sig ) goto invalid; sig &= ~(uint_fast64_t) (! (sigExtra & UINT64_C( 0x7FFFFFFFFFFFFFFF )) & roundNearEven); } if ( sign && sig ) goto invalid; if ( exact && sigExtra ) { softfloat_exceptionFlags |= softfloat_flag_inexact; } return sig; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ invalid: softfloat_raiseFlags( softfloat_flag_invalid ); return sign ? ui64_fromNegOverflow : ui64_fromPosOverflow; } ================================================ FILE: vp/src/vendor/softfloat/s_shiftRightJam128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_shiftRightJam128 struct uint128 softfloat_shiftRightJam128( uint64_t a64, uint64_t a0, uint_fast32_t dist ) { uint_fast8_t u8NegDist; struct uint128 z; if ( dist < 64 ) { u8NegDist = -dist; z.v64 = a64>>dist; z.v0 = a64<<(u8NegDist & 63) | a0>>dist | ((uint64_t) (a0<<(u8NegDist & 63)) != 0); } else { z.v64 = 0; z.v0 = (dist < 127) ? a64>>(dist & 63) | (((a64 & (((uint_fast64_t) 1<<(dist & 63)) - 1)) | a0) != 0) : ((a64 | a0) != 0); } return z; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_shiftRightJam128Extra.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_shiftRightJam128Extra struct uint128_extra softfloat_shiftRightJam128Extra( uint64_t a64, uint64_t a0, uint64_t extra, uint_fast32_t dist ) { uint_fast8_t u8NegDist; struct uint128_extra z; u8NegDist = -dist; if ( dist < 64 ) { z.v.v64 = a64>>dist; z.v.v0 = a64<<(u8NegDist & 63) | a0>>dist; z.extra = a0<<(u8NegDist & 63); } else { z.v.v64 = 0; if ( dist == 64 ) { z.v.v0 = a64; z.extra = a0; } else { extra |= a0; if ( dist < 128 ) { z.v.v0 = a64>>(dist & 63); z.extra = a64<<(u8NegDist & 63); } else { z.v.v0 = 0; z.extra = (dist == 128) ? a64 : (a64 != 0); } } } z.extra |= (extra != 0); return z; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_shiftRightJam256M.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_shiftRightJam256M static void softfloat_shortShiftRightJamM( uint_fast8_t size_words, const uint64_t *aPtr, uint_fast8_t dist, uint64_t *zPtr ) { uint_fast8_t uNegDist; unsigned int index, lastIndex; uint64_t partWordZ, wordA; uNegDist = -dist; index = indexWordLo( size_words ); lastIndex = indexWordHi( size_words ); wordA = aPtr[index]; partWordZ = wordA>>dist; if ( partWordZ<>dist; } zPtr[index] = partWordZ; } void softfloat_shiftRightJam256M( const uint64_t *aPtr, uint_fast32_t dist, uint64_t *zPtr ) { uint64_t wordJam; uint_fast32_t wordDist; uint64_t *ptr; uint_fast8_t i, innerDist; wordJam = 0; wordDist = dist>>6; if ( wordDist ) { if ( 4 < wordDist ) wordDist = 4; ptr = (uint64_t *) (aPtr + indexMultiwordLo( 4, wordDist )); i = wordDist; do { wordJam = *ptr++; if ( wordJam ) break; --i; } while ( i ); ptr = zPtr; } if ( wordDist < 4 ) { aPtr += indexMultiwordHiBut( 4, wordDist ); innerDist = dist & 63; if ( innerDist ) { softfloat_shortShiftRightJamM( 4 - wordDist, aPtr, innerDist, zPtr + indexMultiwordLoBut( 4, wordDist ) ); if ( ! wordDist ) goto wordJam; } else { aPtr += indexWordLo( 4 - wordDist ); ptr = zPtr + indexWordLo( 4 ); for ( i = 4 - wordDist; i; --i ) { *ptr = *aPtr; aPtr += wordIncr; ptr += wordIncr; } } ptr = zPtr + indexMultiwordHi( 4, wordDist ); } do { *ptr++ = 0; --wordDist; } while ( wordDist ); wordJam: if ( wordJam ) zPtr[indexWordLo( 4 )] |= 1; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_shiftRightJam32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #ifndef softfloat_shiftRightJam32 uint32_t softfloat_shiftRightJam32( uint32_t a, uint_fast16_t dist ) { return (dist < 31) ? a>>dist | ((uint32_t) (a<<(-dist & 31)) != 0) : (a != 0); } #endif ================================================ FILE: vp/src/vendor/softfloat/s_shiftRightJam64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #ifndef softfloat_shiftRightJam64 uint64_t softfloat_shiftRightJam64( uint64_t a, uint_fast32_t dist ) { return (dist < 63) ? a>>dist | ((uint64_t) (a<<(-dist & 63)) != 0) : (a != 0); } #endif ================================================ FILE: vp/src/vendor/softfloat/s_shiftRightJam64Extra.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_shiftRightJam64Extra struct uint64_extra softfloat_shiftRightJam64Extra( uint64_t a, uint64_t extra, uint_fast32_t dist ) { struct uint64_extra z; if ( dist < 64 ) { z.v = a>>dist; z.extra = a<<(-dist & 63); } else { z.v = 0; z.extra = (dist == 64) ? a : (a != 0); } z.extra |= (extra != 0); return z; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_shortShiftLeft128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_shortShiftLeft128 struct uint128 softfloat_shortShiftLeft128( uint64_t a64, uint64_t a0, uint_fast8_t dist ) { struct uint128 z; z.v64 = a64<>(-dist & 63); z.v0 = a0< #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_shortShiftLeft64To96M void softfloat_shortShiftLeft64To96M( uint64_t a, uint_fast8_t dist, uint32_t *zPtr ) { zPtr[indexWord( 3, 0 )] = (uint32_t) a<>= 32 - dist; zPtr[indexWord( 3, 2 )] = a>>32; zPtr[indexWord( 3, 1 )] = a; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_shortShiftRight128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_shortShiftRight128 struct uint128 softfloat_shortShiftRight128( uint64_t a64, uint64_t a0, uint_fast8_t dist ) { struct uint128 z; z.v64 = a64>>dist; z.v0 = a64<<(-dist & 63) | a0>>dist; return z; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_shortShiftRightExtendM.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_shortShiftRightExtendM void softfloat_shortShiftRightExtendM( uint_fast8_t size_words, const uint32_t *aPtr, uint_fast8_t dist, uint32_t *zPtr ) { uint_fast8_t uNegDist; unsigned int indexA, lastIndexA; uint32_t partWordZ, wordA; uNegDist = -dist; indexA = indexWordLo( size_words ); lastIndexA = indexWordHi( size_words ); zPtr += indexWordLo( size_words + 1 ); partWordZ = 0; for (;;) { wordA = aPtr[indexA]; *zPtr = wordA<<(uNegDist & 31) | partWordZ; zPtr += wordIncr; partWordZ = wordA>>dist; if ( indexA == lastIndexA ) break; indexA += wordIncr; } *zPtr = partWordZ; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_shortShiftRightJam128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_shortShiftRightJam128 struct uint128 softfloat_shortShiftRightJam128( uint64_t a64, uint64_t a0, uint_fast8_t dist ) { uint_fast8_t uNegDist; struct uint128 z; uNegDist = -dist; z.v64 = a64>>dist; z.v0 = a64<<(uNegDist & 63) | a0>>dist | ((uint64_t) (a0<<(uNegDist & 63)) != 0); return z; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_shortShiftRightJam128Extra.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_shortShiftRightJam128Extra struct uint128_extra softfloat_shortShiftRightJam128Extra( uint64_t a64, uint64_t a0, uint64_t extra, uint_fast8_t dist ) { uint_fast8_t uNegDist; struct uint128_extra z; uNegDist = -dist; z.v.v64 = a64>>dist; z.v.v0 = a64<<(uNegDist & 63) | a0>>dist; z.extra = a0<<(uNegDist & 63) | (extra != 0); return z; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_shortShiftRightJam64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #ifndef softfloat_shortShiftRightJam64 uint64_t softfloat_shortShiftRightJam64( uint64_t a, uint_fast8_t dist ) { return a>>dist | ((a & (((uint_fast64_t) 1< #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_shortShiftRightJam64Extra struct uint64_extra softfloat_shortShiftRightJam64Extra( uint64_t a, uint64_t extra, uint_fast8_t dist ) { struct uint64_extra z; z.v = a>>dist; z.extra = a<<(-dist & 63) | (extra != 0); return z; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_shortShiftRightM.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_shortShiftRightM void softfloat_shortShiftRightM( uint_fast8_t size_words, const uint32_t *aPtr, uint_fast8_t dist, uint32_t *zPtr ) { uint_fast8_t uNegDist; unsigned int index, lastIndex; uint32_t partWordZ, wordA; uNegDist = -dist; index = indexWordLo( size_words ); lastIndex = indexWordHi( size_words ); partWordZ = aPtr[index]>>dist; while ( index != lastIndex ) { wordA = aPtr[index + wordIncr]; zPtr[index] = wordA<<(uNegDist & 31) | partWordZ; index += wordIncr; partWordZ = wordA>>dist; } zPtr[index] = partWordZ; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_sub128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_sub128 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 - (a0 < b0); return z; } #endif ================================================ FILE: vp/src/vendor/softfloat/s_sub1XM.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_sub1XM void softfloat_sub1XM( uint_fast8_t size_words, uint32_t *zPtr ) { unsigned int index, lastIndex; uint32_t wordA; index = indexWordLo( size_words ); lastIndex = indexWordHi( size_words ); for (;;) { wordA = zPtr[index]; zPtr[index] = wordA - 1; if ( wordA || (index == lastIndex) ) break; index += wordIncr; } } #endif ================================================ FILE: vp/src/vendor/softfloat/s_sub256M.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_sub256M void softfloat_sub256M( const uint64_t *aPtr, const uint64_t *bPtr, uint64_t *zPtr ) { unsigned int index; uint_fast8_t borrow; uint64_t wordA, wordB; index = indexWordLo( 4 ); borrow = 0; for (;;) { wordA = aPtr[index]; wordB = bPtr[index]; zPtr[index] = wordA - wordB - borrow; if ( index == indexWordHi( 4 ) ) break; borrow = borrow ? (wordA <= wordB) : (wordA < wordB); index += wordIncr; } } #endif ================================================ FILE: vp/src/vendor/softfloat/s_subM.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "primitiveTypes.h" #ifndef softfloat_subM void softfloat_subM( uint_fast8_t size_words, const uint32_t *aPtr, const uint32_t *bPtr, uint32_t *zPtr ) { unsigned int index, lastIndex; uint_fast8_t borrow; uint32_t wordA, wordB; index = indexWordLo( size_words ); lastIndex = indexWordHi( size_words ); borrow = 0; for (;;) { wordA = aPtr[index]; wordB = bPtr[index]; zPtr[index] = wordA - wordB - borrow; if ( index == lastIndex ) break; borrow = borrow ? (wordA <= wordB) : (wordA < wordB); index += wordIncr; } } #endif ================================================ FILE: vp/src/vendor/softfloat/s_subMagsF128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float128_t softfloat_subMagsF128( uint_fast64_t uiA64, uint_fast64_t uiA0, uint_fast64_t uiB64, uint_fast64_t uiB0, bool signZ ) { int_fast32_t expA; struct uint128 sigA; int_fast32_t expB; struct uint128 sigB, sigZ; int_fast32_t expDiff, expZ; struct uint128 uiZ; union ui128_f128 uZ; expA = expF128UI64( uiA64 ); sigA.v64 = fracF128UI64( uiA64 ); sigA.v0 = uiA0; expB = expF128UI64( uiB64 ); sigB.v64 = fracF128UI64( uiB64 ); sigB.v0 = uiB0; sigA = softfloat_shortShiftLeft128( sigA.v64, sigA.v0, 4 ); sigB = softfloat_shortShiftLeft128( sigB.v64, sigB.v0, 4 ); expDiff = expA - expB; if ( 0 < expDiff ) goto expABigger; if ( expDiff < 0 ) goto expBBigger; if ( expA == 0x7FFF ) { if ( sigA.v64 | sigA.v0 | sigB.v64 | sigB.v0 ) goto propagateNaN; softfloat_raiseFlags( softfloat_flag_invalid ); uiZ.v64 = defaultNaNF128UI64; uiZ.v0 = defaultNaNF128UI0; goto uiZ; } expZ = expA; if ( ! expZ ) expZ = 1; if ( sigB.v64 < sigA.v64 ) goto aBigger; if ( sigA.v64 < sigB.v64 ) goto bBigger; if ( sigB.v0 < sigA.v0 ) goto aBigger; if ( sigA.v0 < sigB.v0 ) goto bBigger; uiZ.v64 = packToF128UI64( (softfloat_roundingMode == softfloat_round_min), 0, 0 ); uiZ.v0 = 0; goto uiZ; expBBigger: if ( expB == 0x7FFF ) { if ( sigB.v64 | sigB.v0 ) goto propagateNaN; uiZ.v64 = packToF128UI64( signZ ^ 1, 0x7FFF, 0 ); uiZ.v0 = 0; goto uiZ; } if ( expA ) { sigA.v64 |= UINT64_C( 0x0010000000000000 ); } else { ++expDiff; if ( ! expDiff ) goto newlyAlignedBBigger; } sigA = softfloat_shiftRightJam128( sigA.v64, sigA.v0, -expDiff ); newlyAlignedBBigger: expZ = expB; sigB.v64 |= UINT64_C( 0x0010000000000000 ); bBigger: signZ = ! signZ; sigZ = softfloat_sub128( sigB.v64, sigB.v0, sigA.v64, sigA.v0 ); goto normRoundPack; expABigger: if ( expA == 0x7FFF ) { if ( sigA.v64 | sigA.v0 ) goto propagateNaN; uiZ.v64 = uiA64; uiZ.v0 = uiA0; goto uiZ; } if ( expB ) { sigB.v64 |= UINT64_C( 0x0010000000000000 ); } else { --expDiff; if ( ! expDiff ) goto newlyAlignedABigger; } sigB = softfloat_shiftRightJam128( sigB.v64, sigB.v0, expDiff ); newlyAlignedABigger: expZ = expA; sigA.v64 |= UINT64_C( 0x0010000000000000 ); aBigger: sigZ = softfloat_sub128( sigA.v64, sigA.v0, sigB.v64, sigB.v0 ); normRoundPack: return softfloat_normRoundPackToF128( signZ, expZ - 5, sigZ.v64, sigZ.v0 ); propagateNaN: uiZ = softfloat_propagateNaNF128UI( uiA64, uiA0, uiB64, uiB0 ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/s_subMagsF16.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float16_t softfloat_subMagsF16( uint_fast16_t uiA, uint_fast16_t uiB ) { int_fast8_t expA; uint_fast16_t sigA; int_fast8_t expB; uint_fast16_t sigB; int_fast8_t expDiff; uint_fast16_t uiZ; int_fast16_t sigDiff; bool signZ; int_fast8_t shiftDist, expZ; uint_fast16_t sigZ, sigX, sigY; uint_fast32_t sig32Z; int_fast8_t roundingMode; union ui16_f16 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expA = expF16UI( uiA ); sigA = fracF16UI( uiA ); expB = expF16UI( uiB ); sigB = fracF16UI( uiB ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expA - expB; if ( ! expDiff ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expA == 0x1F ) { if ( sigA | sigB ) goto propagateNaN; softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF16UI; goto uiZ; } sigDiff = sigA - sigB; if ( ! sigDiff ) { uiZ = packToF16UI( (softfloat_roundingMode == softfloat_round_min), 0, 0 ); goto uiZ; } if ( expA ) --expA; signZ = signF16UI( uiA ); if ( sigDiff < 0 ) { signZ = ! signZ; sigDiff = -sigDiff; } shiftDist = softfloat_countLeadingZeros16( sigDiff ) - 5; expZ = expA - shiftDist; if ( expZ < 0 ) { shiftDist = expA; expZ = 0; } sigZ = sigDiff<>16; if ( sig32Z & 0xFFFF ) { sigZ |= 1; } else { if ( ! (sigZ & 0xF) && ((unsigned int) expZ < 0x1E) ) { sigZ >>= 4; goto pack; } } return softfloat_roundPackToF16( signZ, expZ, sigZ ); } /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ propagateNaN: uiZ = softfloat_propagateNaNF16UI( uiA, uiB ); goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ subEpsilon: roundingMode = softfloat_roundingMode; if ( roundingMode != softfloat_round_near_even ) { if ( (roundingMode == softfloat_round_minMag) || (roundingMode == (signF16UI( uiZ ) ? softfloat_round_max : softfloat_round_min)) ) { --uiZ; } #ifdef SOFTFLOAT_ROUND_ODD else if ( roundingMode == softfloat_round_odd ) { uiZ = (uiZ - 1) | 1; } #endif } softfloat_exceptionFlags |= softfloat_flag_inexact; goto uiZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ pack: uiZ = packToF16UI( signZ, expZ, sigZ ); uiZ: uZ.ui = uiZ; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/s_subMagsF32.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" float32_t softfloat_subMagsF32( uint_fast32_t uiA, uint_fast32_t uiB ) { 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_fast32_t sigDiff; bool signZ; int_fast8_t shiftDist; int_fast16_t expZ; uint_fast32_t sigX, sigY; union ui32_f32 uZ; /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expA = expF32UI( uiA ); sigA = fracF32UI( uiA ); expB = expF32UI( uiB ); sigB = fracF32UI( uiB ); /*------------------------------------------------------------------------ *------------------------------------------------------------------------*/ expDiff = expA - expB; if ( ! expDiff ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expA == 0xFF ) { if ( sigA | sigB ) goto propagateNaN; softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF32UI; goto uiZ; } sigDiff = sigA - sigB; if ( ! sigDiff ) { uiZ = packToF32UI( (softfloat_roundingMode == softfloat_round_min), 0, 0 ); goto uiZ; } if ( expA ) --expA; signZ = signF32UI( uiA ); if ( sigDiff < 0 ) { signZ = ! signZ; sigDiff = -sigDiff; } shiftDist = softfloat_countLeadingZeros32( sigDiff ) - 8; expZ = expA - shiftDist; if ( expZ < 0 ) { shiftDist = expA; expZ = 0; } uiZ = packToF32UI( signZ, expZ, sigDiff< #include #include "platform.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_fast64_t sigDiff; int_fast8_t shiftDist; 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; if ( ! expDiff ) { /*-------------------------------------------------------------------- *--------------------------------------------------------------------*/ if ( expA == 0x7FF ) { if ( sigA | sigB ) goto propagateNaN; softfloat_raiseFlags( softfloat_flag_invalid ); uiZ = defaultNaNF64UI; goto uiZ; } sigDiff = sigA - sigB; if ( ! sigDiff ) { uiZ = packToF64UI( (softfloat_roundingMode == softfloat_round_min), 0, 0 ); goto uiZ; } if ( expA ) --expA; if ( sigDiff < 0 ) { signZ = ! signZ; sigDiff = -sigDiff; } shiftDist = softfloat_countLeadingZeros64( sigDiff ) - 11; expZ = expA - shiftDist; if ( expZ < 0 ) { shiftDist = expA; expZ = 0; } uiZ = packToF64UI( signZ, expZ, sigDiff< #include "platform.h" #include "internals.h" #include "specialize.h" #include "softfloat.h" #ifndef THREAD_LOCAL #define THREAD_LOCAL #endif THREAD_LOCAL uint_fast8_t softfloat_roundingMode = softfloat_round_near_even; THREAD_LOCAL uint_fast8_t softfloat_detectTininess = init_detectTininess; THREAD_LOCAL uint_fast8_t softfloat_exceptionFlags = 0; THREAD_LOCAL uint_fast8_t extF80_roundingPrecision = 80; ================================================ FILE: vp/src/vendor/softfloat/ui32_to_f128.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "internals.h" #include "softfloat.h" float128_t ui32_to_f128( uint32_t a ) { uint_fast64_t uiZ64; int_fast8_t shiftDist; union ui128_f128 uZ; uiZ64 = 0; if ( a ) { shiftDist = softfloat_countLeadingZeros32( a ) + 17; uiZ64 = packToF128UI64( 0, 0x402E - shiftDist, (uint_fast64_t) a< #include "platform.h" #include "internals.h" #include "softfloat.h" float16_t ui32_to_f16( uint32_t a ) { int_fast8_t shiftDist; union ui16_f16 u; uint_fast16_t sig; shiftDist = softfloat_countLeadingZeros32( a ) - 21; if ( 0 <= shiftDist ) { u.ui = a ? packToF16UI( 0, 0x18 - shiftDist, (uint_fast16_t) a<>(-shiftDist) | ((uint32_t) (a<<(shiftDist & 31)) != 0) : (uint_fast16_t) a< #include "platform.h" #include "internals.h" #include "softfloat.h" float32_t ui32_to_f32( uint32_t a ) { union ui32_f32 uZ; if ( ! a ) { uZ.ui = 0; return uZ.f; } if ( a & 0x80000000 ) { return softfloat_roundPackToF32( 0, 0x9D, a>>1 | (a & 1) ); } else { return softfloat_normRoundPackToF32( 0, 0x9C, a ); } } ================================================ FILE: vp/src/vendor/softfloat/ui32_to_f64.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "internals.h" #include "softfloat.h" float64_t ui32_to_f64( uint32_t a ) { uint_fast64_t uiZ; int_fast8_t shiftDist; union ui64_f64 uZ; if ( ! a ) { uiZ = 0; } else { shiftDist = softfloat_countLeadingZeros32( a ) + 21; uiZ = packToF64UI( 0, 0x432 - shiftDist, (uint_fast64_t) a< #include "platform.h" #include "internals.h" #include "softfloat.h" float128_t ui64_to_f128( uint64_t a ) { uint_fast64_t uiZ64, uiZ0; int_fast8_t shiftDist; struct uint128 zSig; union ui128_f128 uZ; if ( ! a ) { uiZ64 = 0; uiZ0 = 0; } else { shiftDist = softfloat_countLeadingZeros64( a ) + 49; if ( 64 <= shiftDist ) { zSig.v64 = a<<(shiftDist - 64); zSig.v0 = 0; } else { zSig = softfloat_shortShiftLeft128( 0, a, shiftDist ); } uiZ64 = packToF128UI64( 0, 0x406E - shiftDist, zSig.v64 ); uiZ0 = zSig.v0; } uZ.ui.v64 = uiZ64; uZ.ui.v0 = uiZ0; return uZ.f; } ================================================ FILE: vp/src/vendor/softfloat/ui64_to_f16.c ================================================ /*============================================================================ This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic Package, Release 3d, by John R. Hauser. Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of California. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. =============================================================================*/ #include #include "platform.h" #include "internals.h" #include "softfloat.h" float16_t ui64_to_f16( uint64_t a ) { int_fast8_t shiftDist; union ui16_f16 u; uint_fast16_t sig; shiftDist = softfloat_countLeadingZeros64( a ) - 53; if ( 0 <= shiftDist ) { u.ui = a ? packToF16UI( 0, 0x18 - shiftDist, (uint_fast16_t) a< #include "platform.h" #include "internals.h" #include "softfloat.h" float32_t ui64_to_f32( uint64_t a ) { int_fast8_t shiftDist; union ui32_f32 u; uint_fast32_t sig; shiftDist = softfloat_countLeadingZeros64( a ) - 40; if ( 0 <= shiftDist ) { u.ui = a ? packToF32UI( 0, 0x95 - shiftDist, (uint_fast32_t) a< #include "platform.h" #include "internals.h" #include "softfloat.h" float64_t ui64_to_f64( uint64_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_shortShiftRightJam64( a, 1 ) ); } else { return softfloat_normRoundPackToF64( 0, 0x43C, a ); } }