From 62cdd8e99385ce5470c96b7ce1808080d11e740f Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sat, 11 Nov 2023 15:49:39 -0800 Subject: [PATCH 01/57] minor update --- .travis.yml | 6 ++-- ci/toolchain_env.sh | 7 ++--- docs/fpga_setup.md | 3 -- hw/syn/xilinx/test/kernel/Makefile | 5 +-- kernel/Makefile | 7 +++-- tests/kernel/common.mk | 49 ++++++++++++++++++++++++++++++ tests/kernel/conform/Makefile | 49 +----------------------------- tests/kernel/fibonacci/Makefile | 49 +----------------------------- tests/kernel/hello/Makefile | 49 +----------------------------- tests/opencl/common.mk | 13 ++++---- tests/regression/common.mk | 8 +++-- tests/unittest/common.mk | 30 ++++++++++++++++++ tests/unittest/vx_malloc/Makefile | 31 +------------------ 13 files changed, 107 insertions(+), 199 deletions(-) create mode 100644 tests/kernel/common.mk create mode 100644 tests/unittest/common.mk diff --git a/.travis.yml b/.travis.yml index f719ce86..236ed3b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ jobs: - rm -rf $HOME/build32 && cp -r $PWD $HOME/build32 - rm -rf $HOME/build64 && cp -r $PWD $HOME/build64 - make -C $HOME/build32 - - XLEN=64 RISCV_TOOLCHAIN_PATH=$TOOLDIR/riscv64-gnu-toolchain make -C $HOME/build64 + - XLEN=64 make -C $HOME/build64 - stage: test name: unittest script: cp -r $HOME/build32 build && cd build && ./ci/travis_run.py ./ci/regression.sh --unittest @@ -47,13 +47,13 @@ jobs: script: cp -r $HOME/build32 build && cd build && ./ci/travis_run.py ./ci/regression.sh --isa - stage: test name: isa64 - script: cp -r $HOME/build64 build && cd build && XLEN=64 RISCV_TOOLCHAIN_PATH=$TOOLDIR/riscv64-gnu-toolchain ./ci/travis_run.py ./ci/regression.sh --isa + script: cp -r $HOME/build64 build && cd build && XLEN=64 ./ci/travis_run.py ./ci/regression.sh --isa - stage: test name: regression script: cp -r $HOME/build32 build && cd build && ./ci/travis_run.py ./ci/regression.sh --regression - stage: test name: regression64 - script: cp -r $HOME/build64 build && cd build && XLEN=64 RISCV_TOOLCHAIN_PATH=$TOOLDIR/riscv64-gnu-toolchain ./ci/travis_run.py ./ci/regression.sh --regression + script: cp -r $HOME/build64 build && cd build && XLEN=64 ./ci/travis_run.py ./ci/regression.sh --regression - stage: test name: opencl script: cp -r $HOME/build32 build && cd build && ./ci/travis_run.py ./ci/regression.sh --opencl diff --git a/ci/toolchain_env.sh b/ci/toolchain_env.sh index 4046a6a7..440a899e 100644 --- a/ci/toolchain_env.sh +++ b/ci/toolchain_env.sh @@ -16,14 +16,11 @@ TOOLDIR=${TOOLDIR:=/opt} -export RISCV_TOOLCHAIN_PATH=$TOOLDIR/riscv-gnu-toolchain -export LLVM_POCL=$TOOLDIR/llvm-pocl -export LLVM_VORTEX=$TOOLDIR/llvm-vortex export VERILATOR_ROOT=$TOOLDIR/verilator export PATH=$VERILATOR_ROOT/bin:$PATH + export SV2V_PATH=$TOOLDIR/sv2v export PATH=$SV2V_PATH/bin:$PATH + export YOSYS_PATH=$TOOLDIR/yosys export PATH=$YOSYS_PATH/bin:$PATH -export POCL_CC_PATH=$TOOLDIR/pocl/compiler -export POCL_RT_PATH=$TOOLDIR/pocl/runtime diff --git a/docs/fpga_setup.md b/docs/fpga_setup.md index 61ff481f..88e0c3c0 100644 --- a/docs/fpga_setup.md +++ b/docs/fpga_setup.md @@ -9,9 +9,6 @@ OPAE Environment Setup $ export C_INCLUDE_PATH=$OPAE_HOME/include:$C_INCLUDE_PATH $ export LIBRARY_PATH=$OPAE_HOME/lib:$LIBRARY_PATH $ export LD_LIBRARY_PATH=$OPAE_HOME/lib:$LD_LIBRARY_PATH - $ export RISCV_TOOLCHAIN_PATH=/opt/riscv-gnu-toolchain - $ export PATH=:/opt/verilator/bin:$PATH - $ export VERILATOR_ROOT=/opt/verilator OPAE Build ------------------ diff --git a/hw/syn/xilinx/test/kernel/Makefile b/hw/syn/xilinx/test/kernel/Makefile index 55c21aa2..11457ab4 100644 --- a/hw/syn/xilinx/test/kernel/Makefile +++ b/hw/syn/xilinx/test/kernel/Makefile @@ -1,10 +1,11 @@ XLEN ?= 32 +TOOLDIR ?= /opt ifeq ($(XLEN),64) -RISCV_TOOLCHAIN_PATH ?= /opt/riscv64-gnu-toolchain +RISCV_TOOLCHAIN_PATH ?= $(TOOLDIR)/riscv64-gnu-toolchain CFLAGS += -march=rv64imafd -mabi=lp64d else -RISCV_TOOLCHAIN_PATH ?= /opt/riscv-gnu-toolchain +RISCV_TOOLCHAIN_PATH ?= $(TOOLDIR)/riscv-gnu-toolchain CFLAGS += -march=rv32imaf -mabi=ilp32f endif diff --git a/kernel/Makefile b/kernel/Makefile index e4c975dc..07b8c97b 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,17 +1,18 @@ XLEN ?= 32 +TOOLDIR ?= /opt ifeq ($(XLEN),64) -RISCV_TOOLCHAIN_PATH ?= /opt/riscv64-gnu-toolchain +RISCV_TOOLCHAIN_PATH ?= $(TOOLDIR)/riscv64-gnu-toolchain CFLAGS += -march=rv64imafd -mabi=lp64d else -RISCV_TOOLCHAIN_PATH ?= /opt/riscv-gnu-toolchain +RISCV_TOOLCHAIN_PATH ?= $(TOOLDIR)/riscv-gnu-toolchain CFLAGS += -march=rv32imaf -mabi=ilp32f endif RISCV_PREFIX ?= riscv$(XLEN)-unknown-elf RISCV_SYSROOT ?= $(RISCV_TOOLCHAIN_PATH)/$(RISCV_PREFIX) -LLVM_VORTEX ?= /opt/llvm-vortex +LLVM_VORTEX ?= $(TOOLDIR)/llvm-vortex LLVM_CFLAGS += --sysroot=$(RISCV_SYSROOT) LLVM_CFLAGS += --gcc-toolchain=$(RISCV_TOOLCHAIN_PATH) diff --git a/tests/kernel/common.mk b/tests/kernel/common.mk new file mode 100644 index 00000000..7bf4b520 --- /dev/null +++ b/tests/kernel/common.mk @@ -0,0 +1,49 @@ +XLEN ?= 32 +TOOLDIR ?= /opt + +ifeq ($(XLEN),64) +RISCV_TOOLCHAIN_PATH ?= $(TOOLDIR)/riscv64-gnu-toolchain +CFLAGS += -march=rv64imafd -mabi=lp64d +else +RISCV_TOOLCHAIN_PATH ?= $(TOOLDIR)/riscv-gnu-toolchain +CFLAGS += -march=rv32imaf -mabi=ilp32f +endif + +RISCV_PREFIX ?= riscv$(XLEN)-unknown-elf + +VORTEX_KN_PATH ?= $(realpath ../../../kernel) + +CC = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-gcc +AR = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-gcc-ar +DP = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-objdump +CP = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-objcopy + +SIM_DIR = ../../../sim + +CFLAGS += -O3 -mcmodel=medany -fno-exceptions -nostartfiles -fdata-sections -ffunction-sections +CFLAGS += -I$(VORTEX_KN_PATH)/include -I$(VORTEX_KN_PATH)/../hw + +LDFLAGS += -lm -Wl,-Bstatic,--gc-sections,-T,$(VORTEX_KN_PATH)/linker/vx_link$(XLEN).ld,--defsym=STARTUP_ADDR=0x80000000 $(VORTEX_KN_PATH)/libvortexrt.a + +all: $(PROJECT).elf $(PROJECT).bin $(PROJECT).dump + +$(PROJECT).dump: $(PROJECT).elf + $(DP) -D $(PROJECT).elf > $(PROJECT).dump + +$(PROJECT).bin: $(PROJECT).elf + $(CP) -O binary $(PROJECT).elf $(PROJECT).bin + +$(PROJECT).elf: $(SRCS) + $(CC) $(CFLAGS) $(SRCS) $(LDFLAGS) -o $(PROJECT).elf + +run-rtlsim: $(PROJECT).bin + $(SIM_DIR)/rtlsim/rtlsim $(PROJECT).bin + +run-simx: $(PROJECT).bin + $(SIM_DIR)/simx/simx $(PROJECT).bin + +.depend: $(SRCS) + $(CC) $(CFLAGS) -MM $^ > .depend; + +clean: + rm -rf *.elf *.bin *.dump .depend diff --git a/tests/kernel/conform/Makefile b/tests/kernel/conform/Makefile index e9897125..ee96978f 100644 --- a/tests/kernel/conform/Makefile +++ b/tests/kernel/conform/Makefile @@ -1,52 +1,5 @@ -XLEN ?= 32 - -ifeq ($(XLEN),64) -RISCV_TOOLCHAIN_PATH ?= /opt/riscv64-gnu-toolchain -CFLAGS += -march=rv64imafd -mabi=lp64d -else -RISCV_TOOLCHAIN_PATH ?= /opt/riscv-gnu-toolchain -CFLAGS += -march=rv32imaf -mabi=ilp32f -endif - -RISCV_PREFIX ?= riscv$(XLEN)-unknown-elf - -VORTEX_KN_PATH ?= $(realpath ../../../kernel) - -CC = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-gcc -AR = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-gcc-ar -DP = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-objdump -CP = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-objcopy - -SIM_DIR = ../../../sim - -CFLAGS += -O3 -mcmodel=medany -fno-exceptions -nostartfiles -fdata-sections -ffunction-sections -CFLAGS += -I$(VORTEX_KN_PATH)/include -I$(VORTEX_KN_PATH)/../hw - -LDFLAGS += -lm -Wl,-Bstatic,--gc-sections,-T,$(VORTEX_KN_PATH)/linker/vx_link$(XLEN).ld,--defsym=STARTUP_ADDR=0x80000000 $(VORTEX_KN_PATH)/libvortexrt.a - PROJECT = conform SRCS = main.cpp tests.cpp -all: $(PROJECT).elf $(PROJECT).bin $(PROJECT).dump - -$(PROJECT).dump: $(PROJECT).elf - $(DP) -D $(PROJECT).elf > $(PROJECT).dump - -$(PROJECT).bin: $(PROJECT).elf - $(CP) -O binary $(PROJECT).elf $(PROJECT).bin - -$(PROJECT).elf: $(SRCS) - $(CC) $(CFLAGS) $(SRCS) $(LDFLAGS) -o $(PROJECT).elf - -run-rtlsim: $(PROJECT).bin - $(SIM_DIR)/rtlsim/rtlsim $(PROJECT).bin - -run-simx: $(PROJECT).bin - $(SIM_DIR)/simx/simx $(PROJECT).bin - -.depend: $(SRCS) - $(CC) $(CFLAGS) -MM $^ > .depend; - -clean: - rm -rf *.elf *.bin *.dump .depend +include ../common.mk diff --git a/tests/kernel/fibonacci/Makefile b/tests/kernel/fibonacci/Makefile index 1338b4ab..d4486c74 100644 --- a/tests/kernel/fibonacci/Makefile +++ b/tests/kernel/fibonacci/Makefile @@ -1,52 +1,5 @@ -XLEN ?= 32 - -ifeq ($(XLEN),64) -RISCV_TOOLCHAIN_PATH ?= /opt/riscv64-gnu-toolchain -CFLAGS += -march=rv64imafd -mabi=lp64d -else -RISCV_TOOLCHAIN_PATH ?= /opt/riscv-gnu-toolchain -CFLAGS += -march=rv32imaf -mabi=ilp32f -endif - -RISCV_PREFIX ?= riscv$(XLEN)-unknown-elf - -VORTEX_KN_PATH ?= $(realpath ../../../kernel) - -CC = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-gcc -AR = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-gcc-ar -DP = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-objdump -CP = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-objcopy - -SIM_DIR = ../../../sim - -CFLAGS += -O3 -mcmodel=medany -fno-exceptions -nostartfiles -fdata-sections -ffunction-sections -CFLAGS += -I$(VORTEX_KN_PATH)/include -I$(VORTEX_KN_PATH)/../hw - -LDFLAGS += -lm -Wl,-Bstatic,--gc-sections,-T,$(VORTEX_KN_PATH)/linker/vx_link$(XLEN).ld,--defsym=STARTUP_ADDR=0x80000000 $(VORTEX_KN_PATH)/libvortexrt.a - PROJECT = fibonacci SRCS = main.cpp -all: $(PROJECT).elf $(PROJECT).bin $(PROJECT).dump - -$(PROJECT).dump: $(PROJECT).elf - $(DP) -D $(PROJECT).elf > $(PROJECT).dump - -$(PROJECT).bin: $(PROJECT).elf - $(CP) -O binary $(PROJECT).elf $(PROJECT).bin - -$(PROJECT).elf: $(SRCS) - $(CC) $(CFLAGS) $(SRCS) $(LDFLAGS) -o $(PROJECT).elf - -run-rtlsim: $(PROJECT).bin - $(SIM_DIR)/rtlsim/rtlsim $(PROJECT).bin - -run-simx: $(PROJECT).bin - $(SIM_DIR)/simx/simx $(PROJECT).bin - -.depend: $(SRCS) - $(CC) $(CFLAGS) -MM $^ > .depend; - -clean: - rm -rf *.elf *.bin *.dump .depend +include ../common.mk diff --git a/tests/kernel/hello/Makefile b/tests/kernel/hello/Makefile index 42d95256..4cff6cbd 100644 --- a/tests/kernel/hello/Makefile +++ b/tests/kernel/hello/Makefile @@ -1,52 +1,5 @@ -XLEN ?= 32 - -ifeq ($(XLEN),64) -RISCV_TOOLCHAIN_PATH ?= /opt/riscv64-gnu-toolchain -CFLAGS += -march=rv64imafd -mabi=lp64d -else -RISCV_TOOLCHAIN_PATH ?= /opt/riscv-gnu-toolchain -CFLAGS += -march=rv32imaf -mabi=ilp32f -endif - -RISCV_PREFIX ?= riscv$(XLEN)-unknown-elf - -VORTEX_KN_PATH ?= $(realpath ../../../kernel) - -CC = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-gcc -AR = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-gcc-ar -DP = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-objdump -CP = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-objcopy - -SIM_DIR = ../../../sim - -CFLAGS += -O3 -v -mcmodel=medany -fno-exceptions -nostartfiles -fdata-sections -ffunction-sections -CFLAGS += -I$(VORTEX_KN_PATH)/include -I$(VORTEX_KN_PATH)/../hw - -LDFLAGS += -lm -Wl,-Bstatic,--gc-sections,-T,$(VORTEX_KN_PATH)/linker/vx_link$(XLEN).ld,--defsym=STARTUP_ADDR=0x80000000 $(VORTEX_KN_PATH)/libvortexrt.a - PROJECT = hello SRCS = main.cpp -all: $(PROJECT).elf $(PROJECT).bin $(PROJECT).dump - -$(PROJECT).dump: $(PROJECT).elf - $(DP) -D $(PROJECT).elf > $(PROJECT).dump - -$(PROJECT).bin: $(PROJECT).elf - $(CP) -O binary $(PROJECT).elf $(PROJECT).bin - -$(PROJECT).elf: $(SRCS) - $(CC) $(CFLAGS) $(SRCS) $(LDFLAGS) -o $(PROJECT).elf - -run-rtlsim: $(PROJECT).bin - $(SIM_DIR)/rtlsim/rtlsim $(PROJECT).bin - -run-simx: $(PROJECT).bin - $(SIM_DIR)/simx/simx $(PROJECT).bin - -.depend: $(SRCS) - $(CC) $(CFLAGS) -MM $^ > .depend; - -clean: - rm -rf *.elf *.bin *.dump .depend +include ../common.mk diff --git a/tests/opencl/common.mk b/tests/opencl/common.mk index fc55ee0a..ce82dac3 100644 --- a/tests/opencl/common.mk +++ b/tests/opencl/common.mk @@ -1,4 +1,5 @@ XLEN ?= 32 +TOOLDIR ?= /opt TARGET ?= opaesim @@ -6,12 +7,12 @@ XRT_SYN_DIR ?= ../../../hw/syn/xilinx/xrt XRT_DEVICE_INDEX ?= 0 ifeq ($(XLEN),64) -RISCV_TOOLCHAIN_PATH ?= /opt/riscv64-gnu-toolchain +RISCV_TOOLCHAIN_PATH ?= $(TOOLDIR)/riscv64-gnu-toolchain VX_CFLAGS += -march=rv64imafd -mabi=lp64d K_CFLAGS += -march=rv64imafd -mabi=ilp64d STARTUP_ADDR ?= 0x180000000 else -RISCV_TOOLCHAIN_PATH ?= /opt/riscv-gnu-toolchain +RISCV_TOOLCHAIN_PATH ?= $(TOOLDIR)/riscv-gnu-toolchain VX_CFLAGS += -march=rv32imaf -mabi=ilp32f K_CFLAGS += -march=rv32imaf -mabi=ilp32f STARTUP_ADDR ?= 0x80000000 @@ -20,16 +21,16 @@ endif RISCV_PREFIX ?= riscv$(XLEN)-unknown-elf RISCV_SYSROOT ?= $(RISCV_TOOLCHAIN_PATH)/$(RISCV_PREFIX) -POCL_CC_PATH ?= /opt/pocl/compiler -POCL_RT_PATH ?= /opt/pocl/runtime +POCL_CC_PATH ?= $(TOOLDIR)/pocl/compiler +POCL_RT_PATH ?= $(TOOLDIR)/pocl/runtime VORTEX_RT_PATH ?= $(realpath ../../../runtime) VORTEX_KN_PATH ?= $(realpath ../../../kernel) FPGA_BIN_DIR ?= $(VORTEX_RT_PATH)/opae -LLVM_VORTEX ?= /opt/llvm-vortex -LLVM_POCL ?= /opt/llvm-vortex +LLVM_VORTEX ?= $(TOOLDIR)/llvm-vortex +LLVM_POCL ?= $(TOOLDIR)/llvm-vortex K_CFLAGS += -v -O3 --sysroot=$(RISCV_SYSROOT) --gcc-toolchain=$(RISCV_TOOLCHAIN_PATH) -Xclang -target-feature -Xclang +vortex K_CFLAGS += -fno-rtti -fno-exceptions -nostartfiles -fdata-sections -ffunction-sections diff --git a/tests/regression/common.mk b/tests/regression/common.mk index 006d6668..6a858edc 100644 --- a/tests/regression/common.mk +++ b/tests/regression/common.mk @@ -1,16 +1,18 @@ XLEN ?= 32 +TOOLDIR ?= /opt + TARGET ?= opaesim XRT_SYN_DIR ?= ../../../hw/syn/xilinx/xrt XRT_DEVICE_INDEX ?= 0 ifeq ($(XLEN),64) -RISCV_TOOLCHAIN_PATH ?= /opt/riscv64-gnu-toolchain +RISCV_TOOLCHAIN_PATH ?= $(TOOLDIR)/riscv64-gnu-toolchain VX_CFLAGS += -march=rv64imafd -mabi=lp64d STARTUP_ADDR ?= 0x180000000 else -RISCV_TOOLCHAIN_PATH ?= /opt/riscv-gnu-toolchain +RISCV_TOOLCHAIN_PATH ?= $(TOOLDIR)/riscv-gnu-toolchain VX_CFLAGS += -march=rv32imaf -mabi=ilp32f STARTUP_ADDR ?= 0x80000000 endif @@ -23,7 +25,7 @@ VORTEX_KN_PATH ?= $(realpath ../../../kernel) FPGA_BIN_DIR ?= $(VORTEX_RT_PATH)/opae -LLVM_VORTEX ?= /opt/llvm-vortex +LLVM_VORTEX ?= $(TOOLDIR)/llvm-vortex LLVM_CFLAGS += --sysroot=$(RISCV_SYSROOT) LLVM_CFLAGS += --gcc-toolchain=$(RISCV_TOOLCHAIN_PATH) diff --git a/tests/unittest/common.mk b/tests/unittest/common.mk new file mode 100644 index 00000000..11add105 --- /dev/null +++ b/tests/unittest/common.mk @@ -0,0 +1,30 @@ +VORTEX_RT_PATH ?= $(realpath ../../../runtime) + +CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic -Wfatal-errors + +CXXFLAGS += -I$(VORTEX_RT_PATH)/common + +# Debugigng +ifdef DEBUG + CXXFLAGS += -g -O0 +else + CXXFLAGS += -O2 -DNDEBUG +endif + +all: $(PROJECT) + +$(PROJECT): $(SRCS) + $(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ + +run: + ./$(PROJECT) + +clean: + rm -rf $(PROJECT) *.o .depend + +clean-all: clean + rm -rf *.elf *.bin *.dump + +ifneq ($(MAKECMDGOALS),clean) + -include .depend +endif diff --git a/tests/unittest/vx_malloc/Makefile b/tests/unittest/vx_malloc/Makefile index 2d604620..2036fcde 100644 --- a/tests/unittest/vx_malloc/Makefile +++ b/tests/unittest/vx_malloc/Makefile @@ -1,34 +1,5 @@ -VORTEX_RT_PATH ?= $(realpath ../../../runtime) - -CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic -Wfatal-errors - -CXXFLAGS += -I$(VORTEX_RT_PATH)/common - -# Debugigng -ifdef DEBUG - CXXFLAGS += -g -O0 -else - CXXFLAGS += -O2 -DNDEBUG -endif - PROJECT = vx_malloc SRCS = main.cpp -all: $(PROJECT) - -$(PROJECT): $(SRCS) - $(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ - -run: - ./$(PROJECT) - -clean: - rm -rf $(PROJECT) *.o .depend - -clean-all: clean - rm -rf *.elf *.bin *.dump - -ifneq ($(MAKECMDGOALS),clean) - -include .depend -endif \ No newline at end of file +include ../common.mk From a08d3ebd4250a7d52ee7741712dfb612c163be2f Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 12 Nov 2023 23:40:59 -0800 Subject: [PATCH 02/57] minor update --- hw/rtl/afu/xrt/VX_afu_wrap.sv | 2 +- hw/rtl/{fpu => core}/VX_fpu_unit.sv | 0 hw/rtl/core/VX_muldiv_unit.sv | 5 + hw/rtl/core/VX_scoreboard.sv | 3 + hw/rtl/fpu/VX_fpu_cvt.sv | 206 ++++++++++------------------ hw/rtl/fpu/VX_fpu_rounding.sv | 1 - 6 files changed, 81 insertions(+), 136 deletions(-) rename hw/rtl/{fpu => core}/VX_fpu_unit.sv (100%) diff --git a/hw/rtl/afu/xrt/VX_afu_wrap.sv b/hw/rtl/afu/xrt/VX_afu_wrap.sv index 3c4b3947..2abbbe43 100644 --- a/hw/rtl/afu/xrt/VX_afu_wrap.sv +++ b/hw/rtl/afu/xrt/VX_afu_wrap.sv @@ -262,7 +262,7 @@ module VX_afu_wrap #( .m_axi_awready (m_axi_mem_awready_a), .m_axi_awaddr (m_axi_mem_awaddr_w), .m_axi_awid (m_axi_mem_awid_a), - `UNUSED_PIN (m_axi_awlen), + .m_axi_awlen (m_axi_mem_awlen_a), `UNUSED_PIN (m_axi_awsize), `UNUSED_PIN (m_axi_awburst), `UNUSED_PIN (m_axi_awlock), diff --git a/hw/rtl/fpu/VX_fpu_unit.sv b/hw/rtl/core/VX_fpu_unit.sv similarity index 100% rename from hw/rtl/fpu/VX_fpu_unit.sv rename to hw/rtl/core/VX_fpu_unit.sv diff --git a/hw/rtl/core/VX_muldiv_unit.sv b/hw/rtl/core/VX_muldiv_unit.sv index f3c730d4..141cdb55 100644 --- a/hw/rtl/core/VX_muldiv_unit.sv +++ b/hw/rtl/core/VX_muldiv_unit.sv @@ -220,8 +220,13 @@ module VX_muldiv_unit #( wire [NUM_LANES-1:0][`XLEN-1:0] div_in2; for (genvar i = 0; i < NUM_LANES; ++i) begin + `ifdef XLEN_64 assign div_in1[i] = is_alu_w ? {{(`XLEN-32){is_signed_op && execute_if.data.rs1_data[i][31]}}, execute_if.data.rs1_data[i][31:0]}: execute_if.data.rs1_data[i]; assign div_in2[i] = is_alu_w ? {{(`XLEN-32){is_signed_op && execute_if.data.rs2_data[i][31]}}, execute_if.data.rs2_data[i][31:0]}: execute_if.data.rs2_data[i]; + `else + assign div_in1[i] = execute_if.data.rs1_data[i]; + assign div_in2[i] = execute_if.data.rs2_data[i]; + `endif end `ifdef IDIV_DPI diff --git a/hw/rtl/core/VX_scoreboard.sv b/hw/rtl/core/VX_scoreboard.sv index ee5ae2ec..90a58134 100644 --- a/hw/rtl/core/VX_scoreboard.sv +++ b/hw/rtl/core/VX_scoreboard.sv @@ -107,6 +107,7 @@ module VX_scoreboard import VX_gpu_pkg::*; #( .ready_out (scoreboard_if[i].ready) ); + `ifdef SIMULATION reg [31:0] timeout_ctr; always @(posedge clk) begin @@ -134,6 +135,8 @@ module VX_scoreboard import VX_gpu_pkg::*; #( `RUNTIME_ASSERT(~writeback_fire || inuse_regs[writeback_if[i].data.wis][writeback_if[i].data.rd] != 0, ("%t: *** core%0d: invalid writeback register: wid=%0d, PC=0x%0h, tmask=%b, rd=%0d (#%0d)", $time, CORE_ID, wis_to_wid(writeback_if[i].data.wis, i), writeback_if[i].data.PC, writeback_if[i].data.tmask, writeback_if[i].data.rd, writeback_if[i].data.uuid)); + `endif + end endmodule diff --git a/hw/rtl/fpu/VX_fpu_cvt.sv b/hw/rtl/fpu/VX_fpu_cvt.sv index 34b2ed28..d668539b 100644 --- a/hw/rtl/fpu/VX_fpu_cvt.sv +++ b/hw/rtl/fpu/VX_fpu_cvt.sv @@ -52,30 +52,27 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( localparam MAN_BITS = 23; localparam EXP_BITS = 8; - localparam EXP_BIAS = 2**(EXP_BITS-1)-1; - - localparam logic [EXP_BITS-1:0] QNAN_EXPONENT = 2**EXP_BITS-1; - localparam logic [MAN_BITS-1:0] QNAN_MANTISSA = 2**(MAN_BITS-1); + localparam EXP_BIAS = 2**(EXP_BITS-1)-1; // Use 32-bit integer - localparam MAX_INT_WIDTH = 32; + localparam INT_WIDTH = 32; // The internal mantissa includes normal bit or an entire integer - localparam INT_MAN_WIDTH = `MAX(MAN_BITS + 1, MAX_INT_WIDTH); + localparam INT_MAN_WIDTH = `MAX(MAN_BITS + 1, INT_WIDTH); // The lower 2p+3 bits of the internal FMA result will be needed for leading-zero detection localparam LZC_RESULT_WIDTH = `CLOG2(INT_MAN_WIDTH); // The internal exponent must be able to represent the smallest denormal input value as signed // or the number of bits in an integer - localparam INT_EXP_WIDTH = `MAX(`CLOG2(MAX_INT_WIDTH), `MAX(EXP_BITS, `CLOG2(EXP_BIAS + MAN_BITS))) + 1; + localparam INT_EXP_WIDTH = `MAX(`CLOG2(INT_WIDTH), `MAX(EXP_BITS, `CLOG2(EXP_BIAS + MAN_BITS))) + 1; // shift amount for denormalization localparam SHAMT_BITS = `CLOG2(INT_MAN_WIDTH+1); localparam FMT_SHIFT_COMPENSATION = INT_MAN_WIDTH - 1 - MAN_BITS; localparam NUM_FP_STICKY = 2 * INT_MAN_WIDTH - MAN_BITS - 1; // removed mantissa, 1. and R - localparam NUM_INT_STICKY = 2 * INT_MAN_WIDTH - MAX_INT_WIDTH; // removed int and R + localparam NUM_INT_STICKY = 2 * INT_MAN_WIDTH - INT_WIDTH; // removed int and R // Input processing @@ -86,8 +83,8 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( .EXP_BITS (EXP_BITS), .MAN_BITS (MAN_BITS) ) fp_class ( - .exp_i (dataa[i][30:23]), - .man_i (dataa[i][22:0]), + .exp_i (dataa[i][INT_WIDTH-2:MAN_BITS]), + .man_i (dataa[i][MAN_BITS-1:0]), .clss_o (fclass[i]) ); end @@ -97,15 +94,13 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( wire [NUM_LANES-1:0] input_sign; for (genvar i = 0; i < NUM_LANES; ++i) begin - wire [INT_MAN_WIDTH-1:0] int_mantissa; - wire [INT_MAN_WIDTH-1:0] fmt_mantissa; - wire fmt_sign = dataa[i][31]; - wire int_sign = dataa[i][31] && is_signed; - assign int_mantissa = int_sign ? (-dataa[i]) : dataa[i]; - assign fmt_mantissa = INT_MAN_WIDTH'({fclass[i].is_normal, dataa[i][MAN_BITS-1:0]}); + wire i2f_sign = dataa[i][INT_WIDTH-1]; + wire f2i_sign = dataa[i][INT_WIDTH-1] && is_signed; + wire [INT_MAN_WIDTH-1:0] f2i_mantissa = f2i_sign ? (-dataa[i]) : dataa[i]; + wire [INT_MAN_WIDTH-1:0] i2f_mantissa = INT_MAN_WIDTH'({fclass[i].is_normal, dataa[i][MAN_BITS-1:0]}); assign input_exp[i] = {1'b0, dataa[i][MAN_BITS +: EXP_BITS]} + INT_EXP_WIDTH'({1'b0, fclass[i].is_subnormal}); - assign input_mant[i] = is_itof ? int_mantissa : fmt_mantissa; - assign input_sign[i] = is_itof ? int_sign : fmt_sign; + assign input_mant[i] = is_itof ? f2i_mantissa : i2f_mantissa; + assign input_sign[i] = is_itof ? f2i_sign : i2f_sign; end // Pipeline stage0 @@ -159,9 +154,9 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( assign input_mant_n_s0[i] = encoded_mant_s0[i] << renorm_shamt_s0[i]; // Unbias exponent and compensate for shift - wire [INT_EXP_WIDTH-1:0] fp_input_exp_s0 = fmt_exponent_s0[i] + INT_EXP_WIDTH'(FMT_SHIFT_COMPENSATION - EXP_BIAS) - INT_EXP_WIDTH'({1'b0, renorm_shamt_s0[i]}); - wire [INT_EXP_WIDTH-1:0] int_input_exp_s0 = INT_EXP_WIDTH'(INT_MAN_WIDTH-1) - INT_EXP_WIDTH'({1'b0, renorm_shamt_s0[i]}); - assign input_exp_n_s0[i] = is_itof_s0 ? int_input_exp_s0 : fp_input_exp_s0; + wire [INT_EXP_WIDTH-1:0] i2f_input_exp_s0 = fmt_exponent_s0[i] + INT_EXP_WIDTH'(FMT_SHIFT_COMPENSATION - EXP_BIAS) - INT_EXP_WIDTH'({1'b0, renorm_shamt_s0[i]}); + wire [INT_EXP_WIDTH-1:0] f2i_input_exp_s0 = INT_EXP_WIDTH'(INT_MAN_WIDTH-1) - INT_EXP_WIDTH'({1'b0, renorm_shamt_s0[i]}); + assign input_exp_n_s0[i] = is_itof_s0 ? f2i_input_exp_s0 : i2f_input_exp_s0; end // Pipeline stage1 @@ -193,51 +188,32 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( wire [NUM_LANES-1:0][2*INT_MAN_WIDTH:0] destination_mant_s1; wire [NUM_LANES-1:0][INT_EXP_WIDTH-1:0] final_exp_s1; - wire [NUM_LANES-1:0] of_before_round_s1; + wire [NUM_LANES-1:0] of_before_round_s1; - for (genvar i = 0; i < NUM_LANES; ++i) begin - reg [2*INT_MAN_WIDTH:0] preshift_mant_s1; // mantissa before final shift - reg [SHAMT_BITS-1:0] denorm_shamt_s1; // shift amount for denormalization - reg [INT_EXP_WIDTH-1:0] final_exp_tmp_s1; // after eventual adjustments - reg of_before_round_tmp_s1; + for (genvar i = 0; i < NUM_LANES; ++i) begin + reg [SHAMT_BITS-1:0] denorm_shamt_s1; // shift amount for denormalization + reg of_before_round_tmp_s1; always @(*) begin - final_exp_tmp_s1 = input_exp_s1[i] + INT_EXP_WIDTH'(EXP_BIAS); // take exponent as is, only look at lower bits - preshift_mant_s1 = {input_mant_s1[i], 33'b0}; denorm_shamt_s1 = '0; of_before_round_tmp_s1 = 1'b0; - if (is_itof_s1) begin - if ($signed(input_exp_s1[i]) >= INT_EXP_WIDTH'($signed(2**EXP_BITS-1-EXP_BIAS))) begin - // Overflow or infinities (for proper rounding) - final_exp_tmp_s1 = (2**EXP_BITS-2); // largest normal value - preshift_mant_s1 = ~0; // largest normal value and RS bits set - of_before_round_tmp_s1 = 1'b1; - end else if ($signed(input_exp_s1[i]) < INT_EXP_WIDTH'($signed(-MAN_BITS-EXP_BIAS))) begin - // Limit the shift to retain sticky bits - final_exp_tmp_s1 = '0; // denormal result - denorm_shamt_s1 = (2 + MAN_BITS); // to sticky - end else if ($signed(input_exp_s1[i]) < INT_EXP_WIDTH'($signed(1-EXP_BIAS))) begin - // Denormalize underflowing values - final_exp_tmp_s1 = '0; // denormal result - denorm_shamt_s1 = SHAMT_BITS'(1-EXP_BIAS) - SHAMT_BITS'(input_exp_s1[i]); // adjust right shifting - end - end else begin - if ($signed(input_exp_s1[i]) >= $signed(INT_EXP_WIDTH'(MAX_INT_WIDTH-1) + INT_EXP_WIDTH'(unsigned_s1))) begin - // overflow: when converting to unsigned the range is larger by one + if (!is_itof_s1) begin + if ($signed(input_exp_s1[i]) >= $signed(INT_EXP_WIDTH'(INT_WIDTH-1) + INT_EXP_WIDTH'(unsigned_s1))) begin + // overflow of_before_round_tmp_s1 = 1'b1; end else if ($signed(input_exp_s1[i]) < INT_EXP_WIDTH'($signed(-1))) begin // underflow - denorm_shamt_s1 = MAX_INT_WIDTH+1; // all bits go to the sticky + denorm_shamt_s1 = INT_WIDTH+1; // all bits go to the sticky end else begin // By default right shift mantissa to be an integer - denorm_shamt_s1 = SHAMT_BITS'(MAX_INT_WIDTH-1) - SHAMT_BITS'(input_exp_s1[i]); + denorm_shamt_s1 = SHAMT_BITS'(INT_WIDTH-1) - SHAMT_BITS'(input_exp_s1[i]); end end end - assign destination_mant_s1[i] = preshift_mant_s1 >> denorm_shamt_s1; - assign final_exp_s1[i] = final_exp_tmp_s1; + assign destination_mant_s1[i] = {input_mant_s1[i], 33'b0} >> denorm_shamt_s1; + assign final_exp_s1[i] = input_exp_s1[i] + INT_EXP_WIDTH'(EXP_BIAS); assign of_before_round_s1[i] = of_before_round_tmp_s1; end @@ -267,33 +243,33 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( .data_out ({valid_in_s2, lane_mask_s2, tag_in_s2, is_itof_s2, unsigned_s2, rnd_mode_s2, fclass_s2, mant_is_zero_s2, input_sign_s2, destination_mant_s2, final_exp_s2, of_before_round_s2}) ); - wire [NUM_LANES-1:0] rounded_sign_s2; - wire [NUM_LANES-1:0][31:0] rounded_abs_s2; // absolute value of result after rounding - wire [NUM_LANES-1:0] int_round_has_sticky_s2; - wire [NUM_LANES-1:0] fp_round_has_sticky_s2; + wire [NUM_LANES-1:0] rounded_sign_s2; + wire [NUM_LANES-1:0][INT_WIDTH-1:0] rounded_abs_s2; // absolute value of result after rounding + wire [NUM_LANES-1:0] f2i_round_has_sticky_s2; + wire [NUM_LANES-1:0] i2f_round_has_sticky_s2; // Rouding and classification for (genvar i = 0; i < NUM_LANES; ++i) begin - wire [MAN_BITS-1:0] final_mant_s2; // mantissa after adjustments - wire [MAX_INT_WIDTH-1:0] final_int_s2; // integer shifted in position - wire [1:0] round_sticky_bits_s2; - wire [31:0] fmt_pre_round_abs_s2; - wire [31:0] pre_round_abs_s2; - wire [1:0] int_round_sticky_bits_s2, fp_round_sticky_bits_s2; + wire [MAN_BITS-1:0] final_mant_s2; // mantissa after adjustments + wire [INT_WIDTH-1:0] final_int_s2; // integer shifted in position + wire [1:0] round_sticky_bits_s2; + wire [INT_WIDTH-1:0] fmt_pre_round_abs_s2; + wire [INT_WIDTH-1:0] pre_round_abs_s2; + wire [1:0] f2i_round_sticky_bits_s2, i2f_round_sticky_bits_s2; // Extract final mantissa and round bit, discard the normal bit (for FP) - assign {final_mant_s2, fp_round_sticky_bits_s2[1]} = destination_mant_s2[i][2*INT_MAN_WIDTH-1 : 2*INT_MAN_WIDTH-1 - (MAN_BITS+1) + 1]; - assign {final_int_s2, int_round_sticky_bits_s2[1]} = destination_mant_s2[i][2*INT_MAN_WIDTH : 2*INT_MAN_WIDTH - (MAX_INT_WIDTH+1) + 1]; + assign {final_mant_s2, i2f_round_sticky_bits_s2[1]} = destination_mant_s2[i][2*INT_MAN_WIDTH-1 : 2*INT_MAN_WIDTH-1 - (MAN_BITS+1) + 1]; + assign {final_int_s2, f2i_round_sticky_bits_s2[1]} = destination_mant_s2[i][2*INT_MAN_WIDTH : 2*INT_MAN_WIDTH - (INT_WIDTH+1) + 1]; // Collapse sticky bits - assign fp_round_sticky_bits_s2[0] = (| destination_mant_s2[i][NUM_FP_STICKY-1:0]); - assign int_round_sticky_bits_s2[0] = (| destination_mant_s2[i][NUM_INT_STICKY-1:0]); - assign fp_round_has_sticky_s2[i] = (| fp_round_sticky_bits_s2); - assign int_round_has_sticky_s2[i] = (| int_round_sticky_bits_s2); + assign i2f_round_sticky_bits_s2[0] = (| destination_mant_s2[i][NUM_FP_STICKY-1:0]); + assign f2i_round_sticky_bits_s2[0] = (| destination_mant_s2[i][NUM_INT_STICKY-1:0]); + assign i2f_round_has_sticky_s2[i] = (| i2f_round_sticky_bits_s2); + assign f2i_round_has_sticky_s2[i] = (| f2i_round_sticky_bits_s2); // select RS bits for destination operation - assign round_sticky_bits_s2 = is_itof_s2 ? fp_round_sticky_bits_s2 : int_round_sticky_bits_s2; + assign round_sticky_bits_s2 = is_itof_s2 ? i2f_round_sticky_bits_s2 : f2i_round_sticky_bits_s2; // Pack exponent and mantissa into proper rounding form assign fmt_pre_round_abs_s2 = {1'b0, final_exp_s2[i][EXP_BITS-1:0], final_mant_s2[MAN_BITS-1:0]}; @@ -327,10 +303,10 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( wire [NUM_LANES-1:0] mant_is_zero_s3; wire [NUM_LANES-1:0] input_sign_s3; wire [NUM_LANES-1:0] rounded_sign_s3; - wire [NUM_LANES-1:0][31:0] rounded_abs_s3; + wire [NUM_LANES-1:0][INT_WIDTH-1:0] rounded_abs_s3; wire [NUM_LANES-1:0] of_before_round_s3; - wire [NUM_LANES-1:0] int_round_has_sticky_s3; - wire [NUM_LANES-1:0] fp_round_has_sticky_s3; + wire [NUM_LANES-1:0] f2i_round_has_sticky_s3; + wire [NUM_LANES-1:0] i2f_round_has_sticky_s3; VX_pipe_register #( .DATAW (1 + NUM_LANES + TAGW + 1 + 1 + NUM_LANES * ($bits(fclass_t) + 1 + 1 + 32 + 1 + 1 + 1 + 1)), @@ -339,105 +315,68 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( .clk (clk), .reset (reset), .enable (~stall), - .data_in ({valid_in_s2, lane_mask_s2, tag_in_s2, is_itof_s2, unsigned_s2, fclass_s2, mant_is_zero_s2, input_sign_s2, rounded_abs_s2, rounded_sign_s2, of_before_round_s2, int_round_has_sticky_s2, fp_round_has_sticky_s2}), - .data_out ({valid_in_s3, lane_mask_s3, tag_in_s3, is_itof_s3, unsigned_s3, fclass_s3, mant_is_zero_s3, input_sign_s3, rounded_abs_s3, rounded_sign_s3, of_before_round_s3, int_round_has_sticky_s3, fp_round_has_sticky_s3}) + .data_in ({valid_in_s2, lane_mask_s2, tag_in_s2, is_itof_s2, unsigned_s2, fclass_s2, mant_is_zero_s2, input_sign_s2, rounded_abs_s2, rounded_sign_s2, of_before_round_s2, f2i_round_has_sticky_s2, i2f_round_has_sticky_s2}), + .data_out ({valid_in_s3, lane_mask_s3, tag_in_s3, is_itof_s3, unsigned_s3, fclass_s3, mant_is_zero_s3, input_sign_s3, rounded_abs_s3, rounded_sign_s3, of_before_round_s3, f2i_round_has_sticky_s3, i2f_round_has_sticky_s3}) ); - wire [NUM_LANES-1:0] of_after_round_s3; - wire [NUM_LANES-1:0] uf_after_round_s3; - wire [NUM_LANES-1:0][31:0] fmt_result_s3; - wire [NUM_LANES-1:0][31:0] rounded_int_res_s3; // after possible inversion + wire [NUM_LANES-1:0][INT_WIDTH-1:0] fmt_result_s3; + wire [NUM_LANES-1:0][INT_WIDTH-1:0] rounded_int_res_s3; // after possible inversion wire [NUM_LANES-1:0] rounded_int_res_zero_s3; // after rounding for (genvar i = 0; i < NUM_LANES; ++i) begin // Assemble regular result, nan box short ones. Int zeroes need to be detected - assign fmt_result_s3[i] = (is_itof_s3 & mant_is_zero_s3[i]) ? 0 : {rounded_sign_s3[i], rounded_abs_s3[i][EXP_BITS+MAN_BITS-1:0]}; - - // Classification after rounding select by destination format - assign uf_after_round_s3[i] = (rounded_abs_s3[i][EXP_BITS+MAN_BITS-1:MAN_BITS] == 0); // denormal - assign of_after_round_s3[i] = (rounded_abs_s3[i][EXP_BITS+MAN_BITS-1:MAN_BITS] == ~0); // inf exp. + assign fmt_result_s3[i] = mant_is_zero_s3[i] ? 0 : {rounded_sign_s3[i], rounded_abs_s3[i][EXP_BITS+MAN_BITS-1:0]}; // Negative integer result needs to be brought into two's complement assign rounded_int_res_s3[i] = rounded_sign_s3[i] ? (-rounded_abs_s3[i]) : rounded_abs_s3[i]; assign rounded_int_res_zero_s3[i] = (rounded_int_res_s3[i] == 0); end - // FP Special case handling + // F2I Special case handling - wire [NUM_LANES-1:0][31:0] fp_special_result_s3; - fflags_t [NUM_LANES-1:0] fp_special_status_s3; - wire [NUM_LANES-1:0] fp_result_is_special_s3; - - for (genvar i = 0; i < NUM_LANES; ++i) begin - // Detect special case from source format, I2F casts don't produce a special result - assign fp_result_is_special_s3[i] = ~is_itof_s3 & (fclass_s3[i].is_zero | fclass_s3[i].is_nan); - - // Signalling input NaNs raise invalid flag, otherwise no flags set - assign fp_special_status_s3[i] = fclass_s3[i].is_signaling ? {1'b1, 4'h0} : 5'h0; // invalid operation - - // Assemble result according to destination format - assign fp_special_result_s3[i] = fclass_s3[i].is_zero ? (32'(input_sign_s3) << 31) // signed zero - : {1'b0, QNAN_EXPONENT, QNAN_MANTISSA}; // qNaN - end - - // INT Special case handling - - reg [NUM_LANES-1:0][31:0] int_special_result_s3; - fflags_t [NUM_LANES-1:0] int_special_status_s3; - wire [NUM_LANES-1:0] int_result_is_special_s3; + reg [NUM_LANES-1:0][INT_WIDTH-1:0] f2i_special_result_s3; + fflags_t [NUM_LANES-1:0] f2i_special_status_s3; + wire [NUM_LANES-1:0] f2i_result_is_special_s3; for (genvar i = 0; i < NUM_LANES; ++i) begin // Assemble result according to destination format always @(*) begin if (input_sign_s3[i] && !fclass_s3[i].is_nan) begin - int_special_result_s3[i][30:0] = '0; // alone yields 2**(31)-1 - int_special_result_s3[i][31] = ~unsigned_s3; // for unsigned casts yields 2**31 + f2i_special_result_s3[i][INT_WIDTH-2:0] = '0; // alone yields 2**(31)-1 + f2i_special_result_s3[i][INT_WIDTH-1] = ~unsigned_s3; // for unsigned casts yields 2**31 end else begin - int_special_result_s3[i][30:0] = 2**(31) - 1; // alone yields 2**(31)-1 - int_special_result_s3[i][31] = unsigned_s3; // for unsigned casts yields 2**31 + f2i_special_result_s3[i][INT_WIDTH-2:0] = 2**(INT_WIDTH-1) - 1; // alone yields 2**(31)-1 + f2i_special_result_s3[i][INT_WIDTH-1] = unsigned_s3; // for unsigned casts yields 2**31 end end // Detect special case from source format (inf, nan, overflow, nan-boxing or negative unsigned) - assign int_result_is_special_s3[i] = fclass_s3[i].is_nan + assign f2i_result_is_special_s3[i] = fclass_s3[i].is_nan | fclass_s3[i].is_inf | of_before_round_s3[i] | (input_sign_s3[i] & unsigned_s3 & ~rounded_int_res_zero_s3[i]); // All integer special cases are invalid - assign int_special_status_s3[i] = {1'b1, 4'h0}; + assign f2i_special_status_s3[i] = {1'b1, 4'h0}; end // Result selection and Output handshake fflags_t [NUM_LANES-1:0] tmp_fflags_s3; - wire [NUM_LANES-1:0][31:0] tmp_result_s3; + wire [NUM_LANES-1:0][INT_WIDTH-1:0] tmp_result_s3; - for (genvar i = 0; i < NUM_LANES; ++i) begin - fflags_t fp_regular_status_s3, int_regular_status_s3; - fflags_t fp_status_s3, int_status_s3; - wire [31:0] fp_result_s3, int_result_s3; + for (genvar i = 0; i < NUM_LANES; ++i) begin + fflags_t i2f_regular_status_s3 = i2f_round_has_sticky_s3[i] ? 5'h1 : 5'h0; + fflags_t f2i_regular_status_s3 = f2i_round_has_sticky_s3[i] ? 5'h1 : 5'h0; - wire inexact_s3 = is_itof_s3 ? fp_round_has_sticky_s3[i] // overflow is invalid in i2f; - : (fp_round_has_sticky_s3[i] || (~fclass_s3[i].is_inf && (of_before_round_s3[i] || of_after_round_s3[i]))); - - assign fp_regular_status_s3.NV = is_itof_s3 & (of_before_round_s3[i] | of_after_round_s3[i]); // overflow is invalid for I2F casts - assign fp_regular_status_s3.DZ = 1'b0; // no divisions - assign fp_regular_status_s3.OF = ~is_itof_s3 & (~fclass_s3[i].is_inf & (of_before_round_s3[i] | of_after_round_s3[i])); // inf casts no OF - assign fp_regular_status_s3.UF = uf_after_round_s3[i] & inexact_s3; - assign fp_regular_status_s3.NX = inexact_s3; + fflags_t i2f_status_s3 = i2f_regular_status_s3; + fflags_t f2i_status_s3 = f2i_result_is_special_s3[i] ? f2i_special_status_s3[i] : f2i_regular_status_s3; - assign int_regular_status_s3 = int_round_has_sticky_s3[i] ? {4'h0, 1'b1} : 5'h0; + wire [INT_WIDTH-1:0] i2f_result_s3 = fmt_result_s3[i]; + wire [INT_WIDTH-1:0] f2i_result_s3 = f2i_result_is_special_s3[i] ? f2i_special_result_s3[i] : rounded_int_res_s3[i]; - assign fp_result_s3 = fp_result_is_special_s3[i] ? fp_special_result_s3[i] : fmt_result_s3[i]; - assign int_result_s3 = int_result_is_special_s3[i] ? int_special_result_s3[i] : rounded_int_res_s3[i]; - - assign fp_status_s3 = fp_result_is_special_s3[i] ? fp_special_status_s3[i] : fp_regular_status_s3; - assign int_status_s3 = int_result_is_special_s3[i] ? int_special_status_s3[i] : int_regular_status_s3; - - // Select output depending on special case detection - assign tmp_result_s3[i] = is_itof_s3 ? fp_result_s3 : int_result_s3; - assign tmp_fflags_s3[i] = is_itof_s3 ? fp_status_s3 : int_status_s3; + assign tmp_result_s3[i] = is_itof_s3 ? i2f_result_s3 : f2i_result_s3; + assign tmp_fflags_s3[i] = is_itof_s3 ? i2f_status_s3 : f2i_status_s3; end assign stall = ~ready_out && valid_out; @@ -457,7 +396,6 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( ); assign ready_in = ~stall; - assign has_fflags = 1'b1; endmodule diff --git a/hw/rtl/fpu/VX_fpu_rounding.sv b/hw/rtl/fpu/VX_fpu_rounding.sv index 5168fada..877b4eb6 100644 --- a/hw/rtl/fpu/VX_fpu_rounding.sv +++ b/hw/rtl/fpu/VX_fpu_rounding.sv @@ -54,7 +54,6 @@ module VX_fpu_rounding #( 2'b01: round_up = 1'b0; // < ulp/2 away, round down 2'b10: round_up = abs_value_i[0]; // = ulp/2 away, round towards even result 2'b11: round_up = 1'b1; // > ulp/2 away, round up - default: round_up = 1'bx; endcase `INST_FRM_RTZ: round_up = 1'b0; // always round down `INST_FRM_RDN: round_up = (| round_sticky_bits_i) & sign_i; // to 0 if +, away if - From b274b8cc217683ec9834b5393bd75406da395f6b Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 13 Nov 2023 00:23:15 -0800 Subject: [PATCH 03/57] minor updates --- hw/rtl/core/VX_operands.sv | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/hw/rtl/core/VX_operands.sv b/hw/rtl/core/VX_operands.sv index 3d2c570c..3ff5df46 100644 --- a/hw/rtl/core/VX_operands.sv +++ b/hw/rtl/core/VX_operands.sv @@ -38,9 +38,12 @@ module VX_operands import VX_gpu_pkg::*; #( reg [`NR_BITS-1:0] gpr_rd_rid, gpr_rd_rid_n; reg [ISSUE_WIS_W-1:0] gpr_rd_wis, gpr_rd_wis_n; - reg [ISSUE_RATIO-1:0][`NUM_THREADS-1:0][`XLEN-1:0] cache_data, cache_data_n; - reg [ISSUE_RATIO-1:0][`NR_BITS-1:0] cache_reg, cache_reg_n; - reg [ISSUE_RATIO-1:0][`NUM_THREADS-1:0] cache_tmask, cache_tmask_n; + reg [`NUM_THREADS-1:0][`XLEN-1:0] cache_data [ISSUE_RATIO-1:0]; + reg [`NUM_THREADS-1:0][`XLEN-1:0] cache_data_n [ISSUE_RATIO-1:0]; + reg [`NR_BITS-1:0] cache_reg [ISSUE_RATIO-1:0]; + reg [`NR_BITS-1:0] cache_reg_n [ISSUE_RATIO-1:0]; + reg [`NUM_THREADS-1:0] cache_tmask [ISSUE_RATIO-1:0]; + reg [`NUM_THREADS-1:0] cache_tmask_n [ISSUE_RATIO-1:0]; reg [ISSUE_RATIO-1:0] cache_eop, cache_eop_n; reg [`NUM_THREADS-1:0][`XLEN-1:0] rs1_data, rs1_data_n; @@ -160,11 +163,8 @@ module VX_operands import VX_gpu_pkg::*; #( end cache_reg_n[writeback_if[i].data.wis] = writeback_if[i].data.rd; cache_eop_n[writeback_if[i].data.wis] = writeback_if[i].data.eop; - if (writeback_if[i].data.sop) begin - cache_tmask_n[writeback_if[i].data.wis] = writeback_if[i].data.tmask; - end else begin - cache_tmask_n[writeback_if[i].data.wis] |= writeback_if[i].data.tmask; - end + cache_tmask_n[writeback_if[i].data.wis] = writeback_if[i].data.sop ? writeback_if[i].data.tmask : + (cache_tmask_n[writeback_if[i].data.wis] | writeback_if[i].data.tmask); end end end @@ -175,7 +175,6 @@ module VX_operands import VX_gpu_pkg::*; #( gpr_rd_rid <= '0; gpr_rd_wis <= '0; cache_eop <= {ISSUE_RATIO{1'b1}}; - cache_reg <= '0; data_ready <= 0; end else begin state <= state_n; From ecf546bc4ab08e1f6f982275bc8fd15c52ce7b64 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 13 Nov 2023 20:00:39 -0800 Subject: [PATCH 04/57] minor update --- hw/rtl/fpu/VX_fpu_cvt.sv | 131 ++++++++++++++++++--------------------- 1 file changed, 60 insertions(+), 71 deletions(-) diff --git a/hw/rtl/fpu/VX_fpu_cvt.sv b/hw/rtl/fpu/VX_fpu_cvt.sv index d668539b..e12e51ad 100644 --- a/hw/rtl/fpu/VX_fpu_cvt.sv +++ b/hw/rtl/fpu/VX_fpu_cvt.sv @@ -67,9 +67,6 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( // or the number of bits in an integer localparam INT_EXP_WIDTH = `MAX(`CLOG2(INT_WIDTH), `MAX(EXP_BITS, `CLOG2(EXP_BIAS + MAN_BITS))) + 1; - // shift amount for denormalization - localparam SHAMT_BITS = `CLOG2(INT_MAN_WIDTH+1); - localparam FMT_SHIFT_COMPENSATION = INT_MAN_WIDTH - 1 - MAN_BITS; localparam NUM_FP_STICKY = 2 * INT_MAN_WIDTH - MAN_BITS - 1; // removed mantissa, 1. and R localparam NUM_INT_STICKY = 2 * INT_MAN_WIDTH - INT_WIDTH; // removed int and R @@ -105,14 +102,14 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( // Pipeline stage0 - wire valid_in_s0; - wire [NUM_LANES-1:0] lane_mask_s0; - wire [TAGW-1:0] tag_in_s0; - wire is_itof_s0; - wire unsigned_s0; - wire [2:0] rnd_mode_s0; + wire valid_in_s0; + wire [NUM_LANES-1:0] lane_mask_s0; + wire [TAGW-1:0] tag_in_s0; + wire is_itof_s0; + wire is_signed_s0; + wire [2:0] rnd_mode_s0; fclass_t [NUM_LANES-1:0] fclass_s0; - wire [NUM_LANES-1:0] input_sign_s0; + wire [NUM_LANES-1:0] input_sign_s0; wire [NUM_LANES-1:0][INT_EXP_WIDTH-1:0] fmt_exponent_s0; wire [NUM_LANES-1:0][INT_MAN_WIDTH-1:0] encoded_mant_s0; @@ -125,8 +122,8 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( .clk (clk), .reset (reset), .enable (~stall), - .data_in ({valid_in, lane_mask, tag_in, is_itof, !is_signed, frm, fclass, input_sign, input_exp, input_mant}), - .data_out ({valid_in_s0, lane_mask_s0, tag_in_s0, is_itof_s0, unsigned_s0, rnd_mode_s0, fclass_s0, input_sign_s0, fmt_exponent_s0, encoded_mant_s0}) + .data_in ({valid_in, lane_mask, tag_in, is_itof, is_signed, frm, fclass, input_sign, input_exp, input_mant}), + .data_out ({valid_in_s0, lane_mask_s0, tag_in_s0, is_itof_s0, is_signed_s0, rnd_mode_s0, fclass_s0, input_sign_s0, fmt_exponent_s0, encoded_mant_s0}) ); // Normalization @@ -161,15 +158,15 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( // Pipeline stage1 - wire valid_in_s1; - wire [NUM_LANES-1:0] lane_mask_s1; - wire [TAGW-1:0] tag_in_s1; - wire is_itof_s1; - wire unsigned_s1; - wire [2:0] rnd_mode_s1; + wire valid_in_s1; + wire [NUM_LANES-1:0] lane_mask_s1; + wire [TAGW-1:0] tag_in_s1; + wire is_itof_s1; + wire is_signed_s1; + wire [2:0] rnd_mode_s1; fclass_t [NUM_LANES-1:0] fclass_s1; - wire [NUM_LANES-1:0] input_sign_s1; - wire [NUM_LANES-1:0] mant_is_zero_s1; + wire [NUM_LANES-1:0] input_sign_s1; + wire [NUM_LANES-1:0] mant_is_zero_s1; wire [NUM_LANES-1:0][INT_MAN_WIDTH-1:0] input_mant_s1; wire [NUM_LANES-1:0][INT_EXP_WIDTH-1:0] input_exp_s1; @@ -180,8 +177,8 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( .clk (clk), .reset (reset), .enable (~stall), - .data_in ({valid_in_s0, lane_mask_s0, tag_in_s0, is_itof_s0, unsigned_s0, rnd_mode_s0, fclass_s0, input_sign_s0, mant_is_zero_s0, input_mant_n_s0, input_exp_n_s0}), - .data_out ({valid_in_s1, lane_mask_s1, tag_in_s1, is_itof_s1, unsigned_s1, rnd_mode_s1, fclass_s1, input_sign_s1, mant_is_zero_s1, input_mant_s1, input_exp_s1}) + .data_in ({valid_in_s0, lane_mask_s0, tag_in_s0, is_itof_s0, is_signed_s0, rnd_mode_s0, fclass_s0, input_sign_s0, mant_is_zero_s0, input_mant_n_s0, input_exp_n_s0}), + .data_out ({valid_in_s1, lane_mask_s1, tag_in_s1, is_itof_s1, is_signed_s1, rnd_mode_s1, fclass_s1, input_sign_s1, mant_is_zero_s1, input_mant_s1, input_exp_s1}) ); // Perform adjustments to mantissa and exponent @@ -190,47 +187,39 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( wire [NUM_LANES-1:0][INT_EXP_WIDTH-1:0] final_exp_s1; wire [NUM_LANES-1:0] of_before_round_s1; - for (genvar i = 0; i < NUM_LANES; ++i) begin - reg [SHAMT_BITS-1:0] denorm_shamt_s1; // shift amount for denormalization - reg of_before_round_tmp_s1; - + for (genvar i = 0; i < NUM_LANES; ++i) begin + wire [INT_EXP_WIDTH-1:0] denorm_shamt = INT_EXP_WIDTH'(INT_WIDTH-1) - input_exp_s1[i]; + wire overflow = ($signed(denorm_shamt) <= -$signed(INT_EXP_WIDTH'(!is_signed_s1))); + wire underflow = ($signed(input_exp_s1[i]) < INT_EXP_WIDTH'($signed(-1))); + reg [INT_EXP_WIDTH-1:0] denorm_shamt_q; always @(*) begin - denorm_shamt_s1 = '0; - of_before_round_tmp_s1 = 1'b0; - - if (!is_itof_s1) begin - if ($signed(input_exp_s1[i]) >= $signed(INT_EXP_WIDTH'(INT_WIDTH-1) + INT_EXP_WIDTH'(unsigned_s1))) begin - // overflow - of_before_round_tmp_s1 = 1'b1; - end else if ($signed(input_exp_s1[i]) < INT_EXP_WIDTH'($signed(-1))) begin - // underflow - denorm_shamt_s1 = INT_WIDTH+1; // all bits go to the sticky - end else begin - // By default right shift mantissa to be an integer - denorm_shamt_s1 = SHAMT_BITS'(INT_WIDTH-1) - SHAMT_BITS'(input_exp_s1[i]); - end + if (overflow) begin + denorm_shamt_q = '0; + end else if (underflow) begin + denorm_shamt_q = INT_WIDTH+1; + end else begin + denorm_shamt_q = denorm_shamt; end end - - assign destination_mant_s1[i] = {input_mant_s1[i], 33'b0} >> denorm_shamt_s1; + assign destination_mant_s1[i] = is_itof_s1 ? {input_mant_s1[i], 33'b0} : ({input_mant_s1[i], 33'b0} >> denorm_shamt_q); assign final_exp_s1[i] = input_exp_s1[i] + INT_EXP_WIDTH'(EXP_BIAS); - assign of_before_round_s1[i] = of_before_round_tmp_s1; + assign of_before_round_s1[i] = overflow; end // Pipeline stage2 - wire valid_in_s2; - wire [NUM_LANES-1:0] lane_mask_s2; - wire [TAGW-1:0] tag_in_s2; - wire is_itof_s2; - wire unsigned_s2; - wire [2:0] rnd_mode_s2; + wire valid_in_s2; + wire [NUM_LANES-1:0] lane_mask_s2; + wire [TAGW-1:0] tag_in_s2; + wire is_itof_s2; + wire is_signed_s2; + wire [2:0] rnd_mode_s2; fclass_t [NUM_LANES-1:0] fclass_s2; - wire [NUM_LANES-1:0] mant_is_zero_s2; - wire [NUM_LANES-1:0] input_sign_s2; + wire [NUM_LANES-1:0] mant_is_zero_s2; + wire [NUM_LANES-1:0] input_sign_s2; wire [NUM_LANES-1:0][2*INT_MAN_WIDTH:0] destination_mant_s2; wire [NUM_LANES-1:0][INT_EXP_WIDTH-1:0] final_exp_s2; - wire [NUM_LANES-1:0] of_before_round_s2; + wire [NUM_LANES-1:0] of_before_round_s2; VX_pipe_register #( .DATAW (1 + NUM_LANES + TAGW + 1 + 1 + `INST_FRM_BITS + NUM_LANES * ($bits(fclass_t) + 1 + 1 + (2*INT_MAN_WIDTH+1) + INT_EXP_WIDTH + 1)), @@ -239,24 +228,24 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( .clk (clk), .reset (reset), .enable (~stall), - .data_in ({valid_in_s1, lane_mask_s1, tag_in_s1, is_itof_s1, unsigned_s1, rnd_mode_s1, fclass_s1, mant_is_zero_s1, input_sign_s1, destination_mant_s1, final_exp_s1, of_before_round_s1}), - .data_out ({valid_in_s2, lane_mask_s2, tag_in_s2, is_itof_s2, unsigned_s2, rnd_mode_s2, fclass_s2, mant_is_zero_s2, input_sign_s2, destination_mant_s2, final_exp_s2, of_before_round_s2}) + .data_in ({valid_in_s1, lane_mask_s1, tag_in_s1, is_itof_s1, is_signed_s1, rnd_mode_s1, fclass_s1, mant_is_zero_s1, input_sign_s1, destination_mant_s1, final_exp_s1, of_before_round_s1}), + .data_out ({valid_in_s2, lane_mask_s2, tag_in_s2, is_itof_s2, is_signed_s2, rnd_mode_s2, fclass_s2, mant_is_zero_s2, input_sign_s2, destination_mant_s2, final_exp_s2, of_before_round_s2}) ); - wire [NUM_LANES-1:0] rounded_sign_s2; + wire [NUM_LANES-1:0] rounded_sign_s2; wire [NUM_LANES-1:0][INT_WIDTH-1:0] rounded_abs_s2; // absolute value of result after rounding - wire [NUM_LANES-1:0] f2i_round_has_sticky_s2; - wire [NUM_LANES-1:0] i2f_round_has_sticky_s2; + wire [NUM_LANES-1:0] f2i_round_has_sticky_s2; + wire [NUM_LANES-1:0] i2f_round_has_sticky_s2; // Rouding and classification for (genvar i = 0; i < NUM_LANES; ++i) begin - wire [MAN_BITS-1:0] final_mant_s2; // mantissa after adjustments - wire [INT_WIDTH-1:0] final_int_s2; // integer shifted in position - wire [1:0] round_sticky_bits_s2; - wire [INT_WIDTH-1:0] fmt_pre_round_abs_s2; - wire [INT_WIDTH-1:0] pre_round_abs_s2; - wire [1:0] f2i_round_sticky_bits_s2, i2f_round_sticky_bits_s2; + wire [MAN_BITS-1:0] final_mant_s2; // mantissa after adjustments + wire [INT_WIDTH-1:0] final_int_s2; // integer shifted in position + wire [1:0] round_sticky_bits_s2; + wire [INT_WIDTH-1:0] fmt_pre_round_abs_s2; + wire [INT_WIDTH-1:0] pre_round_abs_s2; + wire [1:0] f2i_round_sticky_bits_s2, i2f_round_sticky_bits_s2; // Extract final mantissa and round bit, discard the normal bit (for FP) assign {final_mant_s2, i2f_round_sticky_bits_s2[1]} = destination_mant_s2[i][2*INT_MAN_WIDTH-1 : 2*INT_MAN_WIDTH-1 - (MAN_BITS+1) + 1]; @@ -298,7 +287,7 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( wire [NUM_LANES-1:0] lane_mask_s3; wire [TAGW-1:0] tag_in_s3; wire is_itof_s3; - wire unsigned_s3; + wire is_signed_s3; fclass_t [NUM_LANES-1:0] fclass_s3; wire [NUM_LANES-1:0] mant_is_zero_s3; wire [NUM_LANES-1:0] input_sign_s3; @@ -315,8 +304,8 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( .clk (clk), .reset (reset), .enable (~stall), - .data_in ({valid_in_s2, lane_mask_s2, tag_in_s2, is_itof_s2, unsigned_s2, fclass_s2, mant_is_zero_s2, input_sign_s2, rounded_abs_s2, rounded_sign_s2, of_before_round_s2, f2i_round_has_sticky_s2, i2f_round_has_sticky_s2}), - .data_out ({valid_in_s3, lane_mask_s3, tag_in_s3, is_itof_s3, unsigned_s3, fclass_s3, mant_is_zero_s3, input_sign_s3, rounded_abs_s3, rounded_sign_s3, of_before_round_s3, f2i_round_has_sticky_s3, i2f_round_has_sticky_s3}) + .data_in ({valid_in_s2, lane_mask_s2, tag_in_s2, is_itof_s2, is_signed_s2, fclass_s2, mant_is_zero_s2, input_sign_s2, rounded_abs_s2, rounded_sign_s2, of_before_round_s2, f2i_round_has_sticky_s2, i2f_round_has_sticky_s2}), + .data_out ({valid_in_s3, lane_mask_s3, tag_in_s3, is_itof_s3, is_signed_s3, fclass_s3, mant_is_zero_s3, input_sign_s3, rounded_abs_s3, rounded_sign_s3, of_before_round_s3, f2i_round_has_sticky_s3, i2f_round_has_sticky_s3}) ); wire [NUM_LANES-1:0][INT_WIDTH-1:0] fmt_result_s3; @@ -335,18 +324,18 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( // F2I Special case handling reg [NUM_LANES-1:0][INT_WIDTH-1:0] f2i_special_result_s3; - fflags_t [NUM_LANES-1:0] f2i_special_status_s3; - wire [NUM_LANES-1:0] f2i_result_is_special_s3; + fflags_t [NUM_LANES-1:0] f2i_special_status_s3; + wire [NUM_LANES-1:0] f2i_result_is_special_s3; for (genvar i = 0; i < NUM_LANES; ++i) begin // Assemble result according to destination format always @(*) begin if (input_sign_s3[i] && !fclass_s3[i].is_nan) begin f2i_special_result_s3[i][INT_WIDTH-2:0] = '0; // alone yields 2**(31)-1 - f2i_special_result_s3[i][INT_WIDTH-1] = ~unsigned_s3; // for unsigned casts yields 2**31 + f2i_special_result_s3[i][INT_WIDTH-1] = is_signed_s3; // for unsigned casts yields 2**31 end else begin f2i_special_result_s3[i][INT_WIDTH-2:0] = 2**(INT_WIDTH-1) - 1; // alone yields 2**(31)-1 - f2i_special_result_s3[i][INT_WIDTH-1] = unsigned_s3; // for unsigned casts yields 2**31 + f2i_special_result_s3[i][INT_WIDTH-1] = ~is_signed_s3; // for unsigned casts yields 2**31 end end @@ -354,7 +343,7 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( assign f2i_result_is_special_s3[i] = fclass_s3[i].is_nan | fclass_s3[i].is_inf | of_before_round_s3[i] - | (input_sign_s3[i] & unsigned_s3 & ~rounded_int_res_zero_s3[i]); + | (input_sign_s3[i] & ~is_signed_s3 & ~rounded_int_res_zero_s3[i]); // All integer special cases are invalid assign f2i_special_status_s3[i] = {1'b1, 4'h0}; From 4e7a536918638e09e9f4707685a91fa5e2bb451d Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 14 Nov 2023 05:37:46 -0800 Subject: [PATCH 05/57] adding tensor regression test. --- kernel/src/vx_spawn.c | 9 +- tests/opencl/matmul/kernel.cl | 54 +++--- tests/opencl/matmul/main.cc | 4 +- tests/regression/Makefile | 6 + tests/regression/basic/main.cpp | 7 +- tests/regression/demo/common.h | 6 +- tests/regression/demo/kernel.cpp | 8 +- tests/regression/demo/main.cpp | 94 ++++++++--- tests/regression/diverge/main.cpp | 7 +- tests/regression/fence/main.cpp | 7 +- tests/regression/io_addr/main.cpp | 11 +- tests/regression/mstress/main.cpp | 11 +- tests/regression/no_mf_ext/main.cpp | 11 +- tests/regression/no_smem/main.cpp | 9 +- tests/regression/printf/main.cpp | 11 +- tests/regression/sort/common.h | 8 +- tests/regression/sort/kernel.cpp | 8 +- tests/regression/sort/main.cpp | 19 +-- tests/regression/tensor/Makefile | 9 + tests/regression/tensor/common.h | 18 ++ tests/regression/tensor/kernel.cpp | 41 +++++ tests/regression/tensor/main.cpp | 249 ++++++++++++++++++++++++++++ 22 files changed, 474 insertions(+), 133 deletions(-) create mode 100644 tests/regression/tensor/Makefile create mode 100644 tests/regression/tensor/common.h create mode 100644 tests/regression/tensor/kernel.cpp create mode 100644 tests/regression/tensor/main.cpp diff --git a/kernel/src/vx_spawn.c b/kernel/src/vx_spawn.c index 14773707..fd8258e1 100644 --- a/kernel/src/vx_spawn.c +++ b/kernel/src/vx_spawn.c @@ -51,9 +51,8 @@ inline char is_log2(int x) { return ((x & (x-1)) == 0); } -inline int fast_log2(int x) { - float f = x; - return (*(int*)(&f)>>23) - 127; +inline int log2_fast(int x) { + return 31 - __builtin_clz (x); } static void __attribute__ ((noinline)) spawn_tasks_all_stub() { @@ -286,8 +285,8 @@ void vx_spawn_kernel(context_t * ctx, vx_spawn_kernel_cb callback, void * arg) { // fast path handling char isXYpow2 = is_log2(XY); - char log2XY = fast_log2(XY); - char log2X = fast_log2(X); + char log2XY = log2_fast(XY); + char log2X = log2_fast(X); wspawn_kernel_args_t wspawn_args = { ctx, callback, arg, core_id * tasks_per_core, fW, rW, isXYpow2, log2XY, log2X diff --git a/tests/opencl/matmul/kernel.cl b/tests/opencl/matmul/kernel.cl index ea9b2156..a0ef2d81 100644 --- a/tests/opencl/matmul/kernel.cl +++ b/tests/opencl/matmul/kernel.cl @@ -5,35 +5,37 @@ __kernel void matmul(__global float *A, __local float *localA, __local float *localB) { - int row = get_global_id(1); - int col = get_global_id(0); + int globalRow = get_global_id(1); + int globalCol = get_global_id(0); int localRow = get_local_id(1); int localCol = get_local_id(0); int localSize = get_local_size(0); // assuming square local size float sum = 0.0f; - // Loop over all blocks of both matrices - for (int k = 0; k < N; k += localSize) { - // Load block of matrix A to local memory - localA[localRow * localSize + localCol] = A[row * N + k + localCol]; + // Load initial blocks of A and B into local memory + int k = 0; + localA[localRow * localSize + localCol] = A[globalRow * N + k + localCol]; + localB[localRow * localSize + localCol] = B[(k + localRow) * N + globalCol]; - // Load block of matrix B to local memory, adjusting for column-major access - localB[localRow * localSize + localCol] = B[(k + localRow) * N + col]; - - // Synchronize to make sure the tiles are loaded + // Iterate over blocks + for (k = 0; k < N; k += 16) { + // Ensure the initial block is loaded barrier(CLK_LOCAL_MEM_FENCE); - // Multiply the two matrix blocks and accumulate result - for (int j = 0; j < localSize; j++) { + // Compute multiplication for this block + for (int j = 0; j < 16; j++) { sum += localA[localRow * localSize + j] * localB[j * localSize + localCol]; } - // Synchronize before loading the next block - barrier(CLK_LOCAL_MEM_FENCE); + // Load the next block of matrix A into local memory + if (k + 16 < N) { + localA[localRow * localSize + localCol] = A[globalRow * N + k + 16 + localCol]; + localB[localRow * localSize + localCol] = B[(k + 16 + localRow) * N + globalCol]; + } } - C[row * N + col] = sum; + C[globalRow * N + globalCol] = sum; } /*__kernel void matmul(__global float *A, __global float *B, __global float *C, const unsigned int N) @@ -49,15 +51,14 @@ __kernel void matmul(__global float *A, float sum = 0.0f; + // Load initial blocks of A and B into local memory + int k = 0; + localA[localRow][localCol] = A[globalRow * N + k + localCol]; + localB[localRow][localCol] = B[(k + localRow) * N + globalCol]; + // Iterate over blocks - for (int k = 0; k < N; k += 16) { - // Load a block of matrix A into local memory - localA[localRow][localCol] = A[globalRow * N + k + localCol]; - - // Load a block of matrix B into local memory - localB[localRow][localCol] = B[(k + localRow) * N + globalCol]; - - // Ensure the entire block is loaded + for (k = 0; k < N; k += 16) { + // Ensure the initial block is loaded barrier(CLK_LOCAL_MEM_FENCE); // Compute multiplication for this block @@ -65,8 +66,11 @@ __kernel void matmul(__global float *A, sum += localA[localRow][j] * localB[j][localCol]; } - // Wait until all threads have computed before loading the next block - barrier(CLK_LOCAL_MEM_FENCE); + // Load the next block of matrix A into local memory + if (k + 16 < N) { + localA[localRow][localCol] = A[globalRow * N + k + 16 + localCol]; + localB[localRow][localCol] = B[(k + 16 + localRow) * N + globalCol]; + } } C[globalRow * N + globalCol] = sum; diff --git a/tests/opencl/matmul/main.cc b/tests/opencl/matmul/main.cc index 8e20a3ef..f7714dd7 100644 --- a/tests/opencl/matmul/main.cc +++ b/tests/opencl/matmul/main.cc @@ -184,8 +184,8 @@ int main (int argc, char **argv) { CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&b_memobj)); CL_CHECK(clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *)&c_memobj)); CL_CHECK(clSetKernelArg(kernel, 3, sizeof(uint32_t), &size)); - CL_CHECK(clSetKernelArg(kernel, 4, local_size[0]*local_size[1]*sizeof(float), NULL)); - CL_CHECK(clSetKernelArg(kernel, 5, local_size[0]*local_size[1]*sizeof(float), NULL)); + //CL_CHECK(clSetKernelArg(kernel, 4, local_size[0]*local_size[1]*sizeof(float), NULL)); + //CL_CHECK(clSetKernelArg(kernel, 5, local_size[0]*local_size[1]*sizeof(float), NULL)); // Allocate memories for input arrays and output arrays. std::vector h_a(size * size); diff --git a/tests/regression/Makefile b/tests/regression/Makefile index 5ba29d57..89fa25af 100644 --- a/tests/regression/Makefile +++ b/tests/regression/Makefile @@ -10,6 +10,7 @@ all: $(MAKE) -C fence $(MAKE) -C no_mf_ext $(MAKE) -C no_smem + $(MAKE) -C tensor run-simx: $(MAKE) -C basic run-simx @@ -23,6 +24,7 @@ run-simx: $(MAKE) -C fence run-simx $(MAKE) -C no_mf_ext run-simx $(MAKE) -C no_smem run-simx + $(MAKE) -C tensor run-simx run-rtlsim: $(MAKE) -C basic run-rtlsim @@ -36,6 +38,7 @@ run-rtlsim: $(MAKE) -C fence run-rtlsim $(MAKE) -C no_mf_ext run-rtlsim $(MAKE) -C no_smem run-rtlsim + $(MAKE) -C tensor run-rtlsim run-opae: $(MAKE) -C basic run-opae @@ -49,6 +52,7 @@ run-opae: $(MAKE) -C fence run-opae $(MAKE) -C no_mf_ext run-opae $(MAKE) -C no_smem run-opae + $(MAKE) -C tensor run-opae clean: $(MAKE) -C basic clean @@ -62,6 +66,7 @@ clean: $(MAKE) -C fence clean $(MAKE) -C no_mf_ext clean $(MAKE) -C no_smem clean + $(MAKE) -C tensor clean clean-all: $(MAKE) -C basic clean-all @@ -75,3 +80,4 @@ clean-all: $(MAKE) -C fence clean-all $(MAKE) -C no_mf_ext clean-all $(MAKE) -C no_smem clean-all + $(MAKE) -C tensor clean-all diff --git a/tests/regression/basic/main.cpp b/tests/regression/basic/main.cpp index e79387b5..0f6f3bde 100755 --- a/tests/regression/basic/main.cpp +++ b/tests/regression/basic/main.cpp @@ -262,11 +262,8 @@ int main(int argc, char *argv[]) { // upload kernel argument std::cout << "upload kernel argument" << std::endl; - { - auto buf_ptr = (void*)staging_buf.data(); - memcpy(buf_ptr, &kernel_arg, sizeof(kernel_arg_t)); - RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); - } + memcpy(staging_buf.data(), &kernel_arg, sizeof(kernel_arg_t)); + RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); std::cout << "run kernel test" << std::endl; RT_CHECK(run_kernel_test(kernel_arg, buf_size, num_points)); diff --git a/tests/regression/demo/common.h b/tests/regression/demo/common.h index e18b65a0..941983ac 100644 --- a/tests/regression/demo/common.h +++ b/tests/regression/demo/common.h @@ -3,6 +3,10 @@ #define KERNEL_ARG_DEV_MEM_ADDR 0x7ffff000 +#ifndef TYPE +#define TYPE float +#endif + typedef struct { uint32_t num_tasks; uint32_t task_size; @@ -11,4 +15,4 @@ typedef struct { uint64_t dst_addr; } kernel_arg_t; -#endif \ No newline at end of file +#endif diff --git a/tests/regression/demo/kernel.cpp b/tests/regression/demo/kernel.cpp index deb56169..49945440 100644 --- a/tests/regression/demo/kernel.cpp +++ b/tests/regression/demo/kernel.cpp @@ -4,11 +4,11 @@ #include "common.h" void kernel_body(int task_id, kernel_arg_t* __UNIFORM__ arg) { - uint32_t count = arg->task_size; - int32_t* src0_ptr = (int32_t*)arg->src0_addr; - int32_t* src1_ptr = (int32_t*)arg->src1_addr; - int32_t* dst_ptr = (int32_t*)arg->dst_addr; + auto src0_ptr = reinterpret_cast(arg->src0_addr); + auto src1_ptr = reinterpret_cast(arg->src1_addr); + auto dst_ptr = reinterpret_cast(arg->dst_addr); + uint32_t count = arg->task_size; uint32_t offset = task_id * count; for (uint32_t i = 0; i < count; ++i) { diff --git a/tests/regression/demo/main.cpp b/tests/regression/demo/main.cpp index dfe33377..63556a5f 100644 --- a/tests/regression/demo/main.cpp +++ b/tests/regression/demo/main.cpp @@ -5,6 +5,8 @@ #include #include "common.h" +#define FLOAT_ULP 6 + #define RT_CHECK(_expr) \ do { \ int _ret = _expr; \ @@ -17,10 +19,52 @@ /////////////////////////////////////////////////////////////////////////////// +union Float_t { + float f; + int i; + struct { + uint32_t man : 23; + uint32_t exp : 8; + uint32_t sign : 1; + } parts; +}; + +template +class Comparator {}; + +template <> +class Comparator { +public: + static const char* type_str() { + return "integer"; + } + static bool compare(int a, int b) { + return a == b; + } +}; + +template <> +class Comparator { +public: + static const char* type_str() { + return "float"; + } + static bool compare(float a, float b) { + Float_t fa{a}, fb{b}; + auto d = std::abs(fa.i - fb.i); + if (d > FLOAT_ULP) { + std::cout << "*** almost_equal_ulp: a=" << a << ", b=" << b << ", ulp=" << d << ", ia=" << std::hex << fa.i << ", ib=" << fb.i << std::endl; + return false; + } + return true; + } +}; + const char* kernel_file = "kernel.bin"; -uint32_t count = 0; +uint32_t count = 16; vx_device_h device = nullptr; +std::vector source_data; std::vector staging_buf; kernel_arg_t kernel_arg = {}; @@ -79,11 +123,11 @@ int run_test(const kernel_arg_t& kernel_arg, std::cout << "verify result" << std::endl; { int errors = 0; - auto buf_ptr = (int32_t*)staging_buf.data(); + auto buf_ptr = (TYPE*)staging_buf.data(); for (uint32_t i = 0; i < num_points; ++i) { - int ref = i + i; - int cur = buf_ptr[i]; - if (cur != ref) { + auto ref = source_data[2 * i + 0] + source_data[2 * i + 1]; + auto cur = buf_ptr[i]; + if (!Comparator::compare(cur, ref)) { std::cout << "error at result #" << std::dec << i << std::hex << ": actual 0x" << cur << ", expected 0x" << ref << std::endl; ++errors; @@ -103,9 +147,7 @@ int main(int argc, char *argv[]) { // parse command arguments parse_args(argc, argv); - if (count == 0) { - count = 1; - } + std::srand(50); // open device connection std::cout << "open device connection" << std::endl; @@ -118,8 +160,9 @@ int main(int argc, char *argv[]) { uint32_t num_tasks = num_cores * num_warps * num_threads; uint32_t num_points = count * num_tasks; - uint32_t buf_size = num_points * sizeof(int32_t); + uint32_t buf_size = num_points * sizeof(TYPE); + std::cout << "data type: " << Comparator::type_str() << std::endl; std::cout << "number of points: " << num_points << std::endl; std::cout << "buffer size: " << buf_size << " bytes" << std::endl; @@ -147,18 +190,22 @@ int main(int argc, char *argv[]) { // upload kernel argument std::cout << "upload kernel argument" << std::endl; - { - auto buf_ptr = (int*)staging_buf.data(); - memcpy(buf_ptr, &kernel_arg, sizeof(kernel_arg_t)); - RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); + memcpy(staging_buf.data(), &kernel_arg, sizeof(kernel_arg_t)); + RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); + + // generate source data + source_data.resize(2 * num_points); + for (uint32_t i = 0; i < source_data.size(); ++i) { + auto r = static_cast(std::rand()) / RAND_MAX; + source_data[i] = static_cast(r * 2 * num_points); } // upload source buffer0 { std::cout << "upload source buffer0" << std::endl; - auto buf_ptr = (int32_t*)staging_buf.data(); + auto buf_ptr = (TYPE*)staging_buf.data(); for (uint32_t i = 0; i < num_points; ++i) { - buf_ptr[i] = i-1; + buf_ptr[i] = source_data[2 * i + 0]; } RT_CHECK(vx_copy_to_dev(device, kernel_arg.src0_addr, staging_buf.data(), buf_size)); } @@ -166,23 +213,18 @@ int main(int argc, char *argv[]) { // upload source buffer1 { std::cout << "upload source buffer1" << std::endl; - auto buf_ptr = (int32_t*)staging_buf.data(); + auto buf_ptr = (TYPE*)staging_buf.data(); for (uint32_t i = 0; i < num_points; ++i) { - buf_ptr[i] = i+1; + buf_ptr[i] = source_data[2 * i + 1]; } RT_CHECK(vx_copy_to_dev(device, kernel_arg.src1_addr, staging_buf.data(), buf_size)); } // clear destination buffer - { - std::cout << "clear destination buffer" << std::endl; - auto buf_ptr = (int32_t*)staging_buf.data(); - for (uint32_t i = 0; i < num_points; ++i) { - buf_ptr[i] = 0xdeadbeef; - } - RT_CHECK(vx_copy_to_dev(device, kernel_arg.dst_addr, staging_buf.data(), buf_size)); - } - + std::cout << "clear destination buffer" << std::endl; + memset(staging_buf.data(), 0, num_points * sizeof(TYPE)); + RT_CHECK(vx_copy_to_dev(device, kernel_arg.dst_addr, staging_buf.data(), buf_size)); + // run tests std::cout << "run tests" << std::endl; RT_CHECK(run_test(kernel_arg, buf_size, num_points)); diff --git a/tests/regression/diverge/main.cpp b/tests/regression/diverge/main.cpp index 742f2419..d5de1bc1 100644 --- a/tests/regression/diverge/main.cpp +++ b/tests/regression/diverge/main.cpp @@ -233,11 +233,8 @@ int main(int argc, char *argv[]) { // upload kernel argument std::cout << "upload kernel argument" << std::endl; - { - auto buf_ptr = (int*)staging_buf.data(); - memcpy(buf_ptr, &kernel_arg, sizeof(kernel_arg_t)); - RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); - } + memcpy(staging_buf.data(), &kernel_arg, sizeof(kernel_arg_t)); + RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); // upload source buffer { diff --git a/tests/regression/fence/main.cpp b/tests/regression/fence/main.cpp index d9f2920f..c9225edc 100644 --- a/tests/regression/fence/main.cpp +++ b/tests/regression/fence/main.cpp @@ -147,11 +147,8 @@ int main(int argc, char *argv[]) { // upload kernel argument std::cout << "upload kernel argument" << std::endl; - { - auto buf_ptr = (int*)staging_buf.data(); - memcpy(buf_ptr, &kernel_arg, sizeof(kernel_arg_t)); - RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); - } + memcpy(staging_buf.data(), &kernel_arg, sizeof(kernel_arg_t)); + RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); // upload source buffer0 { diff --git a/tests/regression/io_addr/main.cpp b/tests/regression/io_addr/main.cpp index d4c74aad..0272bfbc 100644 --- a/tests/regression/io_addr/main.cpp +++ b/tests/regression/io_addr/main.cpp @@ -190,13 +190,10 @@ int main(int argc, char *argv[]) { staging_buf.resize(staging_buf_size); // upload kernel argument - { - std::cout << "upload kernel argument" << std::endl; - auto buf_ptr = (int*)staging_buf.data(); - memcpy(buf_ptr, &kernel_arg, sizeof(kernel_arg_t)); - RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); - } - + std::cout << "upload kernel argument" << std::endl; + memcpy(staging_buf.data(), &kernel_arg, sizeof(kernel_arg_t)); + RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); + // upload test address data { std::cout << "upload test address data" << std::endl; diff --git a/tests/regression/mstress/main.cpp b/tests/regression/mstress/main.cpp index ecc867bc..9b527126 100644 --- a/tests/regression/mstress/main.cpp +++ b/tests/regression/mstress/main.cpp @@ -236,13 +236,10 @@ int main(int argc, char *argv[]) { staging_buf.resize(staging_buf_size); // upload kernel argument - { - std::cout << "upload kernel argument" << std::endl; - auto buf_ptr = (int*)staging_buf.data(); - memcpy(buf_ptr, &kernel_arg, sizeof(kernel_arg_t)); - RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); - } - + std::cout << "upload kernel argument" << std::endl; + memcpy(staging_buf.data(), &kernel_arg, sizeof(kernel_arg_t)); + RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); + // upload source buffer0 { std::cout << "upload address buffer" << std::endl; diff --git a/tests/regression/no_mf_ext/main.cpp b/tests/regression/no_mf_ext/main.cpp index 7632dad1..e711b99a 100644 --- a/tests/regression/no_mf_ext/main.cpp +++ b/tests/regression/no_mf_ext/main.cpp @@ -136,13 +136,10 @@ int main(int argc, char *argv[]) { staging_buf.resize(alloc_size); // upload kernel argument - { - std::cout << "upload kernel argument" << std::endl; - auto buf_ptr = (int*)staging_buf.data(); - memcpy(buf_ptr, &kernel_arg, sizeof(kernel_arg_t)); - RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); - } - + std::cout << "upload kernel argument" << std::endl; + memcpy(staging_buf.data(), &kernel_arg, sizeof(kernel_arg_t)); + RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); + // upload source buffer0 { std::cout << "upload source buffer" << std::endl; diff --git a/tests/regression/no_smem/main.cpp b/tests/regression/no_smem/main.cpp index 8bb00389..53db0465 100644 --- a/tests/regression/no_smem/main.cpp +++ b/tests/regression/no_smem/main.cpp @@ -135,13 +135,10 @@ int main(int argc, char *argv[]) { uint32_t alloc_size = std::max(buf_size, sizeof(kernel_arg_t)); staging_buf.resize(alloc_size); - // upload kernel argument + // upload kernel argument std::cout << "upload kernel argument" << std::endl; - { - auto buf_ptr = (int*)staging_buf.data(); - memcpy(buf_ptr, &kernel_arg, sizeof(kernel_arg_t)); - RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); - } + memcpy(staging_buf.data(), &kernel_arg, sizeof(kernel_arg_t)); + RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); // upload source buffer0 { diff --git a/tests/regression/printf/main.cpp b/tests/regression/printf/main.cpp index 4b13faad..3a920294 100644 --- a/tests/regression/printf/main.cpp +++ b/tests/regression/printf/main.cpp @@ -110,13 +110,10 @@ int main(int argc, char *argv[]) { staging_buf.resize(alloc_size); // upload kernel argument - { - std::cout << "upload kernel argument" << std::endl; - auto buf_ptr = (void*)staging_buf.data(); - memcpy(buf_ptr, &kernel_arg, sizeof(kernel_arg_t)); - RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); - } - + std::cout << "upload kernel argument" << std::endl; + memcpy(staging_buf.data(), &kernel_arg, sizeof(kernel_arg_t)); + RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); + // upload source buffer0 { std::cout << "upload source buffer" << std::endl; diff --git a/tests/regression/sort/common.h b/tests/regression/sort/common.h index 492e03c6..92ceeb91 100644 --- a/tests/regression/sort/common.h +++ b/tests/regression/sort/common.h @@ -3,11 +3,7 @@ #define KERNEL_ARG_DEV_MEM_ADDR 0x7ffff000 -#define FP_ENABLE - -#ifdef FP_ENABLE -#define TYPE float -#else +#ifndef TYPE #define TYPE int #endif @@ -17,4 +13,4 @@ typedef struct { uint64_t dst_addr; } kernel_arg_t; -#endif \ No newline at end of file +#endif diff --git a/tests/regression/sort/kernel.cpp b/tests/regression/sort/kernel.cpp index 0cd7074e..2e9d3453 100644 --- a/tests/regression/sort/kernel.cpp +++ b/tests/regression/sort/kernel.cpp @@ -5,14 +5,14 @@ void kernel_body(int task_id, kernel_arg_t* __UNIFORM__ arg) { uint32_t num_points = arg->num_points; - TYPE* src_ptr = (TYPE*)arg->src_addr; - TYPE* dst_ptr = (TYPE*)arg->dst_addr; + auto src_ptr = (TYPE*)arg->src_addr; + auto dst_ptr = (TYPE*)arg->dst_addr; - TYPE ref_value = src_ptr[task_id]; + auto ref_value = src_ptr[task_id]; uint32_t pos = 0; for (uint32_t i = 0; i < num_points; ++i) { - TYPE cur_value = src_ptr[i]; + auto cur_value = src_ptr[i]; pos += (cur_value < ref_value) || ((cur_value == ref_value) && (i < task_id)); } dst_ptr[pos] = ref_value; diff --git a/tests/regression/sort/main.cpp b/tests/regression/sort/main.cpp index 59796f73..38d5d4d4 100644 --- a/tests/regression/sort/main.cpp +++ b/tests/regression/sort/main.cpp @@ -66,8 +66,8 @@ void gen_input_data(uint32_t num_points) { src_data.resize(num_points); for (uint32_t i = 0; i < num_points; ++i) { - float r = static_cast(std::rand()) / RAND_MAX; - TYPE value = r * num_points; + auto r = static_cast(std::rand()) / RAND_MAX; + auto value = static_cast(r * num_points); src_data[i] = value; std::cout << std::dec << i << ": value=" << value << std::endl; } @@ -172,19 +172,16 @@ int main(int argc, char *argv[]) { { std::cout << "allocate staging buffer" << std::endl; uint32_t staging_buf_size = std::max(src_buf_size, - std::max(dst_buf_size, - sizeof(kernel_arg_t))); + std::max(dst_buf_size, + sizeof(kernel_arg_t))); staging_buf.resize(staging_buf_size); } // upload kernel argument - { - std::cout << "upload kernel argument" << std::endl; - auto buf_ptr = staging_buf.data(); - memcpy(buf_ptr, &kernel_arg, sizeof(kernel_arg_t)); - RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); - } - + std::cout << "upload kernel argument" << std::endl; + memcpy(staging_buf.data(), &kernel_arg, sizeof(kernel_arg_t)); + RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); + // upload source buffer { std::cout << "upload source buffer" << std::endl; diff --git a/tests/regression/tensor/Makefile b/tests/regression/tensor/Makefile new file mode 100644 index 00000000..790664dc --- /dev/null +++ b/tests/regression/tensor/Makefile @@ -0,0 +1,9 @@ +PROJECT = tensor + +SRCS = main.cpp + +VX_SRCS = kernel.cpp + +OPTS ?= -s16 + +include ../common.mk \ No newline at end of file diff --git a/tests/regression/tensor/common.h b/tests/regression/tensor/common.h new file mode 100644 index 00000000..75cfc340 --- /dev/null +++ b/tests/regression/tensor/common.h @@ -0,0 +1,18 @@ +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#define KERNEL_ARG_DEV_MEM_ADDR 0x7ffff000 + +#ifndef TYPE +#define TYPE float +#endif + +typedef struct { + uint32_t num_tasks; + uint32_t size; + uint64_t A_addr; + uint64_t B_addr; + uint64_t C_addr; +} kernel_arg_t; + +#endif diff --git a/tests/regression/tensor/kernel.cpp b/tests/regression/tensor/kernel.cpp new file mode 100644 index 00000000..5cf0851c --- /dev/null +++ b/tests/regression/tensor/kernel.cpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include "common.h" + +inline char is_log2(uint32_t x) { + return ((x & (x-1)) == 0); +} + +inline uint32_t log2_fast(uint32_t x) { + return 31 - __builtin_clz (x); +} + +void kernel_body(uint32_t task_id, kernel_arg_t* __UNIFORM__ arg) { + auto size = arg->size; + auto A = reinterpret_cast(arg->A_addr); + auto B = reinterpret_cast(arg->B_addr); + auto C = reinterpret_cast(arg->C_addr); + + uint32_t row, col; + if (is_log2(size)) { + uint32_t log_size = log2_fast(size); + row = task_id >> log_size; + col = task_id & (size-1); + } else { + row = task_id / size; + col = task_id % size; + } + + TYPE sum (0); + for (int e = 0; e < size; ++e) { + sum += A[row * size + e] * B[e * size + col]; + } + C[row * size + col] = sum; +} + +int main() { + kernel_arg_t* arg = (kernel_arg_t*)KERNEL_ARG_DEV_MEM_ADDR; + vx_spawn_tasks(arg->num_tasks, (vx_spawn_tasks_cb)kernel_body, arg); + return 0; +} diff --git a/tests/regression/tensor/main.cpp b/tests/regression/tensor/main.cpp new file mode 100644 index 00000000..d93f3177 --- /dev/null +++ b/tests/regression/tensor/main.cpp @@ -0,0 +1,249 @@ +#include +#include +#include +#include +#include +#include "common.h" + +#define FLOAT_ULP 6 + +#define RT_CHECK(_expr) \ + do { \ + int _ret = _expr; \ + if (0 == _ret) \ + break; \ + printf("Error: '%s' returned %d!\n", #_expr, (int)_ret); \ + cleanup(); \ + exit(-1); \ + } while (false) + +/////////////////////////////////////////////////////////////////////////////// + +union Float_t { + float f; + int i; + struct { + uint32_t man : 23; + uint32_t exp : 8; + uint32_t sign : 1; + } parts; +}; + +template +class Comparator {}; + +template <> +class Comparator { +public: + static const char* type_str() { + return "integer"; + } + static bool compare(int a, int b) { + return a == b; + } +}; + +template <> +class Comparator { +public: + static const char* type_str() { + return "float"; + } + static bool compare(float a, float b) { + Float_t fa{a}, fb{b}; + auto d = std::abs(fa.i - fb.i); + if (d > FLOAT_ULP) { + std::cout << "*** almost_equal_ulp: a=" << a << ", b=" << b << ", ulp=" << d << ", ia=" << std::hex << fa.i << ", ib=" << fb.i << std::endl; + return false; + } + return true; + } +}; + +static void cpuMatrixMultiply(TYPE* out, const TYPE* A, const TYPE* B, uint32_t width, uint32_t height) { + for (uint32_t row = 0; row < height; ++row) { + for (uint32_t col = 0; col < width; ++col) { + TYPE sum(0); + for (uint32_t e = 0; e < width; ++e) { + sum += A[row * width + e] * B[e * width + col]; + } + out[row * width + col] = sum; + } + } +} + +const char* kernel_file = "kernel.bin"; +uint32_t size = 16; + +vx_device_h device = nullptr; +std::vector staging_buf; +kernel_arg_t kernel_arg = {}; + +static void show_usage() { + std::cout << "Vortex Test." << std::endl; + std::cout << "Usage: [-k: kernel] [-s size] [-h: help]" << std::endl; +} + +static void parse_args(int argc, char **argv) { + int c; + while ((c = getopt(argc, argv, "s:k:h?")) != -1) { + switch (c) { + case 's': + size = atoi(optarg); + break; + case 'k': + kernel_file = optarg; + break; + case 'h': + case '?': { + show_usage(); + exit(0); + } break; + default: + show_usage(); + exit(-1); + } + } +} + +void cleanup() { + if (device) { + vx_mem_free(device, kernel_arg.A_addr); + vx_mem_free(device, kernel_arg.B_addr); + vx_mem_free(device, kernel_arg.C_addr); + vx_dev_close(device); + } +} + +int run_test(const kernel_arg_t& kernel_arg, + uint32_t buf_size, + const std::vector& refs) { + // start device + std::cout << "start device" << std::endl; + RT_CHECK(vx_start(device)); + + // wait for completion + std::cout << "wait for completion" << std::endl; + RT_CHECK(vx_ready_wait(device, VX_MAX_TIMEOUT)); + + // download destination buffer + std::cout << "download destination buffer" << std::endl; + RT_CHECK(vx_copy_from_dev(device, staging_buf.data(), kernel_arg.C_addr, buf_size)); + + // verify result + std::cout << "verify result" << std::endl; + { + int errors = 0; + auto buf_ptr = (TYPE*)staging_buf.data(); + for (uint32_t i = 0; i < refs.size(); ++i) { + auto ref = refs[i]; + auto cur = buf_ptr[i]; + if (!Comparator::compare(cur, ref)) { + std::cout << "error at result #" << std::dec << i + << std::hex << ": actual 0x" << cur << ", expected 0x" << ref << std::endl; + ++errors; + } + } + if (errors != 0) { + std::cout << "Found " << std::dec << errors << " errors!" << std::endl; + std::cout << "FAILED!" << std::endl; + return 1; + } + } + + return 0; +} + +int main(int argc, char *argv[]) { + // parse command arguments + parse_args(argc, argv); + + std::srand(50); + + // open device connection + std::cout << "open device connection" << std::endl; + RT_CHECK(vx_dev_open(&device)); + + uint32_t num_points = size * size; + uint32_t buf_size = num_points * sizeof(TYPE); + + std::cout << "data type: " << Comparator::type_str() << std::endl; + std::cout << "matrix size: " << size << "x" << size << std::endl; + std::cout << "buffer size: " << buf_size << " bytes" << std::endl; + + // upload program + std::cout << "upload program" << std::endl; + RT_CHECK(vx_upload_kernel_file(device, kernel_file)); + + // allocate device memory + std::cout << "allocate device memory" << std::endl; + RT_CHECK(vx_mem_alloc(device, buf_size, VX_MEM_TYPE_GLOBAL, &kernel_arg.A_addr)); + RT_CHECK(vx_mem_alloc(device, buf_size, VX_MEM_TYPE_GLOBAL, &kernel_arg.B_addr)); + RT_CHECK(vx_mem_alloc(device, buf_size, VX_MEM_TYPE_GLOBAL, &kernel_arg.C_addr)); + + kernel_arg.num_tasks = num_points; + kernel_arg.size = size; + + std::cout << "dev_src0=0x" << std::hex << kernel_arg.A_addr << std::endl; + std::cout << "dev_src1=0x" << std::hex << kernel_arg.B_addr << std::endl; + std::cout << "dev_dst=0x" << std::hex << kernel_arg.C_addr << std::endl; + + // allocate staging buffer + std::cout << "allocate staging buffer" << std::endl; + uint32_t alloc_size = std::max(buf_size, sizeof(kernel_arg_t)); + staging_buf.resize(alloc_size); + + // upload kernel argument + std::cout << "upload kernel argument" << std::endl; + memcpy(staging_buf.data(), &kernel_arg, sizeof(kernel_arg_t)); + RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); + + // generate source data + std::vector src_A(num_points); + std::vector src_B(num_points); + std::vector refs(num_points); + for (uint32_t i = 0; i < num_points; ++i) { + auto a = static_cast(std::rand()) / RAND_MAX; + auto b = static_cast(std::rand()) / RAND_MAX; + src_A[i] = static_cast(a * size); + src_B[i] = static_cast(b * size); + } + cpuMatrixMultiply(refs.data(), src_A.data(), src_B.data(), size, size); + + // upload source buffer0 + { + std::cout << "upload source buffer0" << std::endl; + auto buf_ptr = (TYPE*)staging_buf.data(); + for (uint32_t i = 0; i < num_points; ++i) { + buf_ptr[i] = src_A[i]; + } + RT_CHECK(vx_copy_to_dev(device, kernel_arg.A_addr, staging_buf.data(), buf_size)); + } + + // upload source buffer1 + { + std::cout << "upload source buffer1" << std::endl; + auto buf_ptr = (TYPE*)staging_buf.data(); + for (uint32_t i = 0; i < num_points; ++i) { + buf_ptr[i] = src_B[i]; + } + RT_CHECK(vx_copy_to_dev(device, kernel_arg.B_addr, staging_buf.data(), buf_size)); + } + + // clear destination buffer + std::cout << "clear destination buffer" << std::endl; + memset(staging_buf.data(), 0, num_points * sizeof(TYPE)); + RT_CHECK(vx_copy_to_dev(device, kernel_arg.C_addr, staging_buf.data(), buf_size)); + + // run tests + std::cout << "run tests" << std::endl; + RT_CHECK(run_test(kernel_arg, buf_size, refs)); + + // cleanup + std::cout << "cleanup" << std::endl; + cleanup(); + + std::cout << "PASSED!" << std::endl; + + return 0; +} \ No newline at end of file From 61e3442ef80b5c7db66e436e08855529d9869af0 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 14 Nov 2023 22:31:30 -0800 Subject: [PATCH 06/57] adding opencl convolution benchmark --- tests/opencl/Makefile | 6 + tests/opencl/convolution/Makefile | 7 + tests/opencl/convolution/kernel.cl | 32 ++++ tests/opencl/convolution/main.cc | 258 +++++++++++++++++++++++++++++ tests/opencl/matmul/Makefile | 2 +- tests/opencl/matmul/kernel.cl | 59 +++---- tests/opencl/matmul/main.cc | 51 +++--- tests/opencl/oclprintf/main.cc | 2 +- tests/opencl/psort/main.cc | 3 +- tests/opencl/sgemm/common.h | 6 +- tests/opencl/sgemm/main.cc | 125 ++++++++------ tests/opencl/vecadd/main.cc | 4 +- tests/regression/demo/main.cpp | 46 ++--- tests/regression/tensor/Makefile | 2 +- tests/regression/tensor/kernel.cpp | 4 +- tests/regression/tensor/main.cpp | 53 +++--- 16 files changed, 490 insertions(+), 170 deletions(-) create mode 100644 tests/opencl/convolution/Makefile create mode 100644 tests/opencl/convolution/kernel.cl create mode 100644 tests/opencl/convolution/main.cc diff --git a/tests/opencl/Makefile b/tests/opencl/Makefile index 2cee5c5d..c838c3de 100644 --- a/tests/opencl/Makefile +++ b/tests/opencl/Makefile @@ -18,6 +18,7 @@ all: $(MAKE) -C oclprintf $(MAKE) -C blackscholes $(MAKE) -C matmul + $(MAKE) -C convolution run-simx: $(MAKE) -C vecadd run-simx @@ -37,6 +38,7 @@ run-simx: $(MAKE) -C blackscholes run-simx $(MAKE) -C matmul run-simx $(MAKE) -C transpose run-simx + $(MAKE) -C convolution run-simx # $(MAKE) -C vectorhypot run-simx # $(MAKE) -C mri-q run-simx @@ -58,6 +60,7 @@ run-rtlsim: $(MAKE) -C oclprintf run-rtlsim $(MAKE) -C blackscholes run-rtlsim $(MAKE) -C matmul run-rtlsim + $(MAKE) -C convolution run-rtlsim # $(MAKE) -C vectorhypot run-rtlsim # $(MAKE) -C mri-q run-rtlsim @@ -79,6 +82,7 @@ run-opae: $(MAKE) -C oclprintf run-opae $(MAKE) -C blackscholes run-opae $(MAKE) -C matmul run-opae + $(MAKE) -C convolution run-opae # $(MAKE) -C vectorhypot run-opae # $(MAKE) -C mri-q run-opae @@ -102,6 +106,7 @@ clean: $(MAKE) -C oclprintf clean $(MAKE) -C blackscholes clean $(MAKE) -C matmul clean + $(MAKE) -C convolution clean clean-all: $(MAKE) -C vecadd clean-all @@ -124,3 +129,4 @@ clean-all: $(MAKE) -C oclprintf clean-all $(MAKE) -C blackscholes clean-all $(MAKE) -C matmul clean-all + $(MAKE) -C convolution clean-all diff --git a/tests/opencl/convolution/Makefile b/tests/opencl/convolution/Makefile new file mode 100644 index 00000000..42a577d2 --- /dev/null +++ b/tests/opencl/convolution/Makefile @@ -0,0 +1,7 @@ +PROJECT = convolution + +SRCS = main.cc + +OPTS ?= -n32 + +include ../common.mk diff --git a/tests/opencl/convolution/kernel.cl b/tests/opencl/convolution/kernel.cl new file mode 100644 index 00000000..2ef31040 --- /dev/null +++ b/tests/opencl/convolution/kernel.cl @@ -0,0 +1,32 @@ +__kernel void conv3x3(__global float* output, + __global float* input, + __global float* weights, + const int width, + const int height) +{ + int x = get_global_id(0); + int y = get_global_id(1); + + // Adjust for padded borders + int paddedWidth = width + 2; + int paddedX = x + 1; + int paddedY = y + 1; + + // Compute the convolution sum + float sum = 0.0f; + + sum += input[(paddedY - 1) * paddedWidth + (paddedX - 1)] * weights[0]; // Top-left + sum += input[(paddedY - 1) * paddedWidth + paddedX] * weights[1]; // Top-center + sum += input[(paddedY - 1) * paddedWidth + (paddedX + 1)] * weights[2]; // Top-right + + sum += input[paddedY * paddedWidth + (paddedX - 1)] * weights[3]; // Middle-left + sum += input[paddedY * paddedWidth + paddedX] * weights[4]; // Center + sum += input[paddedY * paddedWidth + (paddedX + 1)] * weights[5]; // Middle-right + + sum += input[(paddedY + 1) * paddedWidth + (paddedX - 1)] * weights[6]; // Bottom-left + sum += input[(paddedY + 1) * paddedWidth + paddedX] * weights[7]; // Bottom-center + sum += input[(paddedY + 1) * paddedWidth + (paddedX + 1)] * weights[8]; // Bottom-right + + // Store the result in the output array + output[y * width + x] = sum; +} \ No newline at end of file diff --git a/tests/opencl/convolution/main.cc b/tests/opencl/convolution/main.cc new file mode 100644 index 00000000..d7487c2f --- /dev/null +++ b/tests/opencl/convolution/main.cc @@ -0,0 +1,258 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FLOAT_ULP 6 + +#define KERNEL_NAME "conv3x3" + +#define CL_CHECK(_expr) \ + do { \ + cl_int _err = _expr; \ + if (_err == CL_SUCCESS) \ + break; \ + printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ + cleanup(); \ + exit(-1); \ + } while (0) + +#define CL_CHECK2(_expr) \ + ({ \ + cl_int _err = CL_INVALID_VALUE; \ + decltype(_expr) _ret = _expr; \ + if (_err != CL_SUCCESS) { \ + printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ + cleanup(); \ + exit(-1); \ + } \ + _ret; \ + }) + +static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { + if (nullptr == filename || nullptr == data || 0 == size) + return -1; + + FILE* fp = fopen(filename, "r"); + if (NULL == fp) { + fprintf(stderr, "Failed to load kernel."); + return -1; + } + + fseek(fp , 0 , SEEK_END); + long fsize = ftell(fp); + rewind(fp); + + *data = (uint8_t*)malloc(fsize); + *size = fread(*data, 1, fsize, fp); + + fclose(fp); + + return 0; +} + +static bool compare_equal(float a, float b) { + union fi_t { float f; int32_t i; }; + fi_t fa, fb; + fa.f = a; + fb.f = b; + auto d = std::abs(fa.i - fb.i); + return d <= FLOAT_ULP; +} + +static void convolution_cpu(float *O, float *I, float *W, int32_t width, int32_t height) { + int paddedWidth = width + 2; + for (int32_t y = 0; y < height; ++y) { + for (int32_t x = 0; x < width; ++x) { + int paddedY = y + 1; + int paddedX = x + 1; + float sum = 0.0f; + for (int32_t ky = -1; ky <= 1; ++ky) { + for (int32_t kx = -1; kx <= 1; ++kx) { + int32_t iy = paddedY + ky; + int32_t ix = paddedX + kx; + float value = I[iy * paddedWidth + ix]; + float weight = W[(ky + 1) * 3 + (kx + 1)]; + sum += value * weight; + } + } + O[y * width + x] = sum; + } + } +} + +cl_device_id device_id = NULL; +cl_context context = NULL; +cl_command_queue commandQueue = NULL; +cl_program program = NULL; +cl_kernel kernel = NULL; +cl_mem i_memobj = NULL; +cl_mem w_memobj = NULL; +cl_mem o_memobj = NULL; +uint8_t* kernel_bin = NULL; + +static void cleanup() { + if (commandQueue) clReleaseCommandQueue(commandQueue); + if (kernel) clReleaseKernel(kernel); + if (program) clReleaseProgram(program); + if (i_memobj) clReleaseMemObject(i_memobj); + if (w_memobj) clReleaseMemObject(w_memobj); + if (o_memobj) clReleaseMemObject(o_memobj); + if (context) clReleaseContext(context); + if (device_id) clReleaseDevice(device_id); + if (kernel_bin) free(kernel_bin); +} + +int size = 32; + +static void show_usage() { + printf("Usage: [-n size] [-h: help]\n"); +} + +static void parse_args(int argc, char **argv) { + int c; + while ((c = getopt(argc, argv, "n:h?")) != -1) { + switch (c) { + case 'n': + size = atoi(optarg); + break; + case 'h': + case '?': { + show_usage(); + exit(0); + } break; + default: + show_usage(); + exit(-1); + } + } +} + +int main (int argc, char **argv) { + // parse command arguments + parse_args(argc, argv); + + printf("Matrix size=%d\n", size); + + uint32_t o_points = size * size; + uint32_t i_points = (size+2) * (size+2); + uint32_t w_points = 3 * 3; + + cl_platform_id platform_id; + size_t kernel_size; + + // Getting platform and device information + CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); + CL_CHECK(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL)); + + printf("Create context\n"); + context = CL_CHECK2(clCreateContext(NULL, 1, &device_id, NULL, NULL, &_err)); + + char device_string[1024]; + clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); + printf("Using device: %s\n", device_string); + + printf("Allocate device buffers\n"); + size_t i_nbytes = i_points * sizeof(float); + size_t w_nbytes = w_points * sizeof(float); + size_t o_nbytes = o_points * sizeof(float); + i_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY, i_nbytes, NULL, &_err)); + w_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY, w_nbytes, NULL, &_err)); + o_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, o_nbytes, NULL, &_err)); + + printf("Create program from kernel source\n"); +#ifdef HOSTGPU + if (0 != read_kernel_file("kernel.cl", &kernel_bin, &kernel_size)) + return -1; + program = CL_CHECK2(clCreateProgramWithSource( + context, 1, (const char**)&kernel_bin, &kernel_size, &_err)); +#else + if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) + return -1; + program = CL_CHECK2(clCreateProgramWithBinary( + context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, NULL, &_err)); +#endif + if (program == NULL) { + cleanup(); + return -1; + } + + // Build program + CL_CHECK(clBuildProgram(program, 1, &device_id, NULL, NULL, NULL)); + + // Create kernel + kernel = CL_CHECK2(clCreateKernel(program, KERNEL_NAME, &_err)); + + size_t global_size[2] = {size, size}; + + // Set kernel arguments + CL_CHECK(clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&o_memobj)); + CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&i_memobj)); + CL_CHECK(clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *)&w_memobj)); + CL_CHECK(clSetKernelArg(kernel, 3, sizeof(uint32_t), &size)); + CL_CHECK(clSetKernelArg(kernel, 4, sizeof(uint32_t), &size)); + + // Allocate memories for input arrays and output arrays. + std::vector h_i(i_points); + std::vector h_w(w_points); + std::vector h_o(o_points, 0.0f); + + // Generate input values + for (int32_t y = -1; y < size+1; ++y) { + for (int32_t x = -1; x < size+1; ++x) { + if (x >= 0 && x < size && y >= 0 && y < size) { + h_i[(y+1) * (size+2) + (x+1)] = static_cast(rand()) / RAND_MAX; + } else { + h_i[(y+1) * (size+2) + (x+1)] = 0; + } + } + } + for (uint32_t i = 0; i < w_points; ++i) { + h_w[i] = static_cast(rand()) / RAND_MAX; + } + + // Creating command queue + commandQueue = CL_CHECK2(clCreateCommandQueue(context, device_id, 0, &_err)); + + printf("Upload source buffers\n"); + CL_CHECK(clEnqueueWriteBuffer(commandQueue, i_memobj, CL_TRUE, 0, i_nbytes, h_i.data(), 0, NULL, NULL)); + CL_CHECK(clEnqueueWriteBuffer(commandQueue, w_memobj, CL_TRUE, 0, w_nbytes, h_w.data(), 0, NULL, NULL)); + + printf("Execute the kernel\n"); + auto time_start = std::chrono::high_resolution_clock::now(); + CL_CHECK(clEnqueueNDRangeKernel(commandQueue, kernel, 2, NULL, global_size, NULL, 0, NULL, NULL)); + CL_CHECK(clFinish(commandQueue)); + auto time_end = std::chrono::high_resolution_clock::now(); + double elapsed = std::chrono::duration_cast(time_end - time_start).count(); + printf("Elapsed time: %lg ms\n", elapsed); + + printf("Download destination buffer\n"); + CL_CHECK(clEnqueueReadBuffer(commandQueue, o_memobj, CL_TRUE, 0, o_nbytes, h_o.data(), 0, NULL, NULL)); + + printf("Verify result\n"); + std::vector ref_vec(o_points); + convolution_cpu(ref_vec.data(), h_i.data(), h_w.data(), size, size); + int errors = 0; + for (uint32_t i = 0; i < o_points; ++i) { + if (!compare_equal(h_o[i], ref_vec[i])) { + if (errors < 100) + printf("*** error: [%d] expected=%f, actual=%f\n", i, ref_vec[i], h_o[i]); + ++errors; + } + } + if (errors != 0) { + printf("FAILED! - %d errors\n", errors); + } else { + printf("PASSED!\n"); + } + + // Clean up + cleanup(); + + return errors; +} diff --git a/tests/opencl/matmul/Makefile b/tests/opencl/matmul/Makefile index 0d1d136a..39b92b36 100644 --- a/tests/opencl/matmul/Makefile +++ b/tests/opencl/matmul/Makefile @@ -2,6 +2,6 @@ PROJECT = matmul SRCS = main.cc -OPTS ?= -n16 +OPTS ?= -n32 include ../common.mk diff --git a/tests/opencl/matmul/kernel.cl b/tests/opencl/matmul/kernel.cl index a0ef2d81..02aa074c 100644 --- a/tests/opencl/matmul/kernel.cl +++ b/tests/opencl/matmul/kernel.cl @@ -7,43 +7,41 @@ __kernel void matmul(__global float *A, { int globalRow = get_global_id(1); int globalCol = get_global_id(0); - int localRow = get_local_id(1); - int localCol = get_local_id(0); + int localRow = get_local_id(1); + int localCol = get_local_id(0); int localSize = get_local_size(0); // assuming square local size float sum = 0.0f; - // Load initial blocks of A and B into local memory - int k = 0; - localA[localRow * localSize + localCol] = A[globalRow * N + k + localCol]; - localB[localRow * localSize + localCol] = B[(k + localRow) * N + globalCol]; + // Loop over all blocks of both matrices + for (int k = 0; k < N; k += localSize) { + // Load block of matrix A to local memory + localA[localRow * localSize + localCol] = A[globalRow * N + k + localCol]; - // Iterate over blocks - for (k = 0; k < N; k += 16) { - // Ensure the initial block is loaded + // Load block of matrix B to local memory, adjusting for column-major access + localB[localRow * localSize + localCol] = B[(k + localRow) * N + globalCol]; + + // Synchronize to make sure the tiles are loaded barrier(CLK_LOCAL_MEM_FENCE); - // Compute multiplication for this block - for (int j = 0; j < 16; j++) { + // Multiply the two matrix blocks and accumulate result + for (int j = 0; j < localSize; j++) { sum += localA[localRow * localSize + j] * localB[j * localSize + localCol]; } - - // Load the next block of matrix A into local memory - if (k + 16 < N) { - localA[localRow * localSize + localCol] = A[globalRow * N + k + 16 + localCol]; - localB[localRow * localSize + localCol] = B[(k + 16 + localRow) * N + globalCol]; - } } C[globalRow * N + globalCol] = sum; } -/*__kernel void matmul(__global float *A, __global float *B, __global float *C, const unsigned int N) +/*__kernel void matmul(__global float *A, + __global float *B, + __global float *C, + const unsigned int N) { int globalRow = get_global_id(1); int globalCol = get_global_id(0); - int localRow = get_local_id(1); - int localCol = get_local_id(0); + int localRow = get_local_id(1); + int localCol = get_local_id(0); // Static local memory declaration __local float localA[16][16]; @@ -51,26 +49,21 @@ __kernel void matmul(__global float *A, float sum = 0.0f; - // Load initial blocks of A and B into local memory - int k = 0; - localA[localRow][localCol] = A[globalRow * N + k + localCol]; - localB[localRow][localCol] = B[(k + localRow) * N + globalCol]; - // Iterate over blocks - for (k = 0; k < N; k += 16) { - // Ensure the initial block is loaded + for (int k = 0; k < N; k += 16) { + // Load a block of matrix A into local memory + localA[localRow][localCol] = A[globalRow * N + k + localCol]; + + // Load a block of matrix B into local memory + localB[localRow][localCol] = B[(k + localRow) * N + globalCol]; + + // Ensure the entire block is loaded barrier(CLK_LOCAL_MEM_FENCE); // Compute multiplication for this block for (int j = 0; j < 16; j++) { sum += localA[localRow][j] * localB[j][localCol]; } - - // Load the next block of matrix A into local memory - if (k + 16 < N) { - localA[localRow][localCol] = A[globalRow * N + k + 16 + localCol]; - localB[localRow][localCol] = B[(k + 16 + localRow) * N + globalCol]; - } } C[globalRow * N + globalCol] = sum; diff --git a/tests/opencl/matmul/main.cc b/tests/opencl/matmul/main.cc index f7714dd7..3d26ff0c 100644 --- a/tests/opencl/matmul/main.cc +++ b/tests/opencl/matmul/main.cc @@ -10,6 +10,8 @@ #define LOCAL_SIZE 16 +#define FLOAT_ULP 6 + #define KERNEL_NAME "matmul" #define CL_CHECK(_expr) \ @@ -56,15 +58,16 @@ static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) return 0; } -static bool compare_equal(float a, float b, int ulp = 21) { - union fi_t { int i; float f; }; +static bool compare_equal(float a, float b) { + union fi_t { float f; int32_t i; }; fi_t fa, fb; fa.f = a; fb.f = b; - return std::abs(fa.i - fb.i) <= ulp; + auto d = std::abs(fa.i - fb.i); + return d <= FLOAT_ULP; } -static void matrix_multiply_cpu(float *A, float *B, float *C, int N) { +static void matmul_cpu(float *C, float *A, float *B, int N) { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { float sum = 0.0f; @@ -98,7 +101,7 @@ static void cleanup() { if (kernel_bin) free(kernel_bin); } -int size = 64; +int size = 32; static void show_usage() { printf("Usage: [-n size] [-h: help]\n"); @@ -106,7 +109,7 @@ static void show_usage() { static void parse_args(int argc, char **argv) { int c; - while ((c = getopt(argc, argv, "fn:h?")) != -1) { + while ((c = getopt(argc, argv, "n:h?")) != -1) { switch (c) { case 'n': size = atoi(optarg); @@ -127,6 +130,8 @@ int main (int argc, char **argv) { // parse command arguments parse_args(argc, argv); + uint32_t num_points = size * size; + printf("Matrix size=%d\n", size); if ((size / LOCAL_SIZE) * LOCAL_SIZE != size) { printf("Error: matrix size must be a multiple of %d\n", LOCAL_SIZE); @@ -148,7 +153,7 @@ int main (int argc, char **argv) { printf("Using device: %s\n", device_string); printf("Allocate device buffers\n"); - size_t nbytes = size * size * sizeof(float); + size_t nbytes = num_points * sizeof(float); a_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY, nbytes, NULL, &_err)); b_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY, nbytes, NULL, &_err)); c_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, nbytes, NULL, &_err)); @@ -176,32 +181,26 @@ int main (int argc, char **argv) { // Create kernel kernel = CL_CHECK2(clCreateKernel(program, KERNEL_NAME, &_err)); - size_t local_size[2] = {LOCAL_SIZE, LOCAL_SIZE}; size_t global_size[2] = {size, size}; + size_t local_size[2] = {LOCAL_SIZE, LOCAL_SIZE}; // Set kernel arguments CL_CHECK(clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&a_memobj)); CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&b_memobj)); CL_CHECK(clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *)&c_memobj)); CL_CHECK(clSetKernelArg(kernel, 3, sizeof(uint32_t), &size)); - //CL_CHECK(clSetKernelArg(kernel, 4, local_size[0]*local_size[1]*sizeof(float), NULL)); - //CL_CHECK(clSetKernelArg(kernel, 5, local_size[0]*local_size[1]*sizeof(float), NULL)); + CL_CHECK(clSetKernelArg(kernel, 4, local_size[0]*local_size[1]*sizeof(float), NULL)); + CL_CHECK(clSetKernelArg(kernel, 5, local_size[0]*local_size[1]*sizeof(float), NULL)); // Allocate memories for input arrays and output arrays. - std::vector h_a(size * size); - std::vector h_b(size * size); - std::vector h_c(size * size); + std::vector h_a(num_points); + std::vector h_b(num_points); + std::vector h_c(num_points); - // Initialize values for array members. - for (int i = 0; i < (size * size); ++i) { - #ifdef USE_FLOAT - h_a[i] = (float)rand() / (float)RAND_MAX; - h_b[i] = (float)rand() / (float)RAND_MAX; - #else - h_a[i] = rand(); - h_b[i] = rand(); - #endif - h_c[i] = 0xdeadbeef; + // Generate input values + for (uint32_t i = 0; i < num_points; ++i) { + h_a[i] = static_cast(rand()) / RAND_MAX; + h_b[i] = static_cast(rand()) / RAND_MAX; } // Creating command queue @@ -223,10 +222,10 @@ int main (int argc, char **argv) { CL_CHECK(clEnqueueReadBuffer(commandQueue, c_memobj, CL_TRUE, 0, nbytes, h_c.data(), 0, NULL, NULL)); printf("Verify result\n"); - std::vector ref_vec(size * size); - matrix_multiply_cpu(h_a.data(), h_b.data(), ref_vec.data(), size); + std::vector ref_vec(num_points); + matmul_cpu(ref_vec.data(), h_a.data(), h_b.data(), size); int errors = 0; - for (int i = 0; i < (size * size); i++) { + for (uint32_t i = 0; i < num_points; ++i) { if (!compare_equal(h_c[i], ref_vec[i])) { if (errors < 100) printf("*** error: [%d] expected=%f, actual=%f\n", i, ref_vec[i], h_c[i]); diff --git a/tests/opencl/oclprintf/main.cc b/tests/opencl/oclprintf/main.cc index 7c0463cf..184eec96 100644 --- a/tests/opencl/oclprintf/main.cc +++ b/tests/opencl/oclprintf/main.cc @@ -143,7 +143,7 @@ int main (int argc, char **argv) { // Allocate memories for input arrays and output arrays. h_a = (int*)malloc(nbytes); - // Initialize values for array members. + // Generate input values for (int i = 0; i < size; ++i) { h_a[i] = -1 + i; } diff --git a/tests/opencl/psort/main.cc b/tests/opencl/psort/main.cc index 26a42807..b627ceee 100644 --- a/tests/opencl/psort/main.cc +++ b/tests/opencl/psort/main.cc @@ -155,9 +155,8 @@ int main (int argc, char **argv) { h_a = (int*)malloc(nbytes); h_c = (int*)malloc(nbytes); - // Initialize values for array members. + // Generate input values for (int i = 0; i < size; ++i) { - h_c[i] = 0xdeadbeef; if (float_enable) { float value = sinf(i)*sinf(i); h_a[i] = *(int*)&value; diff --git a/tests/opencl/sgemm/common.h b/tests/opencl/sgemm/common.h index 01f68d48..fdb40bce 100644 --- a/tests/opencl/sgemm/common.h +++ b/tests/opencl/sgemm/common.h @@ -1,12 +1,8 @@ #ifndef COMMON_H #define COMMON_H -#define USE_FLOAT - -#ifdef USE_FLOAT +#ifndef TYPE #define TYPE float -#else -#define TYPE int #endif #endif // COMMON_H \ No newline at end of file diff --git a/tests/opencl/sgemm/main.cc b/tests/opencl/sgemm/main.cc index 3ca14792..7a02929f 100644 --- a/tests/opencl/sgemm/main.cc +++ b/tests/opencl/sgemm/main.cc @@ -11,6 +11,8 @@ #define KERNEL_NAME "sgemm" +#define FLOAT_ULP 6 + #define CL_CHECK(_expr) \ do { \ cl_int _err = _expr; \ @@ -33,6 +35,66 @@ _ret; \ }) +template +class Comparator {}; + +template <> +class Comparator { +public: + static const char* type_str() { + return "integer"; + } + static int generate() { + return rand(); + } + static bool compare(int a, int b, int index, int errors) { + if (a != b) { + if (errors < 100) { + printf("*** error: [%d] expected=%d, actual=%d\n", index, a, b); + } + return false; + } + return true; + } +}; + +template <> +class Comparator { +public: + static const char* type_str() { + return "float"; + } + static int generate() { + return static_cast(rand()) / RAND_MAX; + } + static bool compare(float a, float b, int index, int errors) { + union fi_t { float f; int32_t i; }; + fi_t fa, fb; + fa.f = a; + fb.f = b; + auto d = std::abs(fa.i - fb.i); + if (d > FLOAT_ULP) { + if (errors < 100) { + printf("*** error: [%d] expected=%f, actual=%f\n", index, a, b); + } + return false; + } + return true; + } +}; + +/*static void sgemm_cpu(TYPE *C, const TYPE* A, const TYPE *B, int M, int N, int K) { + for (int m = 0; m < M; ++m) { + for (int n = 0; n < N; ++n) { + TYPE acc = 0; + for (int k = 0; k < K; ++k) { + acc += A[k * M + m] * B[n * K + k]; + } + C[n * M + m] = acc; + } + } +}*/ + static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { if (nullptr == filename || nullptr == data || 0 == size) return -1; @@ -54,32 +116,6 @@ static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) return 0; } -/*static void matmul(TYPE *C, const TYPE* A, const TYPE *B, int M, int N, int K) { - for (int m = 0; m < M; ++m) { - for (int n = 0; n < N; ++n) { - TYPE acc = 0; - for (int k = 0; k < K; ++k) { - acc += A[k * M + m] * B[n * K + k]; - } - C[n * M + m] = acc; - } - } -}*/ - -#ifdef USE_FLOAT -static bool compare_equal(float a, float b, int ulp = 21) { - union fi_t { int i; float f; }; - fi_t fa, fb; - fa.f = a; - fb.f = b; - return std::abs(fa.i - fb.i) <= ulp; -} -#else -static bool compare_equal(int a, int b, int ulp = 21) { - return (a == b); -} -#endif - cl_device_id device_id = NULL; cl_context context = NULL; cl_command_queue commandQueue = NULL; @@ -145,6 +181,8 @@ int main (int argc, char **argv) { // parse command arguments parse_args(argc, argv); + uint32_t num_points = size * size; + cl_platform_id platform_id; size_t kernel_size; cl_int binary_status; @@ -163,7 +201,7 @@ int main (int argc, char **argv) { context = CL_CHECK2(clCreateContext(NULL, 1, &device_id, NULL, NULL, &_err)); // Allocate device buffers - size_t nbytes = size * size * sizeof(TYPE); + size_t nbytes = num_points * sizeof(TYPE); a_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY, nbytes, NULL, &_err)); b_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY, nbytes, NULL, &_err)); c_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, nbytes, NULL, &_err)); @@ -194,23 +232,17 @@ int main (int argc, char **argv) { h_b = (TYPE*)malloc(nbytes); h_c = (TYPE*)malloc(nbytes); - // Initialize values for array members. - for (int i = 0; i < (size * size); ++i) { - #ifdef USE_FLOAT - h_a[i] = (float)rand() / (float)RAND_MAX; - h_b[i] = (float)rand() / (float)RAND_MAX; - #else - h_a[i] = rand(); - h_b[i] = rand(); - #endif - h_c[i] = 0xdeadbeef; + // Generate input values + for (uint32_t i = 0; i < num_points; ++i) { + h_a[i] = Comparator::generate(); + h_b[i] = Comparator::generate(); } size_t global_offset[2] = {0, 0}; size_t global_work_size[2] = {size, size}; size_t local_work_size[2] = {1, 1}; - std::vector ref_vec(size * size); + std::vector ref_vec(num_points); // reference generation size_t num_groups_y = global_work_size[1] / local_work_size[1]; @@ -228,12 +260,7 @@ int main (int argc, char **argv) { TYPE acc = 0; for (int k = 0; k < width; k++) { acc += h_a[k * width + r] * h_b[c * width + k]; - } - /*#ifdef USE_FLOAT - printf("*** r=%d, c=%d, v=%f\n", r, c, acc); - #else - printf("*** r=%d, c=%d, v=%d\n", r, c, acc); - #endif*/ + } ref_vec[c * width + r] = acc; } } @@ -260,14 +287,8 @@ int main (int argc, char **argv) { printf("Verify result\n"); int errors = 0; - for (int i = 0; i < (size * size); i++) { - if (!compare_equal(h_c[i], ref_vec[i])) { - if (errors < 100) - #ifdef USE_FLOAT - printf("*** error: [%d] expected=%f, actual=%f\n", i, ref_vec[i], h_c[i]); - #else - printf("*** error: [%d] expected=%d, actual=%d\n", i, ref_vec[i], h_c[i]); - #endif + for (uint32_t i = 0; i < num_points; ++i) { + if (!Comparator::compare(h_c[i], ref_vec[i], i, errors)) { ++errors; } } diff --git a/tests/opencl/vecadd/main.cc b/tests/opencl/vecadd/main.cc index 23aa49b4..992e88be 100644 --- a/tests/opencl/vecadd/main.cc +++ b/tests/opencl/vecadd/main.cc @@ -166,12 +166,10 @@ int main (int argc, char **argv) { h_b = (float*)malloc(nbytes); h_c = (float*)malloc(nbytes); - // Initialize values for array members. + // Generate input values for (int i = 0; i < size; ++i) { h_a[i] = sinf(i)*sinf(i); h_b[i] = cosf(i)*cosf(i); - h_c[i] = 0xdeadbeef; - //printf("*** [%d]: h_a=%f, h_b=%f\n", i, h_a[i], h_b[i]); } // Creating command queue diff --git a/tests/regression/demo/main.cpp b/tests/regression/demo/main.cpp index 63556a5f..f14f66c3 100644 --- a/tests/regression/demo/main.cpp +++ b/tests/regression/demo/main.cpp @@ -19,16 +19,6 @@ /////////////////////////////////////////////////////////////////////////////// -union Float_t { - float f; - int i; - struct { - uint32_t man : 23; - uint32_t exp : 8; - uint32_t sign : 1; - } parts; -}; - template class Comparator {}; @@ -38,22 +28,41 @@ public: static const char* type_str() { return "integer"; } - static bool compare(int a, int b) { - return a == b; + static int generate() { + return rand(); + } + static bool compare(int a, int b, int index, int errors) { + if (a != b) { + if (errors < 100) { + printf("*** error: [%d] expected=%d, actual=%d\n", index, a, b); + } + return false; + } + return true; } }; template <> class Comparator { +private: + union Float_t { float f; int i; }; public: static const char* type_str() { return "float"; } - static bool compare(float a, float b) { - Float_t fa{a}, fb{b}; + static int generate() { + return static_cast(rand()) / RAND_MAX; + } + static bool compare(float a, float b, int index, int errors) { + union fi_t { float f; int32_t i; }; + fi_t fa, fb; + fa.f = a; + fb.f = b; auto d = std::abs(fa.i - fb.i); if (d > FLOAT_ULP) { - std::cout << "*** almost_equal_ulp: a=" << a << ", b=" << b << ", ulp=" << d << ", ia=" << std::hex << fa.i << ", ib=" << fb.i << std::endl; + if (errors < 100) { + printf("*** error: [%d] expected=%f, actual=%f\n", index, a, b); + } return false; } return true; @@ -127,9 +136,7 @@ int run_test(const kernel_arg_t& kernel_arg, for (uint32_t i = 0; i < num_points; ++i) { auto ref = source_data[2 * i + 0] + source_data[2 * i + 1]; auto cur = buf_ptr[i]; - if (!Comparator::compare(cur, ref)) { - std::cout << "error at result #" << std::dec << i - << std::hex << ": actual 0x" << cur << ", expected 0x" << ref << std::endl; + if (!Comparator::compare(cur, ref, i, errors)) { ++errors; } } @@ -196,8 +203,7 @@ int main(int argc, char *argv[]) { // generate source data source_data.resize(2 * num_points); for (uint32_t i = 0; i < source_data.size(); ++i) { - auto r = static_cast(std::rand()) / RAND_MAX; - source_data[i] = static_cast(r * 2 * num_points); + source_data[i] = Comparator::generate(); } // upload source buffer0 diff --git a/tests/regression/tensor/Makefile b/tests/regression/tensor/Makefile index 790664dc..dbb70c3b 100644 --- a/tests/regression/tensor/Makefile +++ b/tests/regression/tensor/Makefile @@ -4,6 +4,6 @@ SRCS = main.cpp VX_SRCS = kernel.cpp -OPTS ?= -s16 +OPTS ?= -n32 include ../common.mk \ No newline at end of file diff --git a/tests/regression/tensor/kernel.cpp b/tests/regression/tensor/kernel.cpp index 5cf0851c..b0e8f69e 100644 --- a/tests/regression/tensor/kernel.cpp +++ b/tests/regression/tensor/kernel.cpp @@ -12,10 +12,10 @@ inline uint32_t log2_fast(uint32_t x) { } void kernel_body(uint32_t task_id, kernel_arg_t* __UNIFORM__ arg) { - auto size = arg->size; - auto A = reinterpret_cast(arg->A_addr); + auto A = reinterpret_cast(arg->A_addr); auto B = reinterpret_cast(arg->B_addr); auto C = reinterpret_cast(arg->C_addr); + auto size = arg->size; uint32_t row, col; if (is_log2(size)) { diff --git a/tests/regression/tensor/main.cpp b/tests/regression/tensor/main.cpp index d93f3177..81103c10 100644 --- a/tests/regression/tensor/main.cpp +++ b/tests/regression/tensor/main.cpp @@ -19,16 +19,6 @@ /////////////////////////////////////////////////////////////////////////////// -union Float_t { - float f; - int i; - struct { - uint32_t man : 23; - uint32_t exp : 8; - uint32_t sign : 1; - } parts; -}; - template class Comparator {}; @@ -38,8 +28,17 @@ public: static const char* type_str() { return "integer"; } - static bool compare(int a, int b) { - return a == b; + static int generate() { + return rand(); + } + static bool compare(int a, int b, int index, int errors) { + if (a != b) { + if (errors < 100) { + printf("*** error: [%d] expected=%d, actual=%d\n", index, a, b); + } + return false; + } + return true; } }; @@ -49,18 +48,26 @@ public: static const char* type_str() { return "float"; } - static bool compare(float a, float b) { - Float_t fa{a}, fb{b}; + static int generate() { + return static_cast(rand()) / RAND_MAX; + } + static bool compare(float a, float b, int index, int errors) { + union fi_t { float f; int32_t i; }; + fi_t fa, fb; + fa.f = a; + fb.f = b; auto d = std::abs(fa.i - fb.i); if (d > FLOAT_ULP) { - std::cout << "*** almost_equal_ulp: a=" << a << ", b=" << b << ", ulp=" << d << ", ia=" << std::hex << fa.i << ", ib=" << fb.i << std::endl; + if (errors < 100) { + printf("*** error: [%d] expected=%f, actual=%f\n", index, a, b); + } return false; } return true; } }; -static void cpuMatrixMultiply(TYPE* out, const TYPE* A, const TYPE* B, uint32_t width, uint32_t height) { +static void matmul_cpu(TYPE* out, const TYPE* A, const TYPE* B, uint32_t width, uint32_t height) { for (uint32_t row = 0; row < height; ++row) { for (uint32_t col = 0; col < width; ++col) { TYPE sum(0); @@ -73,7 +80,7 @@ static void cpuMatrixMultiply(TYPE* out, const TYPE* A, const TYPE* B, uint32_t } const char* kernel_file = "kernel.bin"; -uint32_t size = 16; +uint32_t size = 32; vx_device_h device = nullptr; std::vector staging_buf; @@ -81,14 +88,14 @@ kernel_arg_t kernel_arg = {}; static void show_usage() { std::cout << "Vortex Test." << std::endl; - std::cout << "Usage: [-k: kernel] [-s size] [-h: help]" << std::endl; + std::cout << "Usage: [-k: kernel] [-n size] [-h: help]" << std::endl; } static void parse_args(int argc, char **argv) { int c; - while ((c = getopt(argc, argv, "s:k:h?")) != -1) { + while ((c = getopt(argc, argv, "n:k:h?")) != -1) { switch (c) { - case 's': + case 'n': size = atoi(optarg); break; case 'k': @@ -138,9 +145,7 @@ int run_test(const kernel_arg_t& kernel_arg, for (uint32_t i = 0; i < refs.size(); ++i) { auto ref = refs[i]; auto cur = buf_ptr[i]; - if (!Comparator::compare(cur, ref)) { - std::cout << "error at result #" << std::dec << i - << std::hex << ": actual 0x" << cur << ", expected 0x" << ref << std::endl; + if (!Comparator::compare(cur, ref, i, errors)) { ++errors; } } @@ -208,7 +213,7 @@ int main(int argc, char *argv[]) { src_A[i] = static_cast(a * size); src_B[i] = static_cast(b * size); } - cpuMatrixMultiply(refs.data(), src_A.data(), src_B.data(), size, size); + matmul_cpu(refs.data(), src_A.data(), src_B.data(), size, size); // upload source buffer0 { From ede5e1c311f0424b53ac7c33a943c14411ff54ac Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 15 Nov 2023 00:28:26 -0800 Subject: [PATCH 07/57] minor update --- tests/opencl/Makefile | 6 +-- tests/opencl/common.mk | 3 +- tests/opencl/oclprintf/main.cc | 20 ++++----- tests/opencl/psort/main.cc | 74 ++++++++++++++++++---------------- tests/opencl/saxpy/main.cc | 31 ++++++-------- tests/opencl/sfilter/main.cc | 31 ++++++-------- tests/opencl/sgemm/main.cc | 20 ++++----- tests/opencl/vecadd/main.cc | 21 +++++----- 8 files changed, 100 insertions(+), 106 deletions(-) diff --git a/tests/opencl/Makefile b/tests/opencl/Makefile index c838c3de..acb96ba9 100644 --- a/tests/opencl/Makefile +++ b/tests/opencl/Makefile @@ -36,9 +36,9 @@ run-simx: $(MAKE) -C lbm run-simx $(MAKE) -C oclprintf run-simx $(MAKE) -C blackscholes run-simx - $(MAKE) -C matmul run-simx $(MAKE) -C transpose run-simx $(MAKE) -C convolution run-simx +# $(MAKE) -C matmul run-simx # $(MAKE) -C vectorhypot run-simx # $(MAKE) -C mri-q run-simx @@ -59,8 +59,8 @@ run-rtlsim: $(MAKE) -C lbm run-rtlsim $(MAKE) -C oclprintf run-rtlsim $(MAKE) -C blackscholes run-rtlsim - $(MAKE) -C matmul run-rtlsim $(MAKE) -C convolution run-rtlsim +# $(MAKE) -C matmul run-rtlsim # $(MAKE) -C vectorhypot run-rtlsim # $(MAKE) -C mri-q run-rtlsim @@ -81,8 +81,8 @@ run-opae: $(MAKE) -C lbm run-opae $(MAKE) -C oclprintf run-opae $(MAKE) -C blackscholes run-opae - $(MAKE) -C matmul run-opae $(MAKE) -C convolution run-opae +# $(MAKE) -C matmul run-opae # $(MAKE) -C vectorhypot run-opae # $(MAKE) -C mri-q run-opae diff --git a/tests/opencl/common.mk b/tests/opencl/common.mk index ce82dac3..762712b4 100644 --- a/tests/opencl/common.mk +++ b/tests/opencl/common.mk @@ -41,13 +41,12 @@ CXXFLAGS += -std=c++11 -Wall -Wextra -Wfatal-errors CXXFLAGS += -Wno-deprecated-declarations -Wno-unused-parameter -Wno-narrowing CXXFLAGS += -pthread CXXFLAGS += -I$(POCL_RT_PATH)/include -LDFLAGS += -L$(POCL_RT_PATH)/lib -L$(VORTEX_RT_PATH)/stub -lvortex ifdef HOSTGPU CXXFLAGS += -DHOSTGPU LDFLAGS += -lOpenCL else - LDFLAGS += $(POCL_RT_PATH)/lib/libOpenCL.so + LDFLAGS += -L$(VORTEX_RT_PATH)/stub -lvortex $(POCL_RT_PATH)/lib/libOpenCL.so endif # Debugigng diff --git a/tests/opencl/oclprintf/main.cc b/tests/opencl/oclprintf/main.cc index 184eec96..4af39802 100644 --- a/tests/opencl/oclprintf/main.cc +++ b/tests/opencl/oclprintf/main.cc @@ -106,11 +106,6 @@ int main (int argc, char **argv) { cl_platform_id platform_id; size_t kernel_size; - cl_int binary_status; - - // read kernel binary from file - if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) - return -1; // Getting platform and device information CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); @@ -124,12 +119,17 @@ int main (int argc, char **argv) { a_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY, nbytes, NULL, &_err)); printf("Create program from kernel source\n"); - program = CL_CHECK2(clCreateProgramWithBinary( - context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &_err)); - if (program == NULL) { - cleanup(); +#ifdef HOSTGPU + if (0 != read_kernel_file("kernel.cl", &kernel_bin, &kernel_size)) return -1; - } + program = CL_CHECK2(clCreateProgramWithSource( + context, 1, (const char**)&kernel_bin, &kernel_size, &_err)); +#else + if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) + return -1; + program = CL_CHECK2(clCreateProgramWithBinary( + context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, NULL, &_err)); +#endif // Build program CL_CHECK(clBuildProgram(program, 1, &device_id, NULL, NULL, NULL)); diff --git a/tests/opencl/psort/main.cc b/tests/opencl/psort/main.cc index b627ceee..8bc834dc 100644 --- a/tests/opencl/psort/main.cc +++ b/tests/opencl/psort/main.cc @@ -115,11 +115,6 @@ int main (int argc, char **argv) { cl_platform_id platform_id; size_t kernel_size; - cl_int binary_status; - - // read kernel binary from file - if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) - return -1; // Getting platform and device information CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); @@ -134,12 +129,17 @@ int main (int argc, char **argv) { c_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, nbytes, NULL, &_err)); printf("Create program from kernel source\n"); - program = CL_CHECK2(clCreateProgramWithBinary( - context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &_err)); - if (program == NULL) { - cleanup(); +#ifdef HOSTGPU + if (0 != read_kernel_file("kernel.cl", &kernel_bin, &kernel_size)) return -1; - } + program = CL_CHECK2(clCreateProgramWithSource( + context, 1, (const char**)&kernel_bin, &kernel_size, &_err)); +#else + if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) + return -1; + program = CL_CHECK2(clCreateProgramWithBinary( + context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, NULL, &_err)); +#endif // Build program CL_CHECK(clBuildProgram(program, 1, &device_id, NULL, NULL, NULL)); @@ -159,12 +159,12 @@ int main (int argc, char **argv) { for (int i = 0; i < size; ++i) { if (float_enable) { float value = sinf(i)*sinf(i); - h_a[i] = *(int*)&value; - printf("*** [%d]: h_a=%f\n", i, value); + ((float*)h_a)[i] = value; + printf("*** [%d]: %f\n", i, value); } else { int value = size*sinf(i); h_a[i] = value; - printf("*** [%d]: h_a=%d\n", i, value); + printf("*** [%d]: %d\n", i, value); } } @@ -188,38 +188,44 @@ int main (int argc, char **argv) { CL_CHECK(clEnqueueReadBuffer(commandQueue, c_memobj, CL_TRUE, 0, nbytes, h_c, 0, NULL, NULL)); printf("Verify result\n"); - for (int i = 0; i < size; ++i) { - int value = h_c[i]; + for (int i = 0; i < size; ++i) { if (float_enable) { - printf("*** [%d]: h_a=%f\n", i, *(float*)&value); + float value = ((float*)h_c)[i]; + printf("*** [%d]: %f\n", i, value); } else { - printf("*** [%d]: h_a=%d\n", i, value); + int value = h_c[i]; + printf("*** [%d]: %d\n", i, value); } } int errors = 0; - for (int i = 0; i < size; ++i) { - int ref = h_a[i]; - float ref_f = *(float*)&ref; + for (int i = 0; i < size; ++i) { int pos = 0; - for (int j = 0; j < size; ++j) { - int cur = h_a[j]; - if (float_enable) { - float cur_f = *(float*)&cur; - pos += (cur_f < ref_f) || (cur_f == ref_f && j < i); - } else { + if (float_enable) { + float ref = ((float*)h_a)[i]; + for (int j = 0; j < size; ++j) { + float cur = ((float*)h_a)[j]; + pos += (cur < ref) || (cur == ref && j < i); + } + float value = ((float*)h_c)[pos]; + if (value != ref) { + if (errors < 100) { + printf("*** error: [%d] expected=%f, actual=%f\n", pos, ref, value); + } + ++errors; + } + } else { + int ref = h_a[i]; + for (int j = 0; j < size; ++j) { + int cur = h_a[j]; pos += (cur < ref) || (cur == ref && j < i); } - } - int value = h_c[pos]; - if (value != ref) { - if (errors < 100) { - if (float_enable) { - printf("*** error: [%d] expected=%f, actual=%f\n", pos, ref_f, *(float*)&value); - } else { + int value = h_c[pos]; + if (value != ref) { + if (errors < 100) { printf("*** error: [%d] expected=%d, actual=%d\n", pos, ref, value); } + ++errors; } - ++errors; } } if (0 == errors) { diff --git a/tests/opencl/saxpy/main.cc b/tests/opencl/saxpy/main.cc index 4ea15759..9355c945 100644 --- a/tests/opencl/saxpy/main.cc +++ b/tests/opencl/saxpy/main.cc @@ -151,16 +151,12 @@ int main(int argc, char **argv) { cl_platform_id platform_id; cl_device_id device_id; + cl_program program; cl_mem input_buffer; cl_mem output_buffer; size_t kernel_size; cl_context context; cl_command_queue queue; - cl_int binary_status = 0; - - // read kernel binary from file - if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) - return -1; // Getting platform and device information CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); @@ -172,19 +168,18 @@ int main(int argc, char **argv) { cl_kernel kernel = 0; cl_mem memObjects[2] = {0, 0}; - // Create OpenCL program - first attempt to load cached binary. - // If that is not available, then create the program from source - // and store the binary for future use. - printf("create program from binary...\n"); - cl_program program = CL_CHECK_ERR(clCreateProgramWithBinary( - context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &_err)); - if (program == NULL) { - std::cerr << "Failed to write program binary" << std::endl; - Cleanup(device_id, context, queue, program, kernel, memObjects); - return 1; - } else { - printf("Read program from binary.\n"); - } + printf("Create program from kernel source\n"); +#ifdef HOSTGPU + if (0 != read_kernel_file("kernel.cl", &kernel_bin, &kernel_size)) + return -1; + program = CL_CHECK_ERR(clCreateProgramWithSource( + context, 1, (const char**)&kernel_bin, &kernel_size, &_err)); +#else + if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) + return -1; + program = CL_CHECK_ERR(clCreateProgramWithBinary( + context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, NULL, &_err)); +#endif // Build program CL_CHECK(clBuildProgram(program, 1, &device_id, NULL, NULL, NULL)); diff --git a/tests/opencl/sfilter/main.cc b/tests/opencl/sfilter/main.cc index 3a7a5979..0ae264a5 100644 --- a/tests/opencl/sfilter/main.cc +++ b/tests/opencl/sfilter/main.cc @@ -149,14 +149,10 @@ int main(int argc, char **argv) { cl_platform_id platform_id; cl_device_id device_id; + cl_program program; size_t kernel_size; - cl_int binary_status = 0; uint8_t *kernel_bin = NULL; - // read kernel binary from file - if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) - return -1; - // Getting platform and device information CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); CL_CHECK(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL)); @@ -170,19 +166,18 @@ int main(int argc, char **argv) { cl_kernel kernel = 0; cl_mem memObjects[2] = {0, 0}; - // Create OpenCL program - first attempt to load cached binary. - // If that is not available, then create the program from source - // and store the binary for future use. - printf("create program from binary...\n"); - cl_program program = CL_CHECK_ERR(clCreateProgramWithBinary( - context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &_err)); - if (program == NULL) { - std::cerr << "Failed to write program binary" << std::endl; - Cleanup(kernel_bin, device_id, context, queue, program, kernel, memObjects); - return 1; - } else { - printf("Read program from binary."); - } + printf("Create program from kernel source\n"); +#ifdef HOSTGPU + if (0 != read_kernel_file("kernel.cl", &kernel_bin, &kernel_size)) + return -1; + program = CL_CHECK_ERR(clCreateProgramWithSource( + context, 1, (const char**)&kernel_bin, &kernel_size, &_err)); +#else + if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) + return -1; + program = CL_CHECK_ERR(clCreateProgramWithBinary( + context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, NULL, &_err)); +#endif // Build program CL_CHECK(clBuildProgram(program, 1, &device_id, NULL, NULL, NULL)); diff --git a/tests/opencl/sgemm/main.cc b/tests/opencl/sgemm/main.cc index 7a02929f..bc48dff0 100644 --- a/tests/opencl/sgemm/main.cc +++ b/tests/opencl/sgemm/main.cc @@ -185,13 +185,8 @@ int main (int argc, char **argv) { cl_platform_id platform_id; size_t kernel_size; - cl_int binary_status; srand(50); - - // read kernel binary from file - if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) - return -1; // Getting platform and device information CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); @@ -207,12 +202,17 @@ int main (int argc, char **argv) { c_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, nbytes, NULL, &_err)); printf("Create program from kernel source\n"); - program = CL_CHECK2(clCreateProgramWithBinary( - context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &_err)); - if (program == NULL) { - cleanup(); +#ifdef HOSTGPU + if (0 != read_kernel_file("kernel.cl", &kernel_bin, &kernel_size)) return -1; - } + program = CL_CHECK2(clCreateProgramWithSource( + context, 1, (const char**)&kernel_bin, &kernel_size, &_err)); +#else + if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) + return -1; + program = CL_CHECK2(clCreateProgramWithBinary( + context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, NULL, &_err)); +#endif // Build program CL_CHECK(clBuildProgram(program, 1, &device_id, NULL, NULL, NULL)); diff --git a/tests/opencl/vecadd/main.cc b/tests/opencl/vecadd/main.cc index 992e88be..e443f7c5 100644 --- a/tests/opencl/vecadd/main.cc +++ b/tests/opencl/vecadd/main.cc @@ -122,11 +122,6 @@ int main (int argc, char **argv) { cl_platform_id platform_id; size_t kernel_size; - cl_int binary_status; - - // read kernel binary from file - if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) - return -1; // Getting platform and device information CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); @@ -142,13 +137,17 @@ int main (int argc, char **argv) { c_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, nbytes, NULL, &_err)); printf("Create program from kernel source\n"); - cl_int _err; - program = clCreateProgramWithBinary( - context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &_err); - if (program == NULL) { - cleanup(); +#ifdef HOSTGPU + if (0 != read_kernel_file("kernel.cl", &kernel_bin, &kernel_size)) return -1; - } + program = CL_CHECK2(clCreateProgramWithSource( + context, 1, (const char**)&kernel_bin, &kernel_size, &_err)); +#else + if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) + return -1; + program = CL_CHECK2(clCreateProgramWithBinary( + context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, NULL, &_err)); +#endif // Build program CL_CHECK(clBuildProgram(program, 1, &device_id, NULL, NULL, NULL)); From 2c94e358b8d6cfacb360a18ea1810260507a685a Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 15 Nov 2023 00:52:39 -0800 Subject: [PATCH 08/57] perf counter bug fix --- hw/rtl/core/VX_core.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/rtl/core/VX_core.sv b/hw/rtl/core/VX_core.sv index d50a3d32..8aaea911 100644 --- a/hw/rtl/core/VX_core.sv +++ b/hw/rtl/core/VX_core.sv @@ -267,7 +267,7 @@ module VX_core import VX_gpu_pkg::*; #( wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_rsp_per_cycle; - wire perf_icache_pending_read_cycle; + wire [1:0] perf_icache_pending_read_cycle; wire [`CLOG2(DCACHE_NUM_REQS+1)+1-1:0] perf_dcache_pending_read_cycle; reg [`PERF_CTR_BITS-1:0] perf_icache_pending_reads; From 547d916ae25a207e31827b801635fb60e1e30162 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 15 Nov 2023 13:00:06 -0800 Subject: [PATCH 09/57] minor update --- hw/rtl/VX_config.vh | 8 ++++---- hw/syn/altera/opae/Makefile | 6 +++--- hw/syn/xilinx/xrt/Makefile | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 6ecb3cf4..9d4ea56d 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -223,18 +223,18 @@ // Number of ALU units `ifndef NUM_ALU_LANES -`define NUM_ALU_LANES `UP(`NUM_THREADS / 2) +`define NUM_ALU_LANES `NUM_THREADS `endif `ifndef NUM_ALU_BLOCKS -`define NUM_ALU_BLOCKS `UP(`ISSUE_WIDTH / 1) +`define NUM_ALU_BLOCKS `ISSUE_WIDTH `endif // Number of FPU units `ifndef NUM_FPU_LANES -`define NUM_FPU_LANES `UP(`NUM_THREADS / 2) +`define NUM_FPU_LANES `NUM_THREADS `endif `ifndef NUM_FPU_BLOCKS -`define NUM_FPU_BLOCKS `UP(`ISSUE_WIDTH / 1) +`define NUM_FPU_BLOCKS `ISSUE_WIDTH `endif // Number of LSU units diff --git a/hw/syn/altera/opae/Makefile b/hw/syn/altera/opae/Makefile index 0db2015d..56008d42 100644 --- a/hw/syn/altera/opae/Makefile +++ b/hw/syn/altera/opae/Makefile @@ -50,9 +50,9 @@ CONFIGS_1c := -DNUM_CLUSTERS=1 -DNUM_CORES=1 CONFIGS_2c := -DNUM_CLUSTERS=1 -DNUM_CORES=2 CONFIGS_4c := -DNUM_CLUSTERS=1 -DNUM_CORES=4 CONFIGS_8c := -DNUM_CLUSTERS=1 -DNUM_CORES=8 -CONFIGS_16c := -DNUM_CLUSTERS=1 -DNUM_CORES=16 -DL2_ENABLE -CONFIGS_32c := -DNUM_CLUSTERS=2 -DNUM_CORES=16 -DL2_ENABLE -CONFIGS_64c := -DNUM_CLUSTERS=4 -DNUM_CORES=16 -DL2_ENABLE +CONFIGS_16c := -DNUM_CLUSTERS=1 -DNUM_CORES=16 +CONFIGS_32c := -DNUM_CLUSTERS=2 -DNUM_CORES=16 +CONFIGS_64c := -DNUM_CLUSTERS=4 -DNUM_CORES=16 CONFIGS += $(CONFIGS_$(NUM_CORES)c) # include paths diff --git a/hw/syn/xilinx/xrt/Makefile b/hw/syn/xilinx/xrt/Makefile index c8714779..ad8e77a7 100644 --- a/hw/syn/xilinx/xrt/Makefile +++ b/hw/syn/xilinx/xrt/Makefile @@ -67,9 +67,9 @@ CONFIGS_1c := -DNUM_CLUSTERS=1 -DNUM_CORES=1 CONFIGS_2c := -DNUM_CLUSTERS=1 -DNUM_CORES=2 CONFIGS_4c := -DNUM_CLUSTERS=1 -DNUM_CORES=4 CONFIGS_8c := -DNUM_CLUSTERS=1 -DNUM_CORES=8 -CONFIGS_16c := -DNUM_CLUSTERS=1 -DNUM_CORES=16 -DL2_ENABLE -CONFIGS_32c := -DNUM_CLUSTERS=2 -DNUM_CORES=16 -DL2_ENABLE -CONFIGS_64c := -DNUM_CLUSTERS=4 -DNUM_CORES=16 -DL2_ENABLE +CONFIGS_16c := -DNUM_CLUSTERS=1 -DNUM_CORES=16 +CONFIGS_32c := -DNUM_CLUSTERS=2 -DNUM_CORES=16 +CONFIGS_64c := -DNUM_CLUSTERS=4 -DNUM_CORES=16 CONFIGS += $(CONFIGS_$(NUM_CORES)c) # include paths From d65cc61df57b99a8a9226474e53ba5ba34819e9a Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Thu, 16 Nov 2023 12:00:37 -0800 Subject: [PATCH 10/57] minor update --- hw/rtl/VX_config.vh | 6 +- hw/rtl/cache/VX_cache_cluster_top.sv | 190 --------------------------- hw/rtl/cache/VX_cache_data.sv | 2 +- hw/rtl/cache/VX_cache_top.sv | 2 +- hw/syn/altera/quartus/cache/Makefile | 4 +- hw/syn/altera/quartus/core/Makefile | 2 +- 6 files changed, 8 insertions(+), 198 deletions(-) delete mode 100644 hw/rtl/cache/VX_cache_cluster_top.sv diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 9d4ea56d..c7b2a2c3 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -407,7 +407,7 @@ // Number of Associative Ways `ifndef ICACHE_NUM_WAYS -`define ICACHE_NUM_WAYS 2 +`define ICACHE_NUM_WAYS 1 `endif // Dcache Configurable Knobs ////////////////////////////////////////////////// @@ -461,7 +461,7 @@ // Number of Associative Ways `ifndef DCACHE_NUM_WAYS -`define DCACHE_NUM_WAYS 2 +`define DCACHE_NUM_WAYS 1 `endif // SM Configurable Knobs ////////////////////////////////////////////////////// @@ -520,7 +520,7 @@ // Number of Associative Ways `ifndef L2_NUM_WAYS -`define L2_NUM_WAYS 4 +`define L2_NUM_WAYS 2 `endif // L3cache Configurable Knobs ///////////////////////////////////////////////// diff --git a/hw/rtl/cache/VX_cache_cluster_top.sv b/hw/rtl/cache/VX_cache_cluster_top.sv deleted file mode 100644 index 500f2c87..00000000 --- a/hw/rtl/cache/VX_cache_cluster_top.sv +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright © 2019-2023 -// -// Licensed 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. - -`include "VX_cache_define.vh" - -module VX_cache_cluster_top import VX_gpu_pkg::*; #( - parameter `STRING INSTANCE_ID = "", - - parameter NUM_UNITS = 2, - parameter NUM_INPUTS = 4, - parameter TAG_SEL_IDX = 0, - - // Number of Word requests per cycle - parameter NUM_REQS = 4, - - // Size of cache in bytes - parameter CACHE_SIZE = 16384, - // Size of line inside a bank in bytes - parameter LINE_SIZE = 16, - // Number of banks - parameter NUM_BANKS = 4, - // Number of associative ways - parameter NUM_WAYS = 4, - // Size of a word in bytes - parameter WORD_SIZE = 4, - - // Core Response Queue Size - parameter CRSQ_SIZE = 2, - // Miss Reserv Queue Knob - parameter MSHR_SIZE = 16, - // Memory Response Queue Size - parameter MRSQ_SIZE = 0, - // Memory Request Queue Size - parameter MREQ_SIZE = 4, - - // Enable cache writeable - parameter WRITE_ENABLE = 1, - - // Request debug identifier - parameter UUID_WIDTH = 0, - - // core request tag size - parameter TAG_WIDTH = UUID_WIDTH + 16, - - // enable bypass for non-cacheable addresses - parameter NC_ENABLE = 1, - - // Core response output register - parameter CORE_OUT_REG = 2, - - // Memory request output register - parameter MEM_OUT_REG = 2, - - parameter NUM_CACHES = `UP(NUM_UNITS), - parameter PASSTHRU = (NUM_UNITS == 0), - parameter ARB_TAG_WIDTH = TAG_WIDTH + `ARB_SEL_BITS(NUM_INPUTS, NUM_CACHES), - parameter MEM_TAG_WIDTH = PASSTHRU ? (NC_ENABLE ? `CACHE_NC_BYPASS_TAG_WIDTH(NUM_REQS, LINE_SIZE, WORD_SIZE, ARB_TAG_WIDTH) : - `CACHE_BYPASS_TAG_WIDTH(NUM_REQS, LINE_SIZE, WORD_SIZE, ARB_TAG_WIDTH)) : - (NC_ENABLE ? `CACHE_NC_MEM_TAG_WIDTH(MSHR_SIZE, NUM_BANKS, NUM_REQS, LINE_SIZE, WORD_SIZE, ARB_TAG_WIDTH) : - `CACHE_MEM_TAG_WIDTH(MSHR_SIZE, NUM_BANKS)), - parameter MEM_TAG_X_WIDTH = MEM_TAG_WIDTH + `ARB_SEL_BITS(NUM_CACHES, 1) - ) ( - input wire clk, - input wire reset, - -// PERF -`ifdef PERF_ENABLE - output cache_perf_t cache_perf, -`endif - - // Core request - input wire [NUM_INPUTS-1:0][NUM_REQS-1:0] core_req_valid, - input wire [NUM_INPUTS-1:0][NUM_REQS-1:0] core_req_rw, - input wire [NUM_INPUTS-1:0][NUM_REQS-1:0][WORD_SIZE-1:0] core_req_byteen, - input wire [NUM_INPUTS-1:0][NUM_REQS-1:0][`CS_WORD_ADDR_WIDTH-1:0] core_req_addr, - input wire [NUM_INPUTS-1:0][NUM_REQS-1:0][`CS_WORD_WIDTH-1:0] core_req_data, - input wire [NUM_INPUTS-1:0][NUM_REQS-1:0][TAG_WIDTH-1:0] core_req_tag, - output wire [NUM_INPUTS-1:0][NUM_REQS-1:0] core_req_ready, - - // Core response - output wire [NUM_INPUTS-1:0][NUM_REQS-1:0] core_rsp_valid, - output wire [NUM_INPUTS-1:0][NUM_REQS-1:0][`CS_WORD_WIDTH-1:0] core_rsp_data, - output wire [NUM_INPUTS-1:0][NUM_REQS-1:0][TAG_WIDTH-1:0] core_rsp_tag, - input wire [NUM_INPUTS-1:0][NUM_REQS-1:0] core_rsp_ready, - - // Memory request - output wire mem_req_valid, - output wire mem_req_rw, - output wire [LINE_SIZE-1:0] mem_req_byteen, - output wire [`CS_MEM_ADDR_WIDTH-1:0] mem_req_addr, - output wire [`CS_LINE_WIDTH-1:0] mem_req_data, - output wire [MEM_TAG_X_WIDTH-1:0] mem_req_tag, - input wire mem_req_ready, - - // Memory response - input wire mem_rsp_valid, - input wire [`CS_LINE_WIDTH-1:0] mem_rsp_data, - input wire [MEM_TAG_X_WIDTH-1:0] mem_rsp_tag, - output wire mem_rsp_ready -); - VX_mem_bus_if #( - .DATA_SIZE (WORD_SIZE), - .TAG_WIDTH (TAG_WIDTH) - ) core_bus_if[NUM_INPUTS * NUM_REQS](); - - VX_mem_bus_if #( - .DATA_SIZE (LINE_SIZE), - .TAG_WIDTH (MEM_TAG_X_WIDTH) - ) mem_bus_if(); - - // Core request - for (genvar i = 0; i < NUM_INPUTS; ++i) begin - for (genvar r = 0; r < NUM_REQS; ++r) begin - assign core_bus_if[i * NUM_REQS + r].req_valid = core_req_valid[i][r]; - assign core_bus_if[i * NUM_REQS + r].req_data.rw = core_req_rw[i][r]; - assign core_bus_if[i * NUM_REQS + r].req_data.byteen = core_req_byteen[i][r]; - assign core_bus_if[i * NUM_REQS + r].req_data.addr = core_req_addr[i][r]; - assign core_bus_if[i * NUM_REQS + r].req_data.data = core_req_data[i][r]; - assign core_bus_if[i * NUM_REQS + r].req_data.tag = core_req_tag[i][r]; - assign core_req_ready[i][r] = core_bus_if[i * NUM_REQS + r].req_ready; - end - end - - // Core response - for (genvar i = 0; i < NUM_INPUTS; ++i) begin - for (genvar r = 0; r < NUM_REQS; ++r) begin - assign core_rsp_valid[i][r] = core_bus_if[i * NUM_REQS + r].rsp_valid; - assign core_rsp_data[i][r] = core_bus_if[i * NUM_REQS + r].rsp_data.data; - assign core_rsp_tag[i][r] = core_bus_if[i * NUM_REQS + r].rsp_data.tag; - assign core_bus_if[i * NUM_REQS + r].rsp_ready = core_rsp_ready[i][r]; - end - end - - // Memory request - assign mem_req_valid = mem_bus_if.req_valid; - assign mem_req_rw = mem_bus_if.req_data.rw; - assign mem_req_byteen = mem_bus_if.req_data.byteen; - assign mem_req_addr = mem_bus_if.req_data.addr; - assign mem_req_data = mem_bus_if.req_data.data; - assign mem_req_tag = mem_bus_if.req_data.tag; - assign mem_bus_if.req_ready = mem_req_ready; - - // Memory response - assign mem_bus_if.rsp_valid = mem_rsp_valid; - assign mem_bus_if.rsp_data.data = mem_rsp_data; - assign mem_bus_if.rsp_data.tag = mem_rsp_tag; - assign mem_rsp_ready = mem_bus_if.rsp_ready; - - VX_cache_cluster #( - .INSTANCE_ID (INSTANCE_ID), - .NUM_UNITS (NUM_UNITS), - .NUM_INPUTS (NUM_INPUTS), - .TAG_SEL_IDX (TAG_SEL_IDX), - .NUM_REQS (NUM_REQS), - .CACHE_SIZE (CACHE_SIZE), - .LINE_SIZE (LINE_SIZE), - .NUM_BANKS (NUM_BANKS), - .NUM_WAYS (NUM_WAYS), - .WORD_SIZE (WORD_SIZE), - .CRSQ_SIZE (CRSQ_SIZE), - .MSHR_SIZE (MSHR_SIZE), - .MRSQ_SIZE (MRSQ_SIZE), - .MREQ_SIZE (MREQ_SIZE), - .WRITE_ENABLE (WRITE_ENABLE), - .UUID_WIDTH (UUID_WIDTH), - .TAG_WIDTH (TAG_WIDTH), - .NC_ENABLE (NC_ENABLE), - .CORE_OUT_REG (CORE_OUT_REG), - .MEM_OUT_REG (MEM_OUT_REG) - ) cache ( - `ifdef PERF_ENABLE - .cache_perf (cache_perf), - `endif - .clk (clk), - .reset (reset), - .core_bus_if (core_bus_if), - .mem_bus_if (mem_bus_if) - ); - -endmodule diff --git a/hw/rtl/cache/VX_cache_data.sv b/hw/rtl/cache/VX_cache_data.sv index 493e4884..5106d7d5 100644 --- a/hw/rtl/cache/VX_cache_data.sv +++ b/hw/rtl/cache/VX_cache_data.sv @@ -93,7 +93,7 @@ module VX_cache_data #( assign wren = fill; end - wire [`CLOG2(NUM_WAYS)-1:0] way_idx; + wire [`LOG2UP(NUM_WAYS)-1:0] way_idx; VX_onehot_encoder #( .N (NUM_WAYS) diff --git a/hw/rtl/cache/VX_cache_top.sv b/hw/rtl/cache/VX_cache_top.sv index 9e36d9af..9be08dde 100644 --- a/hw/rtl/cache/VX_cache_top.sv +++ b/hw/rtl/cache/VX_cache_top.sv @@ -22,7 +22,7 @@ module VX_cache_top #( // Size of cache in bytes parameter CACHE_SIZE = 16384, // Size of line inside a bank in bytes - parameter LINE_SIZE = 16, + parameter LINE_SIZE = 64, // Number of banks parameter NUM_BANKS = 4, // Number of associative ways diff --git a/hw/syn/altera/quartus/cache/Makefile b/hw/syn/altera/quartus/cache/Makefile index 258dc91a..f96a7614 100755 --- a/hw/syn/altera/quartus/cache/Makefile +++ b/hw/syn/altera/quartus/cache/Makefile @@ -1,6 +1,6 @@ -PROJECT = VX_cache_cluster_top +PROJECT = VX_cache_top TOP_LEVEL_ENTITY = $(PROJECT) -SRC_FILE = VX_cache_cluster.sv +SRC_FILE = $(PROJECT).sv include ../../common.mk diff --git a/hw/syn/altera/quartus/core/Makefile b/hw/syn/altera/quartus/core/Makefile index f1dc07f3..eeeaa523 100644 --- a/hw/syn/altera/quartus/core/Makefile +++ b/hw/syn/altera/quartus/core/Makefile @@ -1,6 +1,6 @@ PROJECT = VX_core_top TOP_LEVEL_ENTITY = $(PROJECT) -SRC_FILE = VX_core.sv +SRC_FILE = $(PROJECT).sv include ../../common.mk From 43154cf738b9dfe91afc53c926e3734e02bd9ab6 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Thu, 16 Nov 2023 23:41:59 -0800 Subject: [PATCH 11/57] minor updates --- hw/rtl/core/VX_sfu_unit.sv | 4 +-- hw/syn/altera/opae/Makefile | 6 ++--- hw/syn/xilinx/xrt/Makefile | 6 ++--- hw/unittest/top_modules/Makefile | 1 - tests/opencl/Makefile | 12 ++++----- tests/opencl/lbm/main.cc | 4 --- tests/opencl/spmv/convert_dataset.c | 4 --- tests/opencl/spmv/main.cc | 3 --- tests/opencl/stencil/main.cc | 38 +++++++++-------------------- 9 files changed, 25 insertions(+), 53 deletions(-) diff --git a/hw/rtl/core/VX_sfu_unit.sv b/hw/rtl/core/VX_sfu_unit.sv index e94f86fd..fd5dd59f 100644 --- a/hw/rtl/core/VX_sfu_unit.sv +++ b/hw/rtl/core/VX_sfu_unit.sv @@ -170,7 +170,7 @@ module VX_sfu_unit import VX_gpu_pkg::*; #( .NUM_INPUTS (RSP_ARB_SIZE), .DATAW (RSP_ARB_DATAW), .ARBITER ("R"), - .OUT_REG (1) + .OUT_REG (3) ) rsp_arb ( .clk (clk), .reset (commit_reset), @@ -186,7 +186,7 @@ module VX_sfu_unit import VX_gpu_pkg::*; #( VX_gather_unit #( .BLOCK_SIZE (BLOCK_SIZE), .NUM_LANES (NUM_LANES), - .OUT_REG (3) + .OUT_REG (1) ) gather_unit ( .clk (clk), .reset (commit_reset), diff --git a/hw/syn/altera/opae/Makefile b/hw/syn/altera/opae/Makefile index 56008d42..0db2015d 100644 --- a/hw/syn/altera/opae/Makefile +++ b/hw/syn/altera/opae/Makefile @@ -50,9 +50,9 @@ CONFIGS_1c := -DNUM_CLUSTERS=1 -DNUM_CORES=1 CONFIGS_2c := -DNUM_CLUSTERS=1 -DNUM_CORES=2 CONFIGS_4c := -DNUM_CLUSTERS=1 -DNUM_CORES=4 CONFIGS_8c := -DNUM_CLUSTERS=1 -DNUM_CORES=8 -CONFIGS_16c := -DNUM_CLUSTERS=1 -DNUM_CORES=16 -CONFIGS_32c := -DNUM_CLUSTERS=2 -DNUM_CORES=16 -CONFIGS_64c := -DNUM_CLUSTERS=4 -DNUM_CORES=16 +CONFIGS_16c := -DNUM_CLUSTERS=1 -DNUM_CORES=16 -DL2_ENABLE +CONFIGS_32c := -DNUM_CLUSTERS=2 -DNUM_CORES=16 -DL2_ENABLE +CONFIGS_64c := -DNUM_CLUSTERS=4 -DNUM_CORES=16 -DL2_ENABLE CONFIGS += $(CONFIGS_$(NUM_CORES)c) # include paths diff --git a/hw/syn/xilinx/xrt/Makefile b/hw/syn/xilinx/xrt/Makefile index ad8e77a7..c8714779 100644 --- a/hw/syn/xilinx/xrt/Makefile +++ b/hw/syn/xilinx/xrt/Makefile @@ -67,9 +67,9 @@ CONFIGS_1c := -DNUM_CLUSTERS=1 -DNUM_CORES=1 CONFIGS_2c := -DNUM_CLUSTERS=1 -DNUM_CORES=2 CONFIGS_4c := -DNUM_CLUSTERS=1 -DNUM_CORES=4 CONFIGS_8c := -DNUM_CLUSTERS=1 -DNUM_CORES=8 -CONFIGS_16c := -DNUM_CLUSTERS=1 -DNUM_CORES=16 -CONFIGS_32c := -DNUM_CLUSTERS=2 -DNUM_CORES=16 -CONFIGS_64c := -DNUM_CLUSTERS=4 -DNUM_CORES=16 +CONFIGS_16c := -DNUM_CLUSTERS=1 -DNUM_CORES=16 -DL2_ENABLE +CONFIGS_32c := -DNUM_CLUSTERS=2 -DNUM_CORES=16 -DL2_ENABLE +CONFIGS_64c := -DNUM_CLUSTERS=4 -DNUM_CORES=16 -DL2_ENABLE CONFIGS += $(CONFIGS_$(NUM_CORES)c) # include paths diff --git a/hw/unittest/top_modules/Makefile b/hw/unittest/top_modules/Makefile index 2d0319e7..7445381e 100644 --- a/hw/unittest/top_modules/Makefile +++ b/hw/unittest/top_modules/Makefile @@ -56,7 +56,6 @@ PROJECT = top_modules all: build build: $(SRCS) - verilator --build $(VL_FLAGS) --cc VX_cache_cluster_top --top-module VX_cache_cluster_top $^ -CFLAGS '$(CXXFLAGS)' verilator --build $(VL_FLAGS) --cc VX_cache_top --top-module VX_cache_top $^ -CFLAGS '$(CXXFLAGS)' verilator --build $(VL_FLAGS) --cc VX_core_top --top-module VX_core_top $^ -CFLAGS '$(CXXFLAGS)' diff --git a/tests/opencl/Makefile b/tests/opencl/Makefile index acb96ba9..88236559 100644 --- a/tests/opencl/Makefile +++ b/tests/opencl/Makefile @@ -31,16 +31,16 @@ run-simx: $(MAKE) -C dotproduct run-simx $(MAKE) -C kmeans run-simx $(MAKE) -C spmv run-simx - $(MAKE) -C cutcp run-simx $(MAKE) -C stencil run-simx $(MAKE) -C lbm run-simx $(MAKE) -C oclprintf run-simx $(MAKE) -C blackscholes run-simx $(MAKE) -C transpose run-simx $(MAKE) -C convolution run-simx -# $(MAKE) -C matmul run-simx -# $(MAKE) -C vectorhypot run-simx -# $(MAKE) -C mri-q run-simx + $(MAKE) -C cutcp run-simx + $(MAKE) -C matmul run-simx + $(MAKE) -C vectorhypot run-simx + $(MAKE) -C mri-q run-simx run-rtlsim: $(MAKE) -C vecadd run-rtlsim @@ -54,12 +54,12 @@ run-rtlsim: $(MAKE) -C kmeans run-rtlsim $(MAKE) -C spmv run-rtlsim $(MAKE) -C transpose run-rtlsim - $(MAKE) -C cutcp run-rtlsim $(MAKE) -C stencil run-rtlsim $(MAKE) -C lbm run-rtlsim $(MAKE) -C oclprintf run-rtlsim $(MAKE) -C blackscholes run-rtlsim $(MAKE) -C convolution run-rtlsim +# $(MAKE) -C cutcp run-rtlsim # $(MAKE) -C matmul run-rtlsim # $(MAKE) -C vectorhypot run-rtlsim # $(MAKE) -C mri-q run-rtlsim @@ -76,12 +76,12 @@ run-opae: $(MAKE) -C kmeans run-opae $(MAKE) -C spmv run-opae $(MAKE) -C transpose run-opae - $(MAKE) -C cutcp run-opae $(MAKE) -C stencil run-opae $(MAKE) -C lbm run-opae $(MAKE) -C oclprintf run-opae $(MAKE) -C blackscholes run-opae $(MAKE) -C convolution run-opae +# $(MAKE) -C cutcp run-opae # $(MAKE) -C matmul run-opae # $(MAKE) -C vectorhypot run-opae # $(MAKE) -C mri-q run-opae diff --git a/tests/opencl/lbm/main.cc b/tests/opencl/lbm/main.cc index 1d825239..58a930e9 100644 --- a/tests/opencl/lbm/main.cc +++ b/tests/opencl/lbm/main.cc @@ -173,14 +173,10 @@ void MAIN_initialize(const MAIN_Param *param, const OpenCL_Param *prm) { pb_SwitchToTimer(&timers, pb_TimerID_COPY); - printf("OK+\n"); - // Setup DEVICE datastructures OpenCL_LBM_allocateGrid(prm, &OpenCL_srcGrid); OpenCL_LBM_allocateGrid(prm, &OpenCL_dstGrid); - printf("OK-\n"); - // Initialize DEVICE datastructures OpenCL_LBM_initializeGrid(prm, OpenCL_srcGrid, TEMP_srcGrid); OpenCL_LBM_initializeGrid(prm, OpenCL_dstGrid, TEMP_dstGrid); diff --git a/tests/opencl/spmv/convert_dataset.c b/tests/opencl/spmv/convert_dataset.c index 122d8819..aba9c3b3 100644 --- a/tests/opencl/spmv/convert_dataset.c +++ b/tests/opencl/spmv/convert_dataset.c @@ -91,15 +91,11 @@ int coo_to_jds(char *mtx_filename, int pad_rows, int warp_size, int pack_size, if ((f = fopen(mtx_filename, "r")) == NULL) exit(1); - printf("OK**\n"); - if (mm_read_banner(f, &matcode) != 0) { printf("Could not process Matrix Market banner.\n"); exit(1); } - printf("OK**\n"); - /* This is how one can screen matrix types if their application */ /* only supports a subset of the Matrix Market data types. */ diff --git a/tests/opencl/spmv/main.cc b/tests/opencl/spmv/main.cc index 85182322..01aa43cd 100644 --- a/tests/opencl/spmv/main.cc +++ b/tests/opencl/spmv/main.cc @@ -148,7 +148,6 @@ int main(int argc, char **argv) { // &h_data, &h_indices, &h_ptr, // &h_perm, &h_nzcnt); int col_count; - printf("OK--\n"); coo_to_jds(parameters->inpFiles[0], // bcsstk32.mtx, fidapm05.mtx, jgl009.mtx 1, // row padding pad, // warp size @@ -159,8 +158,6 @@ int main(int argc, char **argv) { &h_data, &h_ptr, &h_nzcnt, &h_indices, &h_perm, &col_count, &dim, &len, &nzcnt_len, &depth); - printf("OK++\n"); - // pb_SwitchToTimer(&timers, pb_TimerID_COMPUTE); h_Ax_vector = (float *)malloc(sizeof(float) * dim); h_x_vector = (float *)malloc(sizeof(float) * dim); diff --git a/tests/opencl/stencil/main.cc b/tests/opencl/stencil/main.cc index a68bd5a3..cbbed6bc 100644 --- a/tests/opencl/stencil/main.cc +++ b/tests/opencl/stencil/main.cc @@ -157,9 +157,7 @@ int main(int argc, char** argv) { CHECK_ERROR("clBuildProgram") cl_kernel clKernel = clCreateKernel(clProgram,"naive_kernel",&clStatus); - CHECK_ERROR("clCreateKernel") - - printf("OK+\n"); + CHECK_ERROR("clCreateKernel") //host data float *h_A0; @@ -177,15 +175,11 @@ int main(int argc, char** argv) { h_Anext=(float*)malloc(sizeof(float)*size); pb_SwitchToTimer(&timers, pb_TimerID_IO); //FILE *fp = fopen(parameters->inpFiles[0], "rb"); - printf("OK+\n"); read_data(h_A0, nx,ny,nz,NULL); - printf("OK+\n"); - //fclose(fp); - memcpy (h_Anext,h_A0,sizeof(float)*size); + //fclose(fp); + memcpy (h_Anext,h_A0,sizeof(float)*size); pb_SwitchToTimer(&timers, pb_TimerID_COPY); - - printf("OK+\n"); //memory allocation d_A0 = clCreateBuffer(clContext,CL_MEM_READ_WRITE,size*sizeof(float),NULL,&clStatus); @@ -201,18 +195,16 @@ int main(int argc, char** argv) { pb_SwitchToTimer(&timers, pb_TimerID_COMPUTE); - printf("OK+\n"); - //only use 1D thread block - int tx = 128; + int tx = 128; size_t block[3] = {tx,1,1}; size_t grid[3] = {(nx-2+tx-1)/tx*tx,ny-2,nz-2}; - //size_t grid[3] = {nx-2,ny-2,nz-2}; - size_t offset[3] = {1,1,1}; - printf("grid size in x/y/z = %d %d %d\n",grid[0],grid[1],grid[2]); + //size_t grid[3] = {nx-2,ny-2,nz-2}; + size_t offset[3] = {1,1,1}; + printf("grid size in x/y/z = %d %d %d\n",grid[0],grid[1],grid[2]); printf("block size in x/y/z = %d %d %d\n",block[0],block[1],block[2]); - printf ("blocks = %d\n", (grid[0]/block[0])*(grid[1]/block[1])*(grid[2]*block[2])); + printf ("blocks = %d\n", (grid[0]/block[0])*(grid[1]/block[1])*(grid[2]*block[2])); clStatus = clSetKernelArg(clKernel,0,sizeof(float),(void*)&c0); clStatus = clSetKernelArg(clKernel,1,sizeof(float),(void*)&c1); @@ -226,14 +218,10 @@ int main(int argc, char** argv) { //main execution pb_SwitchToTimer(&timers, pb_TimerID_KERNEL); - printf("OK+0\n"); - int t; for(t=0;toutFile) { pb_SwitchToTimer(&timers, pb_TimerID_IO); From 2f1171ca76c4c4c73f8959117c0708bf87ca3896 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 27 Nov 2023 02:04:22 -0800 Subject: [PATCH 12/57] minor update --- tests/opencl/common.mk | 5 ++- tests/opencl/matmul/kernel.cl | 3 ++ tests/regression/tensor/main.cpp | 77 +++++++++++++++----------------- 3 files changed, 44 insertions(+), 41 deletions(-) diff --git a/tests/opencl/common.mk b/tests/opencl/common.mk index 762712b4..cfb436a6 100644 --- a/tests/opencl/common.mk +++ b/tests/opencl/common.mk @@ -73,7 +73,7 @@ OBJS := $(addsuffix .o, $(notdir $(SRCS))) all: $(PROJECT) kernel.pocl kernel.pocl: kernel.cl - LLVM_PREFIX=$(LLVM_VORTEX) POCL_DEBUG=all LD_LIBRARY_PATH=$(LLVM_POCL)/lib:$(POCL_CC_PATH)/lib:$(LLVM_VORTEX)/lib POCL_VORTEX_CFLAGS="$(K_CFLAGS)" POCL_VORTEX_LDFLAGS="$(K_LDFLAGS)" $(POCL_CC_PATH)/bin/poclcc -o kernel.pocl kernel.cl + LD_LIBRARY_PATH=$(LLVM_POCL)/lib:$(POCL_CC_PATH)/lib:$(LLVM_VORTEX)/lib:$(LD_LIBRARY_PATH) LLVM_PREFIX=$(LLVM_VORTEX) POCL_DEBUG=all POCL_VORTEX_CFLAGS="$(K_CFLAGS)" POCL_VORTEX_LDFLAGS="$(K_LDFLAGS)" $(POCL_CC_PATH)/bin/poclcc -o kernel.pocl kernel.cl %.cc.o: %.cc $(CXX) $(CXXFLAGS) -c $< -o $@ @@ -87,6 +87,9 @@ kernel.pocl: kernel.cl $(PROJECT): $(OBJS) $(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ +run-hostgpu: $(PROJECT) kernel.pocl + ./$(PROJECT) $(OPTS) + run-simx: $(PROJECT) kernel.pocl LD_LIBRARY_PATH=$(POCL_RT_PATH)/lib:$(VORTEX_RT_PATH)/simx:$(LD_LIBRARY_PATH) ./$(PROJECT) $(OPTS) diff --git a/tests/opencl/matmul/kernel.cl b/tests/opencl/matmul/kernel.cl index 02aa074c..007a233f 100644 --- a/tests/opencl/matmul/kernel.cl +++ b/tests/opencl/matmul/kernel.cl @@ -28,6 +28,9 @@ __kernel void matmul(__global float *A, for (int j = 0; j < localSize; j++) { sum += localA[localRow * localSize + j] * localB[j * localSize + localCol]; } + + // Ensure computation is done before loading next block + barrier(CLK_LOCAL_MEM_FENCE); } C[globalRow * N + globalCol] = sum; diff --git a/tests/regression/tensor/main.cpp b/tests/regression/tensor/main.cpp index 81103c10..23008011 100644 --- a/tests/regression/tensor/main.cpp +++ b/tests/regression/tensor/main.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "common.h" @@ -122,43 +123,6 @@ void cleanup() { } } -int run_test(const kernel_arg_t& kernel_arg, - uint32_t buf_size, - const std::vector& refs) { - // start device - std::cout << "start device" << std::endl; - RT_CHECK(vx_start(device)); - - // wait for completion - std::cout << "wait for completion" << std::endl; - RT_CHECK(vx_ready_wait(device, VX_MAX_TIMEOUT)); - - // download destination buffer - std::cout << "download destination buffer" << std::endl; - RT_CHECK(vx_copy_from_dev(device, staging_buf.data(), kernel_arg.C_addr, buf_size)); - - // verify result - std::cout << "verify result" << std::endl; - { - int errors = 0; - auto buf_ptr = (TYPE*)staging_buf.data(); - for (uint32_t i = 0; i < refs.size(); ++i) { - auto ref = refs[i]; - auto cur = buf_ptr[i]; - if (!Comparator::compare(cur, ref, i, errors)) { - ++errors; - } - } - if (errors != 0) { - std::cout << "Found " << std::dec << errors << " errors!" << std::endl; - std::cout << "FAILED!" << std::endl; - return 1; - } - } - - return 0; -} - int main(int argc, char *argv[]) { // parse command arguments parse_args(argc, argv); @@ -239,10 +203,43 @@ int main(int argc, char *argv[]) { std::cout << "clear destination buffer" << std::endl; memset(staging_buf.data(), 0, num_points * sizeof(TYPE)); RT_CHECK(vx_copy_to_dev(device, kernel_arg.C_addr, staging_buf.data(), buf_size)); + + auto time_start = std::chrono::high_resolution_clock::now(); - // run tests - std::cout << "run tests" << std::endl; - RT_CHECK(run_test(kernel_arg, buf_size, refs)); + // start device + std::cout << "start device" << std::endl; + RT_CHECK(vx_start(device)); + + // wait for completion + std::cout << "wait for completion" << std::endl; + RT_CHECK(vx_ready_wait(device, VX_MAX_TIMEOUT)); + + auto time_end = std::chrono::high_resolution_clock::now(); + double elapsed = std::chrono::duration_cast(time_end - time_start).count(); + printf("Elapsed time: %lg ms\n", elapsed); + + // download destination buffer + std::cout << "download destination buffer" << std::endl; + RT_CHECK(vx_copy_from_dev(device, staging_buf.data(), kernel_arg.C_addr, buf_size)); + + // verify result + std::cout << "verify result" << std::endl; + { + int errors = 0; + auto buf_ptr = (TYPE*)staging_buf.data(); + for (uint32_t i = 0; i < refs.size(); ++i) { + auto ref = refs[i]; + auto cur = buf_ptr[i]; + if (!Comparator::compare(cur, ref, i, errors)) { + ++errors; + } + } + if (errors != 0) { + std::cout << "Found " << std::dec << errors << " errors!" << std::endl; + std::cout << "FAILED!" << std::endl; + return 1; + } + } // cleanup std::cout << "cleanup" << std::endl; From ebec9824346809b6bb5f3e5b69a8ca6aeb409a65 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 27 Nov 2023 02:04:53 -0800 Subject: [PATCH 13/57] minor update --- hw/rtl/core/VX_ipdom_stack.sv | 6 +++--- hw/rtl/libs/VX_avs_adapter.sv | 4 ++-- hw/rtl/libs/VX_axi_adapter.sv | 2 +- hw/rtl/libs/VX_mem_adapter.sv | 4 ++-- hw/rtl/libs/VX_stream_arb.sv | 2 +- hw/rtl/libs/VX_stream_xbar.sv | 2 +- hw/rtl/mem/VX_gbar_arb.sv | 2 +- hw/rtl/mem/VX_mem_arb.sv | 4 ++-- hw/rtl/mem/VX_smem_switch.sv | 4 ++-- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/hw/rtl/core/VX_ipdom_stack.sv b/hw/rtl/core/VX_ipdom_stack.sv index a6524b2d..b6763f7e 100644 --- a/hw/rtl/core/VX_ipdom_stack.sv +++ b/hw/rtl/core/VX_ipdom_stack.sv @@ -14,10 +14,10 @@ `include "VX_platform.vh" module VX_ipdom_stack #( - parameter WIDTH = 1, - parameter DEPTH = 1, + parameter WIDTH = 1, + parameter DEPTH = 1, parameter OUT_REG = 0, - parameter ADDRW = `LOG2UP(DEPTH) + parameter ADDRW = `LOG2UP(DEPTH) ) ( input wire clk, input wire reset, diff --git a/hw/rtl/libs/VX_avs_adapter.sv b/hw/rtl/libs/VX_avs_adapter.sv index 779eb45e..4ea53757 100644 --- a/hw/rtl/libs/VX_avs_adapter.sv +++ b/hw/rtl/libs/VX_avs_adapter.sv @@ -21,8 +21,8 @@ module VX_avs_adapter #( parameter NUM_BANKS = 1, parameter TAG_WIDTH = 1, parameter RD_QUEUE_SIZE = 1, - parameter OUT_REG_REQ = 0, - parameter OUT_REG_RSP = 0 + parameter OUT_REG_REQ = 0, + parameter OUT_REG_RSP = 0 ) ( input wire clk, input wire reset, diff --git a/hw/rtl/libs/VX_axi_adapter.sv b/hw/rtl/libs/VX_axi_adapter.sv index 967c3af1..c5919b7a 100644 --- a/hw/rtl/libs/VX_axi_adapter.sv +++ b/hw/rtl/libs/VX_axi_adapter.sv @@ -20,7 +20,7 @@ module VX_axi_adapter #( parameter TAG_WIDTH = 8, parameter NUM_BANKS = 1, parameter AVS_ADDR_WIDTH = (ADDR_WIDTH - `CLOG2(DATA_WIDTH/8)), - parameter OUT_REG_RSP = 0 + parameter OUT_REG_RSP = 0 ) ( input wire clk, input wire reset, diff --git a/hw/rtl/libs/VX_mem_adapter.sv b/hw/rtl/libs/VX_mem_adapter.sv index 19d65240..ed983836 100644 --- a/hw/rtl/libs/VX_mem_adapter.sv +++ b/hw/rtl/libs/VX_mem_adapter.sv @@ -21,8 +21,8 @@ module VX_mem_adapter #( parameter DST_ADDR_WIDTH = 1, parameter SRC_TAG_WIDTH = 1, parameter DST_TAG_WIDTH = 1, - parameter OUT_REG_REQ = 0, - parameter OUT_REG_RSP = 0 + parameter OUT_REG_REQ = 0, + parameter OUT_REG_RSP = 0 ) ( input wire clk, input wire reset, diff --git a/hw/rtl/libs/VX_stream_arb.sv b/hw/rtl/libs/VX_stream_arb.sv index 58da0b25..a81be3ef 100644 --- a/hw/rtl/libs/VX_stream_arb.sv +++ b/hw/rtl/libs/VX_stream_arb.sv @@ -21,7 +21,7 @@ module VX_stream_arb #( parameter `STRING ARBITER = "P", parameter LOCK_ENABLE = 1, parameter MAX_FANOUT = `MAX_FANOUT, - parameter OUT_REG = 0 , + parameter OUT_REG = 0 , parameter NUM_REQS = (NUM_INPUTS + NUM_OUTPUTS - 1) / NUM_OUTPUTS, parameter LOG_NUM_REQS = `CLOG2(NUM_REQS), parameter NUM_REQS_W = `UP(LOG_NUM_REQS) diff --git a/hw/rtl/libs/VX_stream_xbar.sv b/hw/rtl/libs/VX_stream_xbar.sv index db92cfd0..a7de9341 100644 --- a/hw/rtl/libs/VX_stream_xbar.sv +++ b/hw/rtl/libs/VX_stream_xbar.sv @@ -22,7 +22,7 @@ module VX_stream_xbar #( parameter OUT_WIDTH = `LOG2UP(NUM_OUTPUTS), parameter ARBITER = "P", parameter LOCK_ENABLE = 0, - parameter OUT_REG = 0, + parameter OUT_REG = 0, parameter MAX_FANOUT = `MAX_FANOUT, parameter PERF_CTR_BITS = `CLOG2(NUM_INPUTS+1) ) ( diff --git a/hw/rtl/mem/VX_gbar_arb.sv b/hw/rtl/mem/VX_gbar_arb.sv index 6aa93510..a4cc07c3 100644 --- a/hw/rtl/mem/VX_gbar_arb.sv +++ b/hw/rtl/mem/VX_gbar_arb.sv @@ -15,7 +15,7 @@ module VX_gbar_arb #( parameter NUM_REQS = 1, - parameter OUT_REG = 0, + parameter OUT_REG = 0, parameter `STRING ARBITER = "R" ) ( input wire clk, diff --git a/hw/rtl/mem/VX_mem_arb.sv b/hw/rtl/mem/VX_mem_arb.sv index 939dd6ba..2588a9ea 100644 --- a/hw/rtl/mem/VX_mem_arb.sv +++ b/hw/rtl/mem/VX_mem_arb.sv @@ -21,8 +21,8 @@ module VX_mem_arb #( parameter ADDR_WIDTH = (MEM_ADDR_WIDTH-`CLOG2(DATA_SIZE)), parameter TAG_WIDTH = 1, parameter TAG_SEL_IDX = 0, - parameter OUT_REG_REQ = 0, - parameter OUT_REG_RSP = 0, + parameter OUT_REG_REQ = 0, + parameter OUT_REG_RSP = 0, parameter `STRING ARBITER = "R" ) ( input wire clk, diff --git a/hw/rtl/mem/VX_smem_switch.sv b/hw/rtl/mem/VX_smem_switch.sv index 7dc410a9..5fb92915 100644 --- a/hw/rtl/mem/VX_smem_switch.sv +++ b/hw/rtl/mem/VX_smem_switch.sv @@ -19,8 +19,8 @@ module VX_smem_switch #( parameter TAG_WIDTH = 1, parameter MEM_ADDR_WIDTH = `MEM_ADDR_WIDTH, parameter TAG_SEL_IDX = 0, - parameter OUT_REG_REQ = 0, - parameter OUT_REG_RSP = 0, + parameter OUT_REG_REQ = 0, + parameter OUT_REG_RSP = 0, parameter `STRING ARBITER = "R" ) ( input wire clk, From 1271c9c03f3c81ebe57ab75c593fe1f6ffe8b9cf Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 27 Nov 2023 02:12:12 -0800 Subject: [PATCH 14/57] minor update --- tests/opencl/Makefile | 12 ++++++------ tests/opencl/{matmul => sgemm2}/Makefile | 2 +- tests/opencl/{matmul => sgemm2}/kernel.cl | 4 ++-- tests/opencl/{matmul => sgemm2}/main.cc | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) rename tests/opencl/{matmul => sgemm2}/Makefile (75%) rename tests/opencl/{matmul => sgemm2}/kernel.cl (96%) rename tests/opencl/{matmul => sgemm2}/main.cc (99%) diff --git a/tests/opencl/Makefile b/tests/opencl/Makefile index 88236559..27ef6f38 100644 --- a/tests/opencl/Makefile +++ b/tests/opencl/Makefile @@ -17,7 +17,7 @@ all: $(MAKE) -C lbm $(MAKE) -C oclprintf $(MAKE) -C blackscholes - $(MAKE) -C matmul + $(MAKE) -C sgemm2 $(MAKE) -C convolution run-simx: @@ -38,7 +38,7 @@ run-simx: $(MAKE) -C transpose run-simx $(MAKE) -C convolution run-simx $(MAKE) -C cutcp run-simx - $(MAKE) -C matmul run-simx + $(MAKE) -C sgemm2 run-simx $(MAKE) -C vectorhypot run-simx $(MAKE) -C mri-q run-simx @@ -60,7 +60,7 @@ run-rtlsim: $(MAKE) -C blackscholes run-rtlsim $(MAKE) -C convolution run-rtlsim # $(MAKE) -C cutcp run-rtlsim -# $(MAKE) -C matmul run-rtlsim +# $(MAKE) -C sgemm2 run-rtlsim # $(MAKE) -C vectorhypot run-rtlsim # $(MAKE) -C mri-q run-rtlsim @@ -82,7 +82,7 @@ run-opae: $(MAKE) -C blackscholes run-opae $(MAKE) -C convolution run-opae # $(MAKE) -C cutcp run-opae -# $(MAKE) -C matmul run-opae +# $(MAKE) -C sgemm2 run-opae # $(MAKE) -C vectorhypot run-opae # $(MAKE) -C mri-q run-opae @@ -105,7 +105,7 @@ clean: $(MAKE) -C lbm clean $(MAKE) -C oclprintf clean $(MAKE) -C blackscholes clean - $(MAKE) -C matmul clean + $(MAKE) -C sgemm2 clean $(MAKE) -C convolution clean clean-all: @@ -128,5 +128,5 @@ clean-all: $(MAKE) -C lbm clean-all $(MAKE) -C oclprintf clean-all $(MAKE) -C blackscholes clean-all - $(MAKE) -C matmul clean-all + $(MAKE) -C sgemm2 clean-all $(MAKE) -C convolution clean-all diff --git a/tests/opencl/matmul/Makefile b/tests/opencl/sgemm2/Makefile similarity index 75% rename from tests/opencl/matmul/Makefile rename to tests/opencl/sgemm2/Makefile index 39b92b36..f507d9ed 100644 --- a/tests/opencl/matmul/Makefile +++ b/tests/opencl/sgemm2/Makefile @@ -1,4 +1,4 @@ -PROJECT = matmul +PROJECT = sgemm2 SRCS = main.cc diff --git a/tests/opencl/matmul/kernel.cl b/tests/opencl/sgemm2/kernel.cl similarity index 96% rename from tests/opencl/matmul/kernel.cl rename to tests/opencl/sgemm2/kernel.cl index 007a233f..6a764820 100644 --- a/tests/opencl/matmul/kernel.cl +++ b/tests/opencl/sgemm2/kernel.cl @@ -1,4 +1,4 @@ -__kernel void matmul(__global float *A, +__kernel void sgemm2(__global float *A, __global float *B, __global float *C, const unsigned int N, @@ -36,7 +36,7 @@ __kernel void matmul(__global float *A, C[globalRow * N + globalCol] = sum; } -/*__kernel void matmul(__global float *A, +/*__kernel void sgemm2(__global float *A, __global float *B, __global float *C, const unsigned int N) diff --git a/tests/opencl/matmul/main.cc b/tests/opencl/sgemm2/main.cc similarity index 99% rename from tests/opencl/matmul/main.cc rename to tests/opencl/sgemm2/main.cc index 3d26ff0c..21ec3a54 100644 --- a/tests/opencl/matmul/main.cc +++ b/tests/opencl/sgemm2/main.cc @@ -12,7 +12,7 @@ #define FLOAT_ULP 6 -#define KERNEL_NAME "matmul" +#define KERNEL_NAME "sgemm2" #define CL_CHECK(_expr) \ do { \ From 9dc5793046e8c147ae04fcd37e9c497483cd0c8f Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 27 Nov 2023 02:21:47 -0800 Subject: [PATCH 15/57] minor udpate --- tests/regression/Makefile | 18 +- tests/regression/{tensor => sgemmx}/Makefile | 2 +- tests/regression/{tensor => sgemmx}/common.h | 0 .../regression/{tensor => sgemmx}/kernel.cpp | 0 tests/regression/{tensor => sgemmx}/main.cpp | 0 tests/regression/vecaddx/Makefile | 9 + tests/regression/vecaddx/common.h | 17 ++ tests/regression/vecaddx/kernel.cpp | 18 ++ tests/regression/vecaddx/main.cpp | 246 ++++++++++++++++++ 9 files changed, 303 insertions(+), 7 deletions(-) rename tests/regression/{tensor => sgemmx}/Makefile (81%) rename tests/regression/{tensor => sgemmx}/common.h (100%) rename tests/regression/{tensor => sgemmx}/kernel.cpp (100%) rename tests/regression/{tensor => sgemmx}/main.cpp (100%) create mode 100644 tests/regression/vecaddx/Makefile create mode 100644 tests/regression/vecaddx/common.h create mode 100644 tests/regression/vecaddx/kernel.cpp create mode 100644 tests/regression/vecaddx/main.cpp diff --git a/tests/regression/Makefile b/tests/regression/Makefile index 89fa25af..d44c82c4 100644 --- a/tests/regression/Makefile +++ b/tests/regression/Makefile @@ -10,7 +10,8 @@ all: $(MAKE) -C fence $(MAKE) -C no_mf_ext $(MAKE) -C no_smem - $(MAKE) -C tensor + $(MAKE) -C vecaddx + $(MAKE) -C sgemmx run-simx: $(MAKE) -C basic run-simx @@ -24,7 +25,8 @@ run-simx: $(MAKE) -C fence run-simx $(MAKE) -C no_mf_ext run-simx $(MAKE) -C no_smem run-simx - $(MAKE) -C tensor run-simx + $(MAKE) -C vecaddx run-simx + $(MAKE) -C sgemmx run-simx run-rtlsim: $(MAKE) -C basic run-rtlsim @@ -38,7 +40,8 @@ run-rtlsim: $(MAKE) -C fence run-rtlsim $(MAKE) -C no_mf_ext run-rtlsim $(MAKE) -C no_smem run-rtlsim - $(MAKE) -C tensor run-rtlsim + $(MAKE) -C vecaddx run-rtlsim + $(MAKE) -C sgemmx run-rtlsim run-opae: $(MAKE) -C basic run-opae @@ -52,7 +55,8 @@ run-opae: $(MAKE) -C fence run-opae $(MAKE) -C no_mf_ext run-opae $(MAKE) -C no_smem run-opae - $(MAKE) -C tensor run-opae + $(MAKE) -C vecaddx run-opae + $(MAKE) -C sgemmx run-opae clean: $(MAKE) -C basic clean @@ -66,7 +70,8 @@ clean: $(MAKE) -C fence clean $(MAKE) -C no_mf_ext clean $(MAKE) -C no_smem clean - $(MAKE) -C tensor clean + $(MAKE) -C vecaddx clean + $(MAKE) -C sgemmx clean clean-all: $(MAKE) -C basic clean-all @@ -80,4 +85,5 @@ clean-all: $(MAKE) -C fence clean-all $(MAKE) -C no_mf_ext clean-all $(MAKE) -C no_smem clean-all - $(MAKE) -C tensor clean-all + $(MAKE) -C vecaddx clean-all + $(MAKE) -C sgemmx clean-all diff --git a/tests/regression/tensor/Makefile b/tests/regression/sgemmx/Makefile similarity index 81% rename from tests/regression/tensor/Makefile rename to tests/regression/sgemmx/Makefile index dbb70c3b..2e72b32e 100644 --- a/tests/regression/tensor/Makefile +++ b/tests/regression/sgemmx/Makefile @@ -1,4 +1,4 @@ -PROJECT = tensor +PROJECT = sgemmx SRCS = main.cpp diff --git a/tests/regression/tensor/common.h b/tests/regression/sgemmx/common.h similarity index 100% rename from tests/regression/tensor/common.h rename to tests/regression/sgemmx/common.h diff --git a/tests/regression/tensor/kernel.cpp b/tests/regression/sgemmx/kernel.cpp similarity index 100% rename from tests/regression/tensor/kernel.cpp rename to tests/regression/sgemmx/kernel.cpp diff --git a/tests/regression/tensor/main.cpp b/tests/regression/sgemmx/main.cpp similarity index 100% rename from tests/regression/tensor/main.cpp rename to tests/regression/sgemmx/main.cpp diff --git a/tests/regression/vecaddx/Makefile b/tests/regression/vecaddx/Makefile new file mode 100644 index 00000000..af43d3c7 --- /dev/null +++ b/tests/regression/vecaddx/Makefile @@ -0,0 +1,9 @@ +PROJECT = vecaddx + +SRCS = main.cpp + +VX_SRCS = kernel.cpp + +OPTS ?= -n64 + +include ../common.mk \ No newline at end of file diff --git a/tests/regression/vecaddx/common.h b/tests/regression/vecaddx/common.h new file mode 100644 index 00000000..2b8f164a --- /dev/null +++ b/tests/regression/vecaddx/common.h @@ -0,0 +1,17 @@ +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#define KERNEL_ARG_DEV_MEM_ADDR 0x7ffff000 + +#ifndef TYPE +#define TYPE float +#endif + +typedef struct { + uint32_t num_points; + uint64_t src0_addr; + uint64_t src1_addr; + uint64_t dst_addr; +} kernel_arg_t; + +#endif diff --git a/tests/regression/vecaddx/kernel.cpp b/tests/regression/vecaddx/kernel.cpp new file mode 100644 index 00000000..6ed42164 --- /dev/null +++ b/tests/regression/vecaddx/kernel.cpp @@ -0,0 +1,18 @@ +#include +#include +#include +#include "common.h" + +void kernel_body(int task_id, kernel_arg_t* __UNIFORM__ arg) { + auto src0_ptr = reinterpret_cast(arg->src0_addr); + auto src1_ptr = reinterpret_cast(arg->src1_addr); + auto dst_ptr = reinterpret_cast(arg->dst_addr); + + dst_ptr[task_id] = src0_ptr[task_id] + src1_ptr[task_id]; +} + +int main() { + kernel_arg_t* arg = (kernel_arg_t*)KERNEL_ARG_DEV_MEM_ADDR; + vx_spawn_tasks(arg->num_points, (vx_spawn_tasks_cb)kernel_body, arg); + return 0; +} diff --git a/tests/regression/vecaddx/main.cpp b/tests/regression/vecaddx/main.cpp new file mode 100644 index 00000000..117f3470 --- /dev/null +++ b/tests/regression/vecaddx/main.cpp @@ -0,0 +1,246 @@ +#include +#include +#include +#include +#include +#include "common.h" + +#define FLOAT_ULP 6 + +#define RT_CHECK(_expr) \ + do { \ + int _ret = _expr; \ + if (0 == _ret) \ + break; \ + printf("Error: '%s' returned %d!\n", #_expr, (int)_ret); \ + cleanup(); \ + exit(-1); \ + } while (false) + +/////////////////////////////////////////////////////////////////////////////// + +template +class Comparator {}; + +template <> +class Comparator { +public: + static const char* type_str() { + return "integer"; + } + static int generate() { + return rand(); + } + static bool compare(int a, int b, int index, int errors) { + if (a != b) { + if (errors < 100) { + printf("*** error: [%d] expected=%d, actual=%d\n", index, a, b); + } + return false; + } + return true; + } +}; + +template <> +class Comparator { +private: + union Float_t { float f; int i; }; +public: + static const char* type_str() { + return "float"; + } + static int generate() { + return static_cast(rand()) / RAND_MAX; + } + static bool compare(float a, float b, int index, int errors) { + union fi_t { float f; int32_t i; }; + fi_t fa, fb; + fa.f = a; + fb.f = b; + auto d = std::abs(fa.i - fb.i); + if (d > FLOAT_ULP) { + if (errors < 100) { + printf("*** error: [%d] expected=%f, actual=%f\n", index, a, b); + } + return false; + } + return true; + } +}; + +const char* kernel_file = "kernel.bin"; +uint32_t size = 16; + +vx_device_h device = nullptr; +std::vector source_data; +std::vector staging_buf; +kernel_arg_t kernel_arg = {}; + +static void show_usage() { + std::cout << "Vortex Test." << std::endl; + std::cout << "Usage: [-k: kernel] [-n words] [-h: help]" << std::endl; +} + +static void parse_args(int argc, char **argv) { + int c; + while ((c = getopt(argc, argv, "n:k:h?")) != -1) { + switch (c) { + case 'n': + size = atoi(optarg); + break; + case 'k': + kernel_file = optarg; + break; + case 'h': + case '?': { + show_usage(); + exit(0); + } break; + default: + show_usage(); + exit(-1); + } + } +} + +void cleanup() { + if (device) { + vx_mem_free(device, kernel_arg.src0_addr); + vx_mem_free(device, kernel_arg.src1_addr); + vx_mem_free(device, kernel_arg.dst_addr); + vx_dev_close(device); + } +} + +int run_test(const kernel_arg_t& kernel_arg, + uint32_t buf_size, + uint32_t num_points) { + // start device + std::cout << "start device" << std::endl; + RT_CHECK(vx_start(device)); + + // wait for completion + std::cout << "wait for completion" << std::endl; + RT_CHECK(vx_ready_wait(device, VX_MAX_TIMEOUT)); + + // download destination buffer + std::cout << "download destination buffer" << std::endl; + RT_CHECK(vx_copy_from_dev(device, staging_buf.data(), kernel_arg.dst_addr, buf_size)); + + // verify result + std::cout << "verify result" << std::endl; + { + int errors = 0; + auto buf_ptr = (TYPE*)staging_buf.data(); + for (uint32_t i = 0; i < num_points; ++i) { + auto ref = source_data[2 * i + 0] + source_data[2 * i + 1]; + auto cur = buf_ptr[i]; + if (!Comparator::compare(cur, ref, i, errors)) { + ++errors; + } + } + if (errors != 0) { + std::cout << "Found " << std::dec << errors << " errors!" << std::endl; + std::cout << "FAILED!" << std::endl; + return 1; + } + } + + return 0; +} + +int main(int argc, char *argv[]) { + // parse command arguments + parse_args(argc, argv); + + std::srand(50); + + // open device connection + std::cout << "open device connection" << std::endl; + RT_CHECK(vx_dev_open(&device)); + + uint64_t num_cores, num_warps, num_threads; + RT_CHECK(vx_dev_caps(device, VX_CAPS_NUM_CORES, &num_cores)); + RT_CHECK(vx_dev_caps(device, VX_CAPS_NUM_WARPS, &num_warps)); + RT_CHECK(vx_dev_caps(device, VX_CAPS_NUM_THREADS, &num_threads)); + std::cout << "number of cores: " << num_cores << std::endl; + std::cout << "number of warps: " << num_warps << std::endl; + std::cout << "number of threads: " << num_threads << std::endl; + + uint32_t num_points = size; + uint32_t buf_size = num_points * sizeof(TYPE); + + std::cout << "number of points: " << num_points << std::endl; + std::cout << "data type: " << Comparator::type_str() << std::endl; + std::cout << "buffer size: " << buf_size << " bytes" << std::endl; + + // upload program + std::cout << "upload program" << std::endl; + RT_CHECK(vx_upload_kernel_file(device, kernel_file)); + + // allocate device memory + std::cout << "allocate device memory" << std::endl; + RT_CHECK(vx_mem_alloc(device, buf_size, VX_MEM_TYPE_GLOBAL, &kernel_arg.src0_addr)); + RT_CHECK(vx_mem_alloc(device, buf_size, VX_MEM_TYPE_GLOBAL, &kernel_arg.src1_addr)); + RT_CHECK(vx_mem_alloc(device, buf_size, VX_MEM_TYPE_GLOBAL, &kernel_arg.dst_addr)); + + kernel_arg.num_points = num_points; + + std::cout << "dev_src0=0x" << std::hex << kernel_arg.src0_addr << std::endl; + std::cout << "dev_src1=0x" << std::hex << kernel_arg.src1_addr << std::endl; + std::cout << "dev_dst=0x" << std::hex << kernel_arg.dst_addr << std::endl; + + // allocate staging buffer + std::cout << "allocate staging buffer" << std::endl; + uint32_t alloc_size = std::max(buf_size, sizeof(kernel_arg_t)); + staging_buf.resize(alloc_size); + + // upload kernel argument + std::cout << "upload kernel argument" << std::endl; + memcpy(staging_buf.data(), &kernel_arg, sizeof(kernel_arg_t)); + RT_CHECK(vx_copy_to_dev(device, KERNEL_ARG_DEV_MEM_ADDR, staging_buf.data(), sizeof(kernel_arg_t))); + + // generate source data + source_data.resize(2 * num_points); + for (uint32_t i = 0; i < source_data.size(); ++i) { + source_data[i] = Comparator::generate(); + } + + // upload source buffer0 + { + std::cout << "upload source buffer0" << std::endl; + auto buf_ptr = (TYPE*)staging_buf.data(); + for (uint32_t i = 0; i < num_points; ++i) { + buf_ptr[i] = source_data[2 * i + 0]; + } + RT_CHECK(vx_copy_to_dev(device, kernel_arg.src0_addr, staging_buf.data(), buf_size)); + } + + // upload source buffer1 + { + std::cout << "upload source buffer1" << std::endl; + auto buf_ptr = (TYPE*)staging_buf.data(); + for (uint32_t i = 0; i < num_points; ++i) { + buf_ptr[i] = source_data[2 * i + 1]; + } + RT_CHECK(vx_copy_to_dev(device, kernel_arg.src1_addr, staging_buf.data(), buf_size)); + } + + // clear destination buffer + std::cout << "clear destination buffer" << std::endl; + memset(staging_buf.data(), 0, num_points * sizeof(TYPE)); + RT_CHECK(vx_copy_to_dev(device, kernel_arg.dst_addr, staging_buf.data(), buf_size)); + + // run tests + std::cout << "run tests" << std::endl; + RT_CHECK(run_test(kernel_arg, buf_size, num_points)); + + // cleanup + std::cout << "cleanup" << std::endl; + cleanup(); + + std::cout << "PASSED!" << std::endl; + + return 0; +} \ No newline at end of file From 4b68235389217ae91ce110b0b1fa84542cb232f7 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 27 Nov 2023 04:50:55 -0800 Subject: [PATCH 16/57] fixed simx dispatcher bug --- hw/rtl/VX_types.vh | 158 +++++++++++++++------------ runtime/common/utils.cpp | 226 +++++++++++++++++++++++++-------------- sim/simx/cache_cluster.h | 10 +- sim/simx/cache_sim.cpp | 139 +++++++++++------------- sim/simx/cache_sim.h | 7 +- sim/simx/cluster.cpp | 27 +++-- sim/simx/core.cpp | 165 ++++++++++++++++------------ sim/simx/core.h | 21 +++- sim/simx/dispatcher.h | 42 ++++---- sim/simx/processor.cpp | 21 ++-- sim/simx/scoreboard.h | 111 +++++++++---------- sim/simx/types.h | 164 +++++++++++++++++++++------- 12 files changed, 640 insertions(+), 451 deletions(-) diff --git a/hw/rtl/VX_types.vh b/hw/rtl/VX_types.vh index 388dc258..80a4a7d7 100644 --- a/hw/rtl/VX_types.vh +++ b/hw/rtl/VX_types.vh @@ -58,6 +58,8 @@ `define VX_CSR_MPM_BASE 12'hB00 `define VX_CSR_MPM_BASE_H 12'hB80 +`define VX_CSR_MPM_USER 12'hB03 +`define VX_CSR_MPM_USER_H 12'hB83 // Machine Performance-monitoring core counters // PERF: Standard @@ -68,29 +70,41 @@ `define VX_CSR_MINSTRET 12'hB02 `define VX_CSR_MINSTRET_H 12'hB82 // PERF: pipeline -`define VX_CSR_MPM_IBUF_ST 12'hB03 -`define VX_CSR_MPM_IBUF_ST_H 12'hB83 -`define VX_CSR_MPM_SCRB_ST 12'hB04 -`define VX_CSR_MPM_SCRB_ST_H 12'hB84 -`define VX_CSR_MPM_ALU_ST 12'hB05 -`define VX_CSR_MPM_ALU_ST_H 12'hB85 -`define VX_CSR_MPM_LSU_ST 12'hB06 -`define VX_CSR_MPM_LSU_ST_H 12'hB86 -`define VX_CSR_MPM_FPU_ST 12'hB07 -`define VX_CSR_MPM_FPU_ST_H 12'hB87 -`define VX_CSR_MPM_SFU_ST 12'hB08 -`define VX_CSR_MPM_SFU_ST_H 12'hB88 +`define VX_CSR_MPM_SCHED_ST 12'hB03 +`define VX_CSR_MPM_SCHED_ST_H 12'hB83 +`define VX_CSR_MPM_FETCH_ST 12'hB04 +`define VX_CSR_MPM_FETCH_ST_H 12'hB84 +`define VX_CSR_MPM_IBUF_ST 12'hB05 +`define VX_CSR_MPM_IBUF_ST_H 12'hB85 +`define VX_CSR_MPM_SCRB_ST 12'hB06 +`define VX_CSR_MPM_SCRB_ST_H 12'hB86 +`define VX_CSR_MPM_ALU_ST 12'hB07 +`define VX_CSR_MPM_ALU_ST_H 12'hB87 +`define VX_CSR_MPM_LSU_ST 12'hB08 +`define VX_CSR_MPM_LSU_ST_H 12'hB88 +`define VX_CSR_MPM_FPU_ST 12'hB09 +`define VX_CSR_MPM_FPU_ST_H 12'hB89 +`define VX_CSR_MPM_SFU_ST 12'hB0A +`define VX_CSR_MPM_SFU_ST_H 12'hB8A +`define VX_CSR_MPM_SCRB_ALU 12'hB0B +`define VX_CSR_MPM_SCRB_ALU_H 12'hB8B +`define VX_CSR_MPM_SCRB_FPU 12'hB0C +`define VX_CSR_MPM_SCRB_FPU_H 12'hB8C +`define VX_CSR_MPM_SCRB_LSU 12'hB0D +`define VX_CSR_MPM_SCRB_LSU_H 12'hB8D +`define VX_CSR_MPM_SCRB_SFU 12'hB0E +`define VX_CSR_MPM_SCRB_SFU_H 12'hB8E // PERF: memory -`define VX_CSR_MPM_IFETCHES 12'hB0A -`define VX_CSR_MPM_IFETCHES_H 12'hB8A -`define VX_CSR_MPM_LOADS 12'hB0B -`define VX_CSR_MPM_LOADS_H 12'hB8B -`define VX_CSR_MPM_STORES 12'hB0C -`define VX_CSR_MPM_STORES_H 12'hB8C -`define VX_CSR_MPM_IFETCH_LAT 12'hB0D -`define VX_CSR_MPM_IFETCH_LAT_H 12'hB8D -`define VX_CSR_MPM_LOAD_LAT 12'hB0E -`define VX_CSR_MPM_LOAD_LAT_H 12'hB8E +`define VX_CSR_MPM_IFETCHES 12'hB0F +`define VX_CSR_MPM_IFETCHES_H 12'hB8F +`define VX_CSR_MPM_LOADS 12'hB10 +`define VX_CSR_MPM_LOADS_H 12'hB90 +`define VX_CSR_MPM_STORES 12'hB11 +`define VX_CSR_MPM_STORES_H 12'hB91 +`define VX_CSR_MPM_IFETCH_LAT 12'hB12 +`define VX_CSR_MPM_IFETCH_LAT_H 12'hB92 +`define VX_CSR_MPM_LOAD_LAT 12'hB13 +`define VX_CSR_MPM_LOAD_LAT_H 12'hB93 // Machine Performance-monitoring memory counters // PERF: icache @@ -98,59 +112,61 @@ `define VX_CSR_MPM_ICACHE_READS_H 12'hB83 `define VX_CSR_MPM_ICACHE_MISS_R 12'hB04 // read misses `define VX_CSR_MPM_ICACHE_MISS_R_H 12'hB84 +`define VX_CSR_MPM_ICACHE_MSHR_ST 12'hB05 // MSHR stalls +`define VX_CSR_MPM_ICACHE_MSHR_ST_H 12'hB85 // PERF: dcache -`define VX_CSR_MPM_DCACHE_READS 12'hB05 // total reads -`define VX_CSR_MPM_DCACHE_READS_H 12'hB85 -`define VX_CSR_MPM_DCACHE_WRITES 12'hB06 // total writes -`define VX_CSR_MPM_DCACHE_WRITES_H 12'hB86 -`define VX_CSR_MPM_DCACHE_MISS_R 12'hB07 // read misses -`define VX_CSR_MPM_DCACHE_MISS_R_H 12'hB87 -`define VX_CSR_MPM_DCACHE_MISS_W 12'hB08 // write misses -`define VX_CSR_MPM_DCACHE_MISS_W_H 12'hB88 -`define VX_CSR_MPM_DCACHE_BANK_ST 12'hB09 // bank conflicts -`define VX_CSR_MPM_DCACHE_BANK_ST_H 12'hB89 -`define VX_CSR_MPM_DCACHE_MSHR_ST 12'hB0A // MSHR stalls -`define VX_CSR_MPM_DCACHE_MSHR_ST_H 12'hB8A -// PERF: smem -`define VX_CSR_MPM_SMEM_READS 12'hB0B // memory reads -`define VX_CSR_MPM_SMEM_READS_H 12'hB8B -`define VX_CSR_MPM_SMEM_WRITES 12'hB0C // memory writes -`define VX_CSR_MPM_SMEM_WRITES_H 12'hB8C -`define VX_CSR_MPM_SMEM_BANK_ST 12'hB0D // bank conflicts -`define VX_CSR_MPM_SMEM_BANK_ST_H 12'hB8D +`define VX_CSR_MPM_DCACHE_READS 12'hB06 // total reads +`define VX_CSR_MPM_DCACHE_READS_H 12'hB86 +`define VX_CSR_MPM_DCACHE_WRITES 12'hB07 // total writes +`define VX_CSR_MPM_DCACHE_WRITES_H 12'hB87 +`define VX_CSR_MPM_DCACHE_MISS_R 12'hB08 // read misses +`define VX_CSR_MPM_DCACHE_MISS_R_H 12'hB88 +`define VX_CSR_MPM_DCACHE_MISS_W 12'hB09 // write misses +`define VX_CSR_MPM_DCACHE_MISS_W_H 12'hB89 +`define VX_CSR_MPM_DCACHE_BANK_ST 12'hB0A // bank conflicts +`define VX_CSR_MPM_DCACHE_BANK_ST_H 12'hB8A +`define VX_CSR_MPM_DCACHE_MSHR_ST 12'hB0B // MSHR stalls +`define VX_CSR_MPM_DCACHE_MSHR_ST_H 12'hB8B // PERF: l2cache -`define VX_CSR_MPM_L2CACHE_READS 12'hB0E // total reads -`define VX_CSR_MPM_L2CACHE_READS_H 12'hB8E -`define VX_CSR_MPM_L2CACHE_WRITES 12'hB0F // total writes -`define VX_CSR_MPM_L2CACHE_WRITES_H 12'hB8F -`define VX_CSR_MPM_L2CACHE_MISS_R 12'hB10 // read misses -`define VX_CSR_MPM_L2CACHE_MISS_R_H 12'hB90 -`define VX_CSR_MPM_L2CACHE_MISS_W 12'hB11 // write misses -`define VX_CSR_MPM_L2CACHE_MISS_W_H 12'hB91 -`define VX_CSR_MPM_L2CACHE_BANK_ST 12'hB12 // bank conflicts -`define VX_CSR_MPM_L2CACHE_BANK_ST_H 12'hB92 -`define VX_CSR_MPM_L2CACHE_MSHR_ST 12'hB13 // MSHR stalls -`define VX_CSR_MPM_L2CACHE_MSHR_ST_H 12'hB93 +`define VX_CSR_MPM_L2CACHE_READS 12'hB0C // total reads +`define VX_CSR_MPM_L2CACHE_READS_H 12'hB8C +`define VX_CSR_MPM_L2CACHE_WRITES 12'hB0D // total writes +`define VX_CSR_MPM_L2CACHE_WRITES_H 12'hB8D +`define VX_CSR_MPM_L2CACHE_MISS_R 12'hB0E // read misses +`define VX_CSR_MPM_L2CACHE_MISS_R_H 12'hB8E +`define VX_CSR_MPM_L2CACHE_MISS_W 12'hB0F // write misses +`define VX_CSR_MPM_L2CACHE_MISS_W_H 12'hB8F +`define VX_CSR_MPM_L2CACHE_BANK_ST 12'hB10 // bank conflicts +`define VX_CSR_MPM_L2CACHE_BANK_ST_H 12'hB90 +`define VX_CSR_MPM_L2CACHE_MSHR_ST 12'hB11 // MSHR stalls +`define VX_CSR_MPM_L2CACHE_MSHR_ST_H 12'hB91 // PERF: l3cache -`define VX_CSR_MPM_L3CACHE_READS 12'hB14 // total reads -`define VX_CSR_MPM_L3CACHE_READS_H 12'hB94 -`define VX_CSR_MPM_L3CACHE_WRITES 12'hB15 // total writes -`define VX_CSR_MPM_L3CACHE_WRITES_H 12'hB95 -`define VX_CSR_MPM_L3CACHE_MISS_R 12'hB16 // read misses -`define VX_CSR_MPM_L3CACHE_MISS_R_H 12'hB96 -`define VX_CSR_MPM_L3CACHE_MISS_W 12'hB17 // write misses -`define VX_CSR_MPM_L3CACHE_MISS_W_H 12'hB97 -`define VX_CSR_MPM_L3CACHE_BANK_ST 12'hB18 // bank conflicts -`define VX_CSR_MPM_L3CACHE_BANK_ST_H 12'hB98 -`define VX_CSR_MPM_L3CACHE_MSHR_ST 12'hB19 // MSHR stalls -`define VX_CSR_MPM_L3CACHE_MSHR_ST_H 12'hB99 +`define VX_CSR_MPM_L3CACHE_READS 12'hB12 // total reads +`define VX_CSR_MPM_L3CACHE_READS_H 12'hB92 +`define VX_CSR_MPM_L3CACHE_WRITES 12'hB13 // total writes +`define VX_CSR_MPM_L3CACHE_WRITES_H 12'hB93 +`define VX_CSR_MPM_L3CACHE_MISS_R 12'hB14 // read misses +`define VX_CSR_MPM_L3CACHE_MISS_R_H 12'hB94 +`define VX_CSR_MPM_L3CACHE_MISS_W 12'hB15 // write misses +`define VX_CSR_MPM_L3CACHE_MISS_W_H 12'hB95 +`define VX_CSR_MPM_L3CACHE_BANK_ST 12'hB16 // bank conflicts +`define VX_CSR_MPM_L3CACHE_BANK_ST_H 12'hB96 +`define VX_CSR_MPM_L3CACHE_MSHR_ST 12'hB17 // MSHR stalls +`define VX_CSR_MPM_L3CACHE_MSHR_ST_H 12'hB97 // PERF: memory -`define VX_CSR_MPM_MEM_READS 12'hB1A // total reads -`define VX_CSR_MPM_MEM_READS_H 12'hB9A -`define VX_CSR_MPM_MEM_WRITES 12'hB1B // total writes -`define VX_CSR_MPM_MEM_WRITES_H 12'hB9B -`define VX_CSR_MPM_MEM_LAT 12'hB1C // memory latency -`define VX_CSR_MPM_MEM_LAT_H 12'hB9C +`define VX_CSR_MPM_MEM_READS 12'hB18 // total reads +`define VX_CSR_MPM_MEM_READS_H 12'hB98 +`define VX_CSR_MPM_MEM_WRITES 12'hB19 // total writes +`define VX_CSR_MPM_MEM_WRITES_H 12'hB99 +`define VX_CSR_MPM_MEM_LAT 12'hB1A // memory latency +`define VX_CSR_MPM_MEM_LAT_H 12'hB9A +// PERF: smem +`define VX_CSR_MPM_SMEM_READS 12'hB1B // memory reads +`define VX_CSR_MPM_SMEM_READS_H 12'hB9B +`define VX_CSR_MPM_SMEM_WRITES 12'hB1C // memory writes +`define VX_CSR_MPM_SMEM_WRITES_H 12'hB9C +`define VX_CSR_MPM_SMEM_BANK_ST 12'hB1D // bank conflicts +`define VX_CSR_MPM_SMEM_BANK_ST_H 12'hB9D // Machine Information Registers diff --git a/runtime/common/utils.cpp b/runtime/common/utils.cpp index 72c2b80c..574f64a7 100644 --- a/runtime/common/utils.cpp +++ b/runtime/common/utils.cpp @@ -186,27 +186,31 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { return int((1.0 - (double(part) / double(total))) * 100); }; - auto caclAvgLatency = [&](uint64_t sum, uint64_t requests)->int { - if (requests == 0) + auto caclAverage = [&](uint64_t part, uint64_t total)->double { + if (total == 0) return 0; - return int(double(sum) / double(requests)); + return double(part) / double(total); }; - auto calcUtilization = [&](uint64_t count, uint64_t stalls)->int { - if (count == 0) - return 0; - return int((double(count) / double(count + stalls)) * 100); + auto calcAvgPercent = [&](uint64_t part, uint64_t total)->int { + return int(caclAverage(part, total) * 100); }; auto perf_class = gAutoPerfDump.get_perf_class(); // PERF: pipeline stalls + uint64_t scheduler_stalls = 0; + uint64_t fetch_stalls = 0; uint64_t ibuffer_stalls = 0; - uint64_t scoreboard_stalls = 0; + uint64_t scrb_stalls = 0; uint64_t lsu_stalls = 0; uint64_t fpu_stalls = 0; uint64_t alu_stalls = 0; - uint64_t sfu_stalls = 0; + uint64_t sfu_stalls = 0; + uint64_t scrb_alu = 0; + uint64_t scrb_fpu = 0; + uint64_t scrb_lsu = 0; + uint64_t scrb_sfu = 0; uint64_t ifetches = 0; uint64_t loads = 0; uint64_t stores = 0; @@ -251,76 +255,121 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { #endif std::vector staging_buf(64* sizeof(uint32_t)); - - for (unsigned core_id = 0; core_id < num_cores; ++core_id) { + + for (unsigned core_id = 0; core_id < num_cores; ++core_id) { uint64_t mpm_mem_addr = IO_CSR_ADDR + core_id * staging_buf.size(); ret = vx_copy_from_dev(hdevice, staging_buf.data(), mpm_mem_addr, staging_buf.size()); if (ret != 0) return ret; + uint64_t cycles_per_core = get_csr_64(staging_buf.data(), VX_CSR_MCYCLE); + uint64_t instrs_per_core = get_csr_64(staging_buf.data(), VX_CSR_MINSTRET); + #ifdef PERF_ENABLE switch (perf_class) { case VX_DCR_MPM_CLASS_CORE: { // PERF: pipeline - // ibuffer_stall - uint64_t ibuffer_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_IBUF_ST); - if (num_cores > 1) fprintf(stream, "PERF: core%d: ibuffer stalls=%ld\n", core_id, ibuffer_stalls_per_core); - ibuffer_stalls += ibuffer_stalls_per_core; - // scoreboard_stall - uint64_t scoreboard_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_ST); - if (num_cores > 1) fprintf(stream, "PERF: core%d: scoreboard stalls=%ld\n", core_id, scoreboard_stalls_per_core); - scoreboard_stalls += scoreboard_stalls_per_core; - // alu_stall - uint64_t alu_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_ALU_ST); - if (num_cores > 1) fprintf(stream, "PERF: core%d: alu unit stalls=%ld\n", core_id, alu_stalls_per_core); - alu_stalls += alu_stalls_per_core; - // lsu_stall - uint64_t lsu_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_LSU_ST); - if (num_cores > 1) fprintf(stream, "PERF: core%d: lsu unit stalls=%ld\n", core_id, lsu_stalls_per_core); - lsu_stalls += lsu_stalls_per_core; - // fpu_stall - uint64_t fpu_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_FPU_ST); - if (num_cores > 1) fprintf(stream, "PERF: core%d: fpu unit stalls=%ld\n", core_id, fpu_stalls_per_core); - fpu_stalls += fpu_stalls_per_core; - // sfu_stall - uint64_t sfu_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SFU_ST); - if (num_cores > 1) fprintf(stream, "PERF: core%d: sfu unit stalls=%ld\n", core_id, sfu_stalls_per_core); - sfu_stalls += sfu_stalls_per_core; + // schedule stalls + { + uint64_t scheduler_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCHED_ST); + int scheduler_percent_per_core = calcAvgPercent(scheduler_stalls_per_core, cycles_per_core); + if (num_cores > 1) fprintf(stream, "PERF: core%d: schedule stalls=%ld (%d%%)\n", core_id, scheduler_stalls_per_core, scheduler_percent_per_core); + scheduler_stalls += scheduler_stalls_per_core; + } + // fetch stalls + { + uint64_t fetch_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_FETCH_ST); + int fetch_percent_per_core = calcAvgPercent(fetch_stalls_per_core, cycles_per_core); + if (num_cores > 1) fprintf(stream, "PERF: core%d: ifetch stalls=%ld (%d%%)\n", core_id, fetch_stalls_per_core, fetch_percent_per_core); + fetch_stalls += fetch_stalls_per_core; + } + // ibuffer_stalls + { + uint64_t ibuffer_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_IBUF_ST); + int ibuffer_percent_per_core = calcAvgPercent(ibuffer_stalls_per_core, cycles_per_core); + if (num_cores > 1) fprintf(stream, "PERF: core%d: ibuffer stalls=%ld (%d%%)\n", core_id, ibuffer_stalls_per_core, ibuffer_percent_per_core); + ibuffer_stalls += ibuffer_stalls_per_core; + } + // scrb_stalls + { + uint64_t scrb_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_ST); + uint64_t scrb_alu_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_ALU); + uint64_t scrb_fpu_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_FPU); + uint64_t scrb_lsu_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_LSU); + uint64_t scrb_sfu_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_SFU); + uint64_t scrb_total = scrb_alu_per_core + scrb_fpu_per_core + scrb_lsu_per_core + scrb_sfu_per_core; + scrb_alu += scrb_alu_per_core; + scrb_fpu += scrb_fpu_per_core; + scrb_lsu += scrb_lsu_per_core; + scrb_sfu += scrb_sfu_per_core; + if (num_cores > 1) fprintf(stream, "PERF: core%d: scoreboard stalls=%ld (alu=%d%%, fpu=%d%%, lsu=%d%%, sfu=%d%%)\n", core_id, scrb_stalls_per_core, + calcAvgPercent(scrb_alu_per_core, scrb_total), + calcAvgPercent(scrb_fpu_per_core, scrb_total), + calcAvgPercent(scrb_lsu_per_core, scrb_total), + calcAvgPercent(scrb_sfu_per_core, scrb_total)); + scrb_stalls += scrb_stalls_per_core; + } + // alu_stalls + { + uint64_t alu_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_ALU_ST); + if (num_cores > 1) fprintf(stream, "PERF: core%d: alu unit stalls=%ld\n", core_id, alu_stalls_per_core); + alu_stalls += alu_stalls_per_core; + } + // lsu_stalls + { + uint64_t lsu_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_LSU_ST); + if (num_cores > 1) fprintf(stream, "PERF: core%d: lsu unit stalls=%ld\n", core_id, lsu_stalls_per_core); + lsu_stalls += lsu_stalls_per_core; + } + // fpu_stalls + { + uint64_t fpu_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_FPU_ST); + if (num_cores > 1) fprintf(stream, "PERF: core%d: fpu unit stalls=%ld\n", core_id, fpu_stalls_per_core); + fpu_stalls += fpu_stalls_per_core; + } + // sfu_stalls + { + uint64_t sfu_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SFU_ST); + if (num_cores > 1) fprintf(stream, "PERF: core%d: sfu unit stalls=%ld\n", core_id, sfu_stalls_per_core); + sfu_stalls += sfu_stalls_per_core; + } // PERF: memory // ifetches - uint64_t ifetches_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_LOADS); - if (num_cores > 1) fprintf(stream, "PERF: core%d: ifetches=%ld\n", core_id, ifetches_per_core); - ifetches += ifetches_per_core; + { + uint64_t ifetches_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_LOADS); + if (num_cores > 1) fprintf(stream, "PERF: core%d: ifetches=%ld\n", core_id, ifetches_per_core); + ifetches += ifetches_per_core; + + uint64_t ifetch_lat_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_IFETCH_LAT); + int mem_avg_lat = caclAverage(ifetch_lat_per_core, ifetches_per_core); + if (num_cores > 1) fprintf(stream, "PERF: core%d: ifetch latency=%d cycles\n", core_id, mem_avg_lat); + ifetch_lat += ifetch_lat_per_core; + } // loads - uint64_t loads_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_LOADS); - if (num_cores > 1) fprintf(stream, "PERF: core%d: loads=%ld\n", core_id, loads_per_core); - loads += loads_per_core; + { + uint64_t loads_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_LOADS); + if (num_cores > 1) fprintf(stream, "PERF: core%d: loads=%ld\n", core_id, loads_per_core); + loads += loads_per_core; + + uint64_t load_lat_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_LOAD_LAT); + int mem_avg_lat = caclAverage(load_lat_per_core, loads_per_core); + if (num_cores > 1) fprintf(stream, "PERF: core%d: load latency=%d cycles\n", core_id, mem_avg_lat); + load_lat += load_lat_per_core; + } // stores - uint64_t stores_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_STORES); - if (num_cores > 1) fprintf(stream, "PERF: core%d: stores=%ld\n", core_id, stores_per_core); - stores += stores_per_core; - // ifetch latency - uint64_t ifetch_lat_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_IFETCH_LAT); - if (num_cores > 1) { - int mem_avg_lat = caclAvgLatency(ifetch_lat_per_core, ifetches_per_core); - fprintf(stream, "PERF: core%d: ifetch latency=%d cycles\n", core_id, mem_avg_lat); + { + uint64_t stores_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_STORES); + if (num_cores > 1) fprintf(stream, "PERF: core%d: stores=%ld\n", core_id, stores_per_core); + stores += stores_per_core; } - ifetch_lat += ifetch_lat_per_core; - // load latency - uint64_t load_lat_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_LOAD_LAT); - if (num_cores > 1) { - int mem_avg_lat = caclAvgLatency(load_lat_per_core, loads_per_core); - fprintf(stream, "PERF: core%d: load latency=%d cycles\n", core_id, mem_avg_lat); - } - load_lat += load_lat_per_core; } break; - case VX_DCR_MPM_CLASS_MEM: { + case VX_DCR_MPM_CLASS_MEM: { if (smem_enable) { // PERF: smem uint64_t smem_reads = get_csr_64(staging_buf.data(), VX_CSR_MPM_SMEM_READS); uint64_t smem_writes = get_csr_64(staging_buf.data(), VX_CSR_MPM_SMEM_WRITES); uint64_t smem_bank_stalls = get_csr_64(staging_buf.data(), VX_CSR_MPM_SMEM_BANK_ST); - int smem_bank_utilization = calcUtilization(smem_reads + smem_writes, smem_bank_stalls); + int smem_bank_utilization = calcAvgPercent(smem_reads + smem_writes, smem_reads + smem_writes + smem_bank_stalls); fprintf(stream, "PERF: core%d: smem reads=%ld\n", core_id, smem_reads); fprintf(stream, "PERF: core%d: smem writes=%ld\n", core_id, smem_writes); fprintf(stream, "PERF: core%d: smem bank stalls=%ld (utilization=%d%%)\n", core_id, smem_bank_stalls, smem_bank_utilization); @@ -330,9 +379,12 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { // PERF: Icache uint64_t icache_reads = get_csr_64(staging_buf.data(), VX_CSR_MPM_ICACHE_READS); uint64_t icache_read_misses = get_csr_64(staging_buf.data(), VX_CSR_MPM_ICACHE_MISS_R); - int icache_read_hit_ratio = calcRatio(icache_read_misses, icache_reads); + uint64_t icache_mshr_stalls = get_csr_64(staging_buf.data(), VX_CSR_MPM_ICACHE_MSHR_ST); + int icache_read_hit_ratio = calcRatio(icache_read_misses, icache_reads); + int mshr_utilization = calcAvgPercent(icache_read_misses, icache_read_misses + icache_mshr_stalls); fprintf(stream, "PERF: core%d: icache reads=%ld\n", core_id, icache_reads); fprintf(stream, "PERF: core%d: icache read misses=%ld (hit ratio=%d%%)\n", core_id, icache_read_misses, icache_read_hit_ratio); + fprintf(stream, "PERF: core%d: icache mshr stalls=%ld (utilization=%d%%)\n", core_id, icache_mshr_stalls, mshr_utilization); } if (dcache_enable) { @@ -345,13 +397,14 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { uint64_t dcache_mshr_stalls = get_csr_64(staging_buf.data(), VX_CSR_MPM_DCACHE_MSHR_ST); int dcache_read_hit_ratio = calcRatio(dcache_read_misses, dcache_reads); int dcache_write_hit_ratio = calcRatio(dcache_write_misses, dcache_writes); - int dcache_bank_utilization = calcUtilization(dcache_reads + dcache_writes, dcache_bank_stalls); + int dcache_bank_utilization = calcAvgPercent(dcache_reads + dcache_writes, dcache_reads + dcache_writes + dcache_bank_stalls); + int mshr_utilization = calcAvgPercent(dcache_read_misses + dcache_write_misses, dcache_read_misses + dcache_write_misses + dcache_mshr_stalls); fprintf(stream, "PERF: core%d: dcache reads=%ld\n", core_id, dcache_reads); fprintf(stream, "PERF: core%d: dcache writes=%ld\n", core_id, dcache_writes); fprintf(stream, "PERF: core%d: dcache read misses=%ld (hit ratio=%d%%)\n", core_id, dcache_read_misses, dcache_read_hit_ratio); fprintf(stream, "PERF: core%d: dcache write misses=%ld (hit ratio=%d%%)\n", core_id, dcache_write_misses, dcache_write_hit_ratio); fprintf(stream, "PERF: core%d: dcache bank stalls=%ld (utilization=%d%%)\n", core_id, dcache_bank_stalls, dcache_bank_utilization); - fprintf(stream, "PERF: core%d: dcache mshr stalls=%ld\n", core_id, dcache_mshr_stalls); + fprintf(stream, "PERF: core%d: dcache mshr stalls=%ld (utilization=%d%%)\n", core_id, dcache_mshr_stalls, mshr_utilization); } if (l2cache_enable) { @@ -386,8 +439,6 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { } #endif - uint64_t instrs_per_core = get_csr_64(staging_buf.data(), VX_CSR_MINSTRET); - uint64_t cycles_per_core = get_csr_64(staging_buf.data(), VX_CSR_MCYCLE); float IPC = (float)(double(instrs_per_core) / double(cycles_per_core)); if (num_cores > 1) fprintf(stream, "PERF: core%d: instrs=%ld, cycles=%ld, IPC=%f\n", core_id, instrs_per_core, cycles_per_core, IPC); instrs += instrs_per_core; @@ -397,10 +448,20 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { #ifdef PERF_ENABLE switch (perf_class) { case VX_DCR_MPM_CLASS_CORE: { + int scheduler_percent = calcAvgPercent(scheduler_stalls, cycles); + int fetch_percent = calcAvgPercent(fetch_stalls, cycles); + int ibuffer_percent = calcAvgPercent(ibuffer_stalls, cycles); int ifetch_avg_lat = (int)(double(ifetch_lat) / double(ifetches)); int load_avg_lat = (int)(double(load_lat) / double(loads)); - fprintf(stream, "PERF: ibuffer stalls=%ld\n", ibuffer_stalls); - fprintf(stream, "PERF: scoreboard stalls=%ld\n", scoreboard_stalls); + uint64_t scrb_total = scrb_alu + scrb_fpu + scrb_lsu + scrb_sfu; + fprintf(stream, "PERF: scheduler stalls=%ld (%d%%)\n", scheduler_stalls, scheduler_percent); + fprintf(stream, "PERF: fetch stalls=%ld (%d%%)\n", fetch_stalls, fetch_percent); + fprintf(stream, "PERF: ibuffer stalls=%ld (%d%%)\n", ibuffer_stalls, ibuffer_percent); + fprintf(stream, "PERF: scoreboard stalls=%ld (alu=%d%%, fpu=%d%%, lsu=%d%%, sfu=%d%%)\n", scrb_stalls, + calcAvgPercent(scrb_alu, scrb_total), + calcAvgPercent(scrb_fpu, scrb_total), + calcAvgPercent(scrb_lsu, scrb_total), + calcAvgPercent(scrb_sfu, scrb_total)); fprintf(stream, "PERF: alu unit stalls=%ld\n", alu_stalls); fprintf(stream, "PERF: lsu unit stalls=%ld\n", lsu_stalls); fprintf(stream, "PERF: fpu unit stalls=%ld\n", fpu_stalls); @@ -419,31 +480,32 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { l2cache_write_misses /= num_cores; l2cache_bank_stalls /= num_cores; l2cache_mshr_stalls /= num_cores; - int l2cache_read_hit_ratio = calcRatio(l2cache_read_misses, l2cache_reads); - int l2cache_write_hit_ratio = calcRatio(l2cache_write_misses, l2cache_writes); - int l2cache_bank_utilization = calcUtilization(l2cache_reads + l2cache_writes, l2cache_bank_stalls); - + int read_hit_ratio = calcRatio(l2cache_read_misses, l2cache_reads); + int write_hit_ratio = calcRatio(l2cache_write_misses, l2cache_writes); + int bank_utilization = calcAvgPercent(l2cache_reads + l2cache_writes, l2cache_reads + l2cache_writes + l2cache_bank_stalls); + int mshr_utilization = calcAvgPercent(l2cache_read_misses + l2cache_write_misses, l2cache_read_misses + l2cache_write_misses + l2cache_mshr_stalls); fprintf(stream, "PERF: l2cache reads=%ld\n", l2cache_reads); fprintf(stream, "PERF: l2cache writes=%ld\n", l2cache_writes); - fprintf(stream, "PERF: l2cache read misses=%ld (hit ratio=%d%%)\n", l2cache_read_misses, l2cache_read_hit_ratio); - fprintf(stream, "PERF: l2cache write misses=%ld (hit ratio=%d%%)\n", l2cache_write_misses, l2cache_write_hit_ratio); - fprintf(stream, "PERF: l2cache bank stalls=%ld (utilization=%d%%)\n", l2cache_bank_stalls, l2cache_bank_utilization); - fprintf(stream, "PERF: l2cache mshr stalls=%ld\n", l2cache_mshr_stalls); + fprintf(stream, "PERF: l2cache read misses=%ld (hit ratio=%d%%)\n", l2cache_read_misses, read_hit_ratio); + fprintf(stream, "PERF: l2cache write misses=%ld (hit ratio=%d%%)\n", l2cache_write_misses, write_hit_ratio); + fprintf(stream, "PERF: l2cache bank stalls=%ld (utilization=%d%%)\n", l2cache_bank_stalls, bank_utilization); + fprintf(stream, "PERF: l2cache mshr stalls=%ld (utilization=%d%%)\n", l2cache_mshr_stalls, mshr_utilization); } if (l3cache_enable) { - int l3cache_read_hit_ratio = calcRatio(l3cache_read_misses, l3cache_reads); - int l3cache_write_hit_ratio = calcRatio(l3cache_write_misses, l3cache_writes); - int l3cache_bank_utilization = calcUtilization(l3cache_reads + l3cache_writes, l3cache_bank_stalls); + int read_hit_ratio = calcRatio(l3cache_read_misses, l3cache_reads); + int write_hit_ratio = calcRatio(l3cache_write_misses, l3cache_writes); + int bank_utilization = calcAvgPercent(l3cache_reads + l3cache_writes, l3cache_reads + l3cache_writes + l3cache_bank_stalls); + int mshr_utilization = calcAvgPercent(l3cache_read_misses + l3cache_write_misses, l3cache_read_misses + l3cache_write_misses + l3cache_mshr_stalls); fprintf(stream, "PERF: l3cache reads=%ld\n", l3cache_reads); fprintf(stream, "PERF: l3cache writes=%ld\n", l3cache_writes); - fprintf(stream, "PERF: l3cache read misses=%ld (hit ratio=%d%%)\n", l3cache_read_misses, l3cache_read_hit_ratio); - fprintf(stream, "PERF: l3cache write misses=%ld (hit ratio=%d%%)\n", l3cache_write_misses, l3cache_write_hit_ratio); - fprintf(stream, "PERF: l3cache bank stalls=%ld (utilization=%d%%)\n", l3cache_bank_stalls, l3cache_bank_utilization); - fprintf(stream, "PERF: l3cache mshr stalls=%ld\n", l3cache_mshr_stalls); + fprintf(stream, "PERF: l3cache read misses=%ld (hit ratio=%d%%)\n", l3cache_read_misses, read_hit_ratio); + fprintf(stream, "PERF: l3cache write misses=%ld (hit ratio=%d%%)\n", l3cache_write_misses, write_hit_ratio); + fprintf(stream, "PERF: l3cache bank stalls=%ld (utilization=%d%%)\n", l3cache_bank_stalls, bank_utilization); + fprintf(stream, "PERF: l3cache mshr stalls=%ld (utilization=%d%%)\n", l3cache_mshr_stalls, mshr_utilization); } - int mem_avg_lat = caclAvgLatency(mem_lat, mem_reads); + int mem_avg_lat = caclAverage(mem_lat, mem_reads); fprintf(stream, "PERF: memory requests=%ld (reads=%ld, writes=%ld)\n", (mem_reads + mem_writes), mem_reads, mem_writes); fprintf(stream, "PERF: memory latency=%d cycles\n", mem_avg_lat); } break; diff --git a/sim/simx/cache_cluster.h b/sim/simx/cache_cluster.h index be3146d3..aef28d1a 100644 --- a/sim/simx/cache_cluster.h +++ b/sim/simx/cache_cluster.h @@ -45,20 +45,20 @@ public: char sname[100]; - std::vector::Ptr> unit_arbs(num_units); + std::vector unit_arbs(num_units); for (uint32_t u = 0; u < num_units; ++u) { snprintf(sname, 100, "%s-unit-arb-%d", name, u); - unit_arbs.at(u) = Switch::Create(sname, ArbiterType::RoundRobin, num_requests, config.num_inputs); + unit_arbs.at(u) = MemSwitch::Create(sname, ArbiterType::RoundRobin, num_requests, config.num_inputs); for (uint32_t i = 0; i < num_requests; ++i) { this->CoreReqPorts.at(u).at(i).bind(&unit_arbs.at(u)->ReqIn.at(i)); unit_arbs.at(u)->RspIn.at(i).bind(&this->CoreRspPorts.at(u).at(i)); } } - std::vector::Ptr> mem_arbs(config.num_inputs); + std::vector mem_arbs(config.num_inputs); for (uint32_t i = 0; i < config.num_inputs; ++i) { snprintf(sname, 100, "%s-mem-arb-%d", name, i); - mem_arbs.at(i) = Switch::Create(sname, ArbiterType::RoundRobin, num_units, num_caches); + mem_arbs.at(i) = MemSwitch::Create(sname, ArbiterType::RoundRobin, num_units, num_caches); for (uint32_t u = 0; u < num_units; ++u) { unit_arbs.at(u)->ReqOut.at(i).bind(&mem_arbs.at(i)->ReqIn.at(u)); mem_arbs.at(i)->RspIn.at(u).bind(&unit_arbs.at(u)->RspOut.at(i)); @@ -66,7 +66,7 @@ public: } snprintf(sname, 100, "%s-cache-arb", name); - auto cache_arb = Switch::Create(sname, ArbiterType::RoundRobin, num_caches, 1); + auto cache_arb = MemSwitch::Create(sname, ArbiterType::RoundRobin, num_caches, 1); for (uint32_t i = 0; i < num_caches; ++i) { snprintf(sname, 100, "%s-cache%d", name, i); diff --git a/sim/simx/cache_sim.cpp b/sim/simx/cache_sim.cpp index 5a6906a9..2c9410f4 100644 --- a/sim/simx/cache_sim.cpp +++ b/sim/simx/cache_sim.cpp @@ -41,19 +41,16 @@ struct params_t { uint32_t tag_select_addr_end; params_t(const CacheSim::Config& config) { - int32_t bank_bits = log2ceil(config.num_banks); - int32_t offset_bits = config.B - config.W; - int32_t log2_bank_size = config.C - bank_bits; - int32_t index_bits = log2_bank_size - (config.B + config.A); - assert(log2_bank_size > 0); + int32_t offset_bits = config.L - config.W; + int32_t index_bits = config.C - (config.L + config.A + config.B); assert(offset_bits >= 0); assert(index_bits >= 0); this->log2_num_inputs = log2ceil(config.num_inputs); - this->words_per_line = 1 << offset_bits; + this->sets_per_bank = 1 << index_bits; this->lines_per_set = 1 << config.A; - this->sets_per_bank = 1 << index_bits; + this->words_per_line = 1 << offset_bits; assert(config.ports_per_bank <= this->words_per_line); @@ -63,7 +60,7 @@ struct params_t { // Bank select this->bank_select_addr_start = (1+this->word_select_addr_end); - this->bank_select_addr_end = (this->bank_select_addr_start+bank_bits-1); + this->bank_select_addr_end = (this->bank_select_addr_start+config.B-1); // Set select this->set_select_addr_start = (1+this->bank_select_addr_end); @@ -74,23 +71,23 @@ struct params_t { this->tag_select_addr_end = (config.addr_width-1); } - uint32_t addr_bank_id(uint64_t word_addr) const { + uint32_t addr_bank_id(uint64_t addr) const { if (bank_select_addr_end >= bank_select_addr_start) - return (uint32_t)bit_getw(word_addr, bank_select_addr_start, bank_select_addr_end); + return (uint32_t)bit_getw(addr, bank_select_addr_start, bank_select_addr_end); else return 0; } - uint32_t addr_set_id(uint64_t word_addr) const { + uint32_t addr_set_id(uint64_t addr) const { if (set_select_addr_end >= set_select_addr_start) - return (uint32_t)bit_getw(word_addr, set_select_addr_start, set_select_addr_end); + return (uint32_t)bit_getw(addr, set_select_addr_start, set_select_addr_end); else return 0; } - uint64_t addr_tag(uint64_t word_addr) const { + uint64_t addr_tag(uint64_t addr) const { if (tag_select_addr_end >= tag_select_addr_start) - return bit_getw(word_addr, tag_select_addr_start, tag_select_addr_end); + return bit_getw(addr, tag_select_addr_start, tag_select_addr_end); else return 0; } @@ -288,8 +285,8 @@ private: Config config_; params_t params_; std::vector banks_; - Switch::Ptr bank_switch_; - Switch::Ptr bypass_switch_; + MemSwitch::Ptr bank_switch_; + MemSwitch::Ptr bypass_switch_; std::vector> mem_req_ports_; std::vector> mem_rsp_ports_; std::vector pipeline_reqs_; @@ -304,16 +301,16 @@ public: : simobject_(simobject) , config_(config) , params_(config) - , banks_(config.num_banks, {config, params_}) - , mem_req_ports_(config.num_banks, simobject) - , mem_rsp_ports_(config.num_banks, simobject) - , pipeline_reqs_(config.num_banks, config.ports_per_bank) + , banks_((1 << config.B), {config, params_}) + , mem_req_ports_((1 << config.B), simobject) + , mem_rsp_ports_((1 << config.B), simobject) + , pipeline_reqs_((1 << config.B), config.ports_per_bank) { char sname[100]; snprintf(sname, 100, "%s-bypass-arb", simobject->name().c_str()); if (config_.bypass) { - bypass_switch_ = Switch::Create(sname, ArbiterType::RoundRobin, config_.num_inputs); + bypass_switch_ = MemSwitch::Create(sname, ArbiterType::RoundRobin, config_.num_inputs); for (uint32_t i = 0; i < config_.num_inputs; ++i) { simobject->CoreReqPorts.at(i).bind(&bypass_switch_->ReqIn.at(i)); bypass_switch_->RspIn.at(i).bind(&simobject->CoreRspPorts.at(i)); @@ -323,14 +320,14 @@ public: return; } - bypass_switch_ = Switch::Create(sname, ArbiterType::Priority, 2); + bypass_switch_ = MemSwitch::Create(sname, ArbiterType::Priority, 2); bypass_switch_->ReqOut.at(0).bind(&simobject->MemReqPort); simobject->MemRspPort.bind(&bypass_switch_->RspOut.at(0)); - if (config.num_banks > 1) { + if (config.B != 0) { snprintf(sname, 100, "%s-bank-arb", simobject->name().c_str()); - bank_switch_ = Switch::Create(sname, ArbiterType::RoundRobin, config.num_banks); - for (uint32_t i = 0, n = config.num_banks; i < n; ++i) { + bank_switch_ = MemSwitch::Create(sname, ArbiterType::RoundRobin, (1 << config.B)); + for (uint32_t i = 0, n = (1 << config.B); i < n; ++i) { mem_req_ports_.at(i).bind(&bank_switch_->ReqIn.at(i)); bank_switch_->RspIn.at(i).bind(&mem_rsp_ports_.at(i)); } @@ -383,20 +380,22 @@ public: pipeline_req.clear(); } - // schedule MSHR replay - for (uint32_t bank_id = 0, n = config_.num_banks; bank_id < n; ++bank_id) { + // first: schedule MSHR replay (flush MSHR queue) + for (uint32_t bank_id = 0, n = (1 << config_.B); bank_id < n; ++bank_id) { auto& bank = banks_.at(bank_id); auto& pipeline_req = pipeline_reqs_.at(bank_id); bank.mshr.pop(&pipeline_req); } - // schedule memory fill - for (uint32_t bank_id = 0, n = config_.num_banks; bank_id < n; ++bank_id) { + // second: schedule memory fill (flush memory queue) + for (uint32_t bank_id = 0, n = (1 << config_.B); bank_id < n; ++bank_id) { auto& mem_rsp_port = mem_rsp_ports_.at(bank_id); if (mem_rsp_port.empty()) continue; auto& pipeline_req = pipeline_reqs_.at(bank_id); + + // skip if bank already busy if (pipeline_req.type != bank_req_t::None) continue; @@ -407,7 +406,7 @@ public: mem_rsp_port.pop(); } - // schedule core requests + // last: schedule core requests (flush core queue) for (uint32_t req_id = 0, n = config_.num_inputs; req_id < n; ++req_id) { auto& core_req_port = simobject_->CoreReqPorts.at(req_id); if (core_req_port.empty()) @@ -425,18 +424,21 @@ public: } auto bank_id = params_.addr_bank_id(core_req.addr); - auto set_id = params_.addr_set_id(core_req.addr); - auto tag = params_.addr_tag(core_req.addr); - auto port_id = req_id % config_.ports_per_bank; - auto& bank = banks_.at(bank_id); auto& pipeline_req = pipeline_reqs_.at(bank_id); + // skip if bank already busy + if (pipeline_req.type != bank_req_t::None) + continue; + + auto set_id = params_.addr_set_id(core_req.addr); + auto tag = params_.addr_tag(core_req.addr); + auto port_id = req_id % config_.ports_per_bank; + // check MSHR capacity if ((!core_req.write || !config_.write_through) && bank.mshr.full()) { ++perf_stats_.mshr_stalls; - ++perf_stats_.bank_stalls; continue; } @@ -452,7 +454,7 @@ public: } // extend request ports pipeline_req.ports.at(port_id) = bank_req_port_t{req_id, core_req.tag, true}; - } else if (pipeline_req.type == bank_req_t::None) { + } else { // schedule new request bank_req_t bank_req(config_.ports_per_bank); bank_req.ports.at(port_id) = bank_req_port_t{req_id, core_req.tag, true}; @@ -463,10 +465,6 @@ public: bank_req.type = bank_req_t::Core; bank_req.write = core_req.write; pipeline_req = bank_req; - } else { - // bank in use - ++perf_stats_.bank_stalls; - continue; } if (core_req.write) @@ -516,7 +514,7 @@ private: } void processBankRequests() { - for (uint32_t bank_id = 0, n = config_.num_banks; bank_id < n; ++bank_id) { + for (uint32_t bank_id = 0, n = (1 << config_.B); bank_id < n; ++bank_id) { auto& bank = banks_.at(bank_id); auto pipeline_req = pipeline_reqs_.at(bank_id); @@ -545,11 +543,10 @@ private: } } } break; - case bank_req_t::Core: { - bool hit = false; - bool found_free_line = false; - uint32_t hit_line_id = 0; - uint32_t repl_line_id = 0; + case bank_req_t::Core: { + int32_t hit_line_id = -1; + int32_t free_line_id = -1; + int32_t repl_line_id = 0; uint32_t max_cnt = 0; auto& set = bank.sets.at(pipeline_req.set_id); @@ -557,38 +554,34 @@ private: // tag lookup for (uint32_t i = 0, n = set.lines.size(); i < n; ++i) { auto& line = set.lines.at(i); + if (max_cnt < line.lru_ctr) { + max_cnt = line.lru_ctr; + repl_line_id = i; + } if (line.valid) { - if (line.tag == pipeline_req.tag) { - line.lru_ctr = 0; + if (line.tag == pipeline_req.tag) { hit_line_id = i; - hit = true; + line.lru_ctr = 0; } else { ++line.lru_ctr; } - if (max_cnt < line.lru_ctr) { - max_cnt = line.lru_ctr; - repl_line_id = i; - } } else { - found_free_line = true; - repl_line_id = i; + free_line_id = i; } } - if (hit) { - // - // Hit handling - // + if (hit_line_id != -1) { + // Hit handling if (pipeline_req.write) { - // handle write hit + // handle write has_hit auto& hit_line = set.lines.at(hit_line_id); if (config_.write_through) { // forward write request to memory MemReq mem_req; - mem_req.addr = params_.mem_addr(bank_id, pipeline_req.set_id, hit_line.tag); + mem_req.addr = params_.mem_addr(bank_id, pipeline_req.set_id, pipeline_req.tag); mem_req.write = true; - mem_req.cid = pipeline_req.cid; - mem_req.uuid = pipeline_req.uuid; + mem_req.cid = pipeline_req.cid; + mem_req.uuid = pipeline_req.uuid; mem_req_ports_.at(bank_id).send(mem_req, 1); DT(3, simobject_->name() << "-dram-" << mem_req); } else { @@ -606,23 +599,21 @@ private: DT(3, simobject_->name() << "-core-" << core_rsp); } } - } else { - // - // Miss handling - // + } else { + // Miss handling if (pipeline_req.write) ++perf_stats_.write_misses; else ++perf_stats_.read_misses; - if (!found_free_line && !config_.write_through) { + if (free_line_id == -1 && !config_.write_through) { // write back dirty line auto& repl_line = set.lines.at(repl_line_id); if (repl_line.dirty) { MemReq mem_req; mem_req.addr = params_.mem_addr(bank_id, pipeline_req.set_id, repl_line.tag); mem_req.write = true; - mem_req.cid = pipeline_req.cid; + mem_req.cid = pipeline_req.cid; mem_req_ports_.at(bank_id).send(mem_req, 1); DT(3, simobject_->name() << "-dram-" << mem_req); ++perf_stats_.evictions; @@ -635,8 +626,8 @@ private: MemReq mem_req; mem_req.addr = params_.mem_addr(bank_id, pipeline_req.set_id, pipeline_req.tag); mem_req.write = true; - mem_req.cid = pipeline_req.cid; - mem_req.uuid = pipeline_req.uuid; + mem_req.cid = pipeline_req.cid; + mem_req.uuid = pipeline_req.uuid; mem_req_ports_.at(bank_id).send(mem_req, 1); DT(3, simobject_->name() << "-dram-" << mem_req); } @@ -655,7 +646,7 @@ private: auto mshr_pending = bank.mshr.lookup(pipeline_req); // allocate MSHR - auto mshr_id = bank.mshr.allocate(pipeline_req, repl_line_id); + auto mshr_id = bank.mshr.allocate(pipeline_req, (free_line_id != -1) ? free_line_id : repl_line_id); // send fill request if (!mshr_pending) { @@ -663,8 +654,8 @@ private: mem_req.addr = params_.mem_addr(bank_id, pipeline_req.set_id, pipeline_req.tag); mem_req.write = false; mem_req.tag = mshr_id; - mem_req.cid = pipeline_req.cid; - mem_req.uuid = pipeline_req.uuid; + mem_req.cid = pipeline_req.cid; + mem_req.uuid = pipeline_req.uuid; mem_req_ports_.at(bank_id).send(mem_req, 1); DT(3, simobject_->name() << "-dram-" << mem_req); ++pending_fill_reqs_; diff --git a/sim/simx/cache_sim.h b/sim/simx/cache_sim.h index 498fb73f..2faea91d 100644 --- a/sim/simx/cache_sim.h +++ b/sim/simx/cache_sim.h @@ -23,16 +23,15 @@ public: struct Config { bool bypass; // cache bypass uint8_t C; // log2 cache size - uint8_t B; // log2 block size + uint8_t L; // log2 line size uint8_t W; // log2 word size uint8_t A; // log2 associativity - uint8_t addr_width; // word address bits - uint8_t num_banks; // number of banks + uint8_t B; // log2 number of banks + uint8_t addr_width; // word address bits uint8_t ports_per_bank; // number of ports per bank uint8_t num_inputs; // number of inputs bool write_through; // is write-through bool write_reponse; // enable write response - uint16_t victim_size; // victim cache size uint16_t mshr_size; // MSHR buffer size uint8_t latency; // pipeline latency }; diff --git a/sim/simx/cluster.cpp b/sim/simx/cluster.cpp index a129ddaa..d7104915 100644 --- a/sim/simx/cluster.cpp +++ b/sim/simx/cluster.cpp @@ -36,16 +36,15 @@ Cluster::Cluster(const SimContext& ctx, l2cache_ = CacheSim::Create(sname, CacheSim::Config{ !L2_ENABLED, log2ceil(L2_CACHE_SIZE), // C - log2ceil(MEM_BLOCK_SIZE), // B + log2ceil(MEM_BLOCK_SIZE), // L log2ceil(L2_NUM_WAYS), // W 0, // A + log2ceil(L2_NUM_BANKS), // B XLEN, // address bits - L2_NUM_BANKS, // number of banks 1, // number of ports 5, // request size true, // write-through false, // write response - 0, // victim size L2_MSHR_SIZE, // mshr 2, // pipeline latency }); @@ -57,16 +56,15 @@ Cluster::Cluster(const SimContext& ctx, icaches_ = CacheCluster::Create(sname, num_cores, NUM_ICACHES, 1, CacheSim::Config{ !ICACHE_ENABLED, log2ceil(ICACHE_SIZE), // C - log2ceil(L1_LINE_SIZE), // B + log2ceil(L1_LINE_SIZE), // L log2ceil(sizeof(uint32_t)), // W log2ceil(ICACHE_NUM_WAYS),// A - XLEN, // address bits - 1, // number of banks + 1, // B + XLEN, // address bits 1, // number of ports 1, // number of inputs true, // write-through false, // write response - 0, // victim size (uint8_t)arch.num_warps(), // mshr 2, // pipeline latency }); @@ -78,16 +76,15 @@ Cluster::Cluster(const SimContext& ctx, dcaches_ = CacheCluster::Create(sname, num_cores, NUM_DCACHES, NUM_LSU_LANES, CacheSim::Config{ !DCACHE_ENABLED, log2ceil(DCACHE_SIZE), // C - log2ceil(L1_LINE_SIZE), // B + log2ceil(L1_LINE_SIZE), // L log2ceil(sizeof(Word)), // W log2ceil(DCACHE_NUM_WAYS),// A - XLEN, // address bits - DCACHE_NUM_BANKS, // number of banks + log2ceil(DCACHE_NUM_BANKS), // B + XLEN, // address bits 1, // number of ports DCACHE_NUM_BANKS, // number of inputs true, // write-through false, // write response - 0, // victim size DCACHE_MSHR_SIZE, // mshr 4, // pipeline latency }); @@ -129,11 +126,11 @@ Cluster::Cluster(const SimContext& ctx, cores_.at(i)->dcache_req_ports.at(j).bind(&smem_demux->ReqIn); smem_demux->RspIn.bind(&cores_.at(i)->dcache_rsp_ports.at(j)); - smem_demux->ReqDc.bind(&dcaches_->CoreReqPorts.at(i).at(j)); - dcaches_->CoreRspPorts.at(i).at(j).bind(&smem_demux->RspDc); + smem_demux->ReqDC.bind(&dcaches_->CoreReqPorts.at(i).at(j)); + dcaches_->CoreRspPorts.at(i).at(j).bind(&smem_demux->RspDC); - smem_demux->ReqSm.bind(&sharedmems_.at(i)->Inputs.at(j)); - sharedmems_.at(i)->Outputs.at(j).bind(&smem_demux->RspSm); + smem_demux->ReqSM.bind(&sharedmems_.at(i)->Inputs.at(j)); + sharedmems_.at(i)->Outputs.at(j).bind(&smem_demux->RspSM); } } } diff --git a/sim/simx/core.cpp b/sim/simx/core.cpp index f2931324..b2fe7ea2 100644 --- a/sim/simx/core.cpp +++ b/sim/simx/core.cpp @@ -45,19 +45,21 @@ Core::Core(const SimContext& ctx, , warps_(arch.num_warps()) , barriers_(arch.num_barriers(), 0) , fcsrs_(arch.num_warps(), 0) - , ibuffers_(ISSUE_WIDTH, IBUF_SIZE) + , ibuffers_(arch.num_warps(), IBUF_SIZE) , scoreboard_(arch_) , operands_(ISSUE_WIDTH) - , dispatchers_((uint32_t)ExeType::MAX) - , exe_units_((uint32_t)ExeType::MAX) + , dispatchers_((uint32_t)ExeType::ExeTypeCount) + , exe_units_((uint32_t)ExeType::ExeTypeCount) , sharedmem_(sharedmem) , fetch_latch_("fetch") , decode_latch_("decode") , pending_icache_(arch_.num_warps()) - , committed_traces_(ISSUE_WIDTH, nullptr) , csrs_(arch.num_warps()) , cluster_(cluster) -{ + , commit_arbs_(ISSUE_WIDTH) +{ + char sname[100]; + for (uint32_t i = 0; i < arch_.num_warps(); ++i) { csrs_.at(i).resize(arch.num_threads()); } @@ -82,6 +84,16 @@ Core::Core(const SimContext& ctx, exe_units_.at((int)ExeType::LSU) = SimPlatform::instance().create_object(this); exe_units_.at((int)ExeType::SFU) = SimPlatform::instance().create_object(this); + // bind commit arbiters + for (uint32_t i = 0; i < ISSUE_WIDTH; ++i) { + snprintf(sname, 100, "commit-arb%d", i); + auto arbiter = TraceSwitch::Create(sname, ArbiterType::RoundRobin, (uint32_t)ExeType::ExeTypeCount, 1); + for (uint32_t j = 0; j < (uint32_t)ExeType::ExeTypeCount; ++j) { + exe_units_.at(j)->Outputs.at(i).bind(&arbiter->Inputs.at(j)); + } + commit_arbs_.at(i) = arbiter; + } + this->reset(); } @@ -99,8 +111,12 @@ void Core::reset() { for (auto& exe_unit : exe_units_) { exe_unit->reset(); } + + for (auto& commit_arb : commit_arbs_) { + commit_arb->reset(); + } - for ( auto& barrier : barriers_) { + for (auto& barrier : barriers_) { barrier.reset(); } @@ -112,7 +128,7 @@ void Core::reset() { ibuf.clear(); } - commit_exe_= 0; + ibuffer_idx_ = 0; scoreboard_.clear(); fetch_latch_.clear(); @@ -150,8 +166,10 @@ void Core::schedule() { break; } } - if (scheduled_warp == -1) + if (scheduled_warp == -1) { + ++perf_stats_.sched_stalls; return; + } // suspend warp until decode stalled_warps_.set(scheduled_warp); @@ -192,11 +210,11 @@ void Core::fetch() { mem_req.tag = pending_icache_.allocate(trace); mem_req.cid = trace->cid; mem_req.uuid = trace->uuid; - icache_req_ports.at(0).send(mem_req, 1); + icache_req_ports.at(0).send(mem_req, 2); DT(3, "icache-req: addr=0x" << std::hex << mem_req.addr << ", tag=" << mem_req.tag << ", " << *trace); - fetch_latch_.pop(); - ++pending_ifetches_; + fetch_latch_.pop(); ++perf_stats_.ifetches; + ++pending_ifetches_; } void Core::decode() { @@ -206,7 +224,7 @@ void Core::decode() { auto trace = decode_latch_.front(); // check ibuffer capacity - auto& ibuffer = ibuffers_.at(trace->wid % ISSUE_WIDTH); + auto& ibuffer = ibuffers_.at(trace->wid); if (ibuffer.full()) { if (!trace->log_once(true)) { DT(3, "*** ibuffer-stall: " << *trace); @@ -239,7 +257,7 @@ void Core::decode() { } void Core::issue() { - // operands to dispatch + // operands to dispatchers for (uint32_t i = 0; i < ISSUE_WIDTH; ++i) { auto& operand = operands_.at(i); if (operand->Output.empty()) @@ -257,7 +275,8 @@ void Core::issue() { // issue ibuffer instructions for (uint32_t i = 0; i < ISSUE_WIDTH; ++i) { - auto& ibuffer = ibuffers_.at(i); + uint32_t ii = (ibuffer_idx_ + i) % ibuffers_.size(); + auto& ibuffer = ibuffers_.at(ii); if (ibuffer.empty()) continue; @@ -265,17 +284,27 @@ void Core::issue() { // check scoreboard if (scoreboard_.in_use(trace)) { + auto uses = scoreboard_.get_uses(trace); if (!trace->log_once(true)) { - DTH(3, "*** scoreboard-stall: dependents={"); - auto uses = scoreboard_.get_uses(trace); + DTH(3, "*** scoreboard-stall: dependents={"); for (uint32_t j = 0, n = uses.size(); j < n; ++j) { auto& use = uses.at(j); __unused (use); if (j) DTN(3, ", "); - DTN(3, use.type << use.reg << "(#" << use.owner << ")"); + DTN(3, use.reg_type << use.reg_id << "(#" << use.uuid << ")"); } DTN(3, "}, " << *trace << std::endl); } + for (uint32_t j = 0, n = uses.size(); j < n; ++j) { + auto& use = uses.at(j); + switch (use.exe_type) { + case ExeType::ALU: ++perf_stats_.scrb_alu; break; + case ExeType::FPU: ++perf_stats_.scrb_fpu; break; + case ExeType::LSU: ++perf_stats_.scrb_lsu; break; + case ExeType::SFU: ++perf_stats_.scrb_sfu; break; + default: assert(false); + } + } ++perf_stats_.scrb_stalls; continue; } else { @@ -294,10 +323,11 @@ void Core::issue() { ibuffer.pop(); } + ibuffer_idx_ += ISSUE_WIDTH; } void Core::execute() { - for (uint32_t i = 0; i < (uint32_t)ExeType::MAX; ++i) { + for (uint32_t i = 0; i < (uint32_t)ExeType::ExeTypeCount; ++i) { auto& dispatch = dispatchers_.at(i); auto& exe_unit = exe_units_.at(i); for (uint32_t j = 0; j < ISSUE_WIDTH; ++j) { @@ -313,10 +343,11 @@ void Core::execute() { void Core::commit() { // process completed instructions for (uint32_t i = 0; i < ISSUE_WIDTH; ++i) { - auto trace = committed_traces_.at(i); - if (!trace) + auto& commit_arb = commit_arbs_.at(i); + if (commit_arb->Outputs.at(0).empty()) continue; - committed_traces_.at(i) = nullptr; + + auto trace = commit_arb->Outputs.at(0).front(); // advance to commit stage DT(3, "pipeline-commit: " << *trace); @@ -334,27 +365,11 @@ void Core::commit() { perf_stats_.instrs += trace->tmask.count(); } + commit_arb->Outputs.at(0).pop(); + // delete the trace delete trace; } - - // select completed instructions - for (uint32_t i = 0; i < (uint32_t)ExeType::MAX; ++i) { - uint32_t ii = (commit_exe_ + i) % (uint32_t)ExeType::MAX; - auto& exe_unit = exe_units_.at(ii); - for (uint32_t j = 0; j < ISSUE_WIDTH; ++j) { - auto committed_trace = committed_traces_.at(j); - if (committed_trace) - continue; - auto& output = exe_unit->Outputs.at(j); - if (output.empty()) - continue; - auto trace = output.front(); - committed_traces_.at(j) = trace; - output.pop(); - } - } - ++commit_exe_; } void Core::wspawn(uint32_t num_warps, Word nextPC) { @@ -533,6 +548,10 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { break; case VX_DCR_MPM_CLASS_CORE: { switch (addr) { + case VX_CSR_MPM_SCHED_ST: return perf_stats_.sched_stalls & 0xffffffff; + case VX_CSR_MPM_SCHED_ST_H:return perf_stats_.sched_stalls >> 32; + case VX_CSR_MPM_FETCH_ST: return perf_stats_.fetch_stalls & 0xffffffff; + case VX_CSR_MPM_FETCH_ST_H:return perf_stats_.fetch_stalls >> 32; case VX_CSR_MPM_IBUF_ST: return perf_stats_.ibuf_stalls & 0xffffffff; case VX_CSR_MPM_IBUF_ST_H: return perf_stats_.ibuf_stalls >> 32; case VX_CSR_MPM_SCRB_ST: return perf_stats_.scrb_stalls & 0xffffffff; @@ -545,6 +564,14 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { case VX_CSR_MPM_FPU_ST_H: return perf_stats_.fpu_stalls >> 32; case VX_CSR_MPM_SFU_ST: return perf_stats_.sfu_stalls & 0xffffffff; case VX_CSR_MPM_SFU_ST_H: return perf_stats_.sfu_stalls >> 32; + case VX_CSR_MPM_SCRB_ALU: return perf_stats_.scrb_alu & 0xffffffff; + case VX_CSR_MPM_SCRB_ALU_H:return perf_stats_.scrb_alu >> 32; + case VX_CSR_MPM_SCRB_FPU: return perf_stats_.scrb_fpu & 0xffffffff; + case VX_CSR_MPM_SCRB_FPU_H:return perf_stats_.scrb_fpu >> 32; + case VX_CSR_MPM_SCRB_LSU: return perf_stats_.scrb_lsu & 0xffffffff; + case VX_CSR_MPM_SCRB_LSU_H:return perf_stats_.scrb_lsu >> 32; + case VX_CSR_MPM_SCRB_SFU: return perf_stats_.scrb_sfu & 0xffffffff; + case VX_CSR_MPM_SCRB_SFU_H:return perf_stats_.scrb_sfu >> 32; case VX_CSR_MPM_IFETCHES: return perf_stats_.ifetches & 0xffffffff; case VX_CSR_MPM_IFETCHES_H: return perf_stats_.ifetches >> 32; @@ -561,30 +588,25 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { case VX_DCR_MPM_CLASS_MEM: { auto proc_perf = cluster_->processor()->perf_stats(); switch (addr) { - case VX_CSR_MPM_ICACHE_READS: return proc_perf.clusters.icache.reads & 0xffffffff; - case VX_CSR_MPM_ICACHE_READS_H: return proc_perf.clusters.icache.reads >> 32; - case VX_CSR_MPM_ICACHE_MISS_R: return proc_perf.clusters.icache.read_misses & 0xffffffff; - case VX_CSR_MPM_ICACHE_MISS_R_H: return proc_perf.clusters.icache.read_misses >> 32; + case VX_CSR_MPM_ICACHE_READS: return proc_perf.clusters.icache.reads & 0xffffffff; + case VX_CSR_MPM_ICACHE_READS_H: return proc_perf.clusters.icache.reads >> 32; + case VX_CSR_MPM_ICACHE_MISS_R: return proc_perf.clusters.icache.read_misses & 0xffffffff; + case VX_CSR_MPM_ICACHE_MISS_R_H: return proc_perf.clusters.icache.read_misses >> 32; + case VX_CSR_MPM_ICACHE_MSHR_ST: return proc_perf.clusters.icache.mshr_stalls & 0xffffffff; + case VX_CSR_MPM_ICACHE_MSHR_ST_H: return proc_perf.clusters.icache.mshr_stalls >> 32; - case VX_CSR_MPM_DCACHE_READS: return proc_perf.clusters.dcache.reads & 0xffffffff; - case VX_CSR_MPM_DCACHE_READS_H: return proc_perf.clusters.dcache.reads >> 32; - case VX_CSR_MPM_DCACHE_WRITES: return proc_perf.clusters.dcache.writes & 0xffffffff; - case VX_CSR_MPM_DCACHE_WRITES_H: return proc_perf.clusters.dcache.writes >> 32; - case VX_CSR_MPM_DCACHE_MISS_R: return proc_perf.clusters.dcache.read_misses & 0xffffffff; - case VX_CSR_MPM_DCACHE_MISS_R_H: return proc_perf.clusters.dcache.read_misses >> 32; - case VX_CSR_MPM_DCACHE_MISS_W: return proc_perf.clusters.dcache.write_misses & 0xffffffff; - case VX_CSR_MPM_DCACHE_MISS_W_H: return proc_perf.clusters.dcache.write_misses >> 32; - case VX_CSR_MPM_DCACHE_BANK_ST: return proc_perf.clusters.dcache.bank_stalls & 0xffffffff; - case VX_CSR_MPM_DCACHE_BANK_ST_H:return proc_perf.clusters.dcache.bank_stalls >> 32; - case VX_CSR_MPM_DCACHE_MSHR_ST: return proc_perf.clusters.dcache.mshr_stalls & 0xffffffff; - case VX_CSR_MPM_DCACHE_MSHR_ST_H:return proc_perf.clusters.dcache.mshr_stalls >> 32; - - case VX_CSR_MPM_SMEM_READS: return proc_perf.clusters.sharedmem.reads & 0xffffffff; - case VX_CSR_MPM_SMEM_READS_H: return proc_perf.clusters.sharedmem.reads >> 32; - case VX_CSR_MPM_SMEM_WRITES: return proc_perf.clusters.sharedmem.writes & 0xffffffff; - case VX_CSR_MPM_SMEM_WRITES_H: return proc_perf.clusters.sharedmem.writes >> 32; - case VX_CSR_MPM_SMEM_BANK_ST: return proc_perf.clusters.sharedmem.bank_stalls & 0xffffffff; - case VX_CSR_MPM_SMEM_BANK_ST_H:return proc_perf.clusters.sharedmem.bank_stalls >> 32; + case VX_CSR_MPM_DCACHE_READS: return proc_perf.clusters.dcache.reads & 0xffffffff; + case VX_CSR_MPM_DCACHE_READS_H: return proc_perf.clusters.dcache.reads >> 32; + case VX_CSR_MPM_DCACHE_WRITES: return proc_perf.clusters.dcache.writes & 0xffffffff; + case VX_CSR_MPM_DCACHE_WRITES_H: return proc_perf.clusters.dcache.writes >> 32; + case VX_CSR_MPM_DCACHE_MISS_R: return proc_perf.clusters.dcache.read_misses & 0xffffffff; + case VX_CSR_MPM_DCACHE_MISS_R_H: return proc_perf.clusters.dcache.read_misses >> 32; + case VX_CSR_MPM_DCACHE_MISS_W: return proc_perf.clusters.dcache.write_misses & 0xffffffff; + case VX_CSR_MPM_DCACHE_MISS_W_H: return proc_perf.clusters.dcache.write_misses >> 32; + case VX_CSR_MPM_DCACHE_BANK_ST: return proc_perf.clusters.dcache.bank_stalls & 0xffffffff; + case VX_CSR_MPM_DCACHE_BANK_ST_H: return proc_perf.clusters.dcache.bank_stalls >> 32; + case VX_CSR_MPM_DCACHE_MSHR_ST: return proc_perf.clusters.dcache.mshr_stalls & 0xffffffff; + case VX_CSR_MPM_DCACHE_MSHR_ST_H: return proc_perf.clusters.dcache.mshr_stalls >> 32; case VX_CSR_MPM_L2CACHE_READS: return proc_perf.clusters.l2cache.reads & 0xffffffff; case VX_CSR_MPM_L2CACHE_READS_H: return proc_perf.clusters.l2cache.reads >> 32; @@ -612,12 +634,19 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { case VX_CSR_MPM_L3CACHE_MSHR_ST: return proc_perf.l3cache.mshr_stalls & 0xffffffff; case VX_CSR_MPM_L3CACHE_MSHR_ST_H:return proc_perf.l3cache.mshr_stalls >> 32; - case VX_CSR_MPM_MEM_READS: return proc_perf.mem_reads & 0xffffffff; - case VX_CSR_MPM_MEM_READS_H: return proc_perf.mem_reads >> 32; - case VX_CSR_MPM_MEM_WRITES: return proc_perf.mem_writes & 0xffffffff; - case VX_CSR_MPM_MEM_WRITES_H:return proc_perf.mem_writes >> 32; - case VX_CSR_MPM_MEM_LAT: return proc_perf.mem_latency & 0xffffffff; - case VX_CSR_MPM_MEM_LAT_H: return proc_perf.mem_latency >> 32; + case VX_CSR_MPM_MEM_READS: return proc_perf.mem_reads & 0xffffffff; + case VX_CSR_MPM_MEM_READS_H: return proc_perf.mem_reads >> 32; + case VX_CSR_MPM_MEM_WRITES: return proc_perf.mem_writes & 0xffffffff; + case VX_CSR_MPM_MEM_WRITES_H: return proc_perf.mem_writes >> 32; + case VX_CSR_MPM_MEM_LAT: return proc_perf.mem_latency & 0xffffffff; + case VX_CSR_MPM_MEM_LAT_H: return proc_perf.mem_latency >> 32; + + case VX_CSR_MPM_SMEM_READS: return proc_perf.clusters.sharedmem.reads & 0xffffffff; + case VX_CSR_MPM_SMEM_READS_H: return proc_perf.clusters.sharedmem.reads >> 32; + case VX_CSR_MPM_SMEM_WRITES: return proc_perf.clusters.sharedmem.writes & 0xffffffff; + case VX_CSR_MPM_SMEM_WRITES_H: return proc_perf.clusters.sharedmem.writes >> 32; + case VX_CSR_MPM_SMEM_BANK_ST: return proc_perf.clusters.sharedmem.bank_stalls & 0xffffffff; + case VX_CSR_MPM_SMEM_BANK_ST_H: return proc_perf.clusters.sharedmem.bank_stalls >> 32; } } break; } diff --git a/sim/simx/core.h b/sim/simx/core.h index ed06574d..60290bef 100644 --- a/sim/simx/core.h +++ b/sim/simx/core.h @@ -22,11 +22,11 @@ #include #include #include +#include #include "debug.h" #include "types.h" #include "arch.h" #include "decode.h" -#include "mem.h" #include "warp.h" #include "pipeline.h" #include "cache_sim.h" @@ -42,17 +42,25 @@ namespace vortex { class Cluster; +using TraceSwitch = Mux; + class Core : public SimObject { public: struct PerfStats { uint64_t cycles; uint64_t instrs; + uint64_t sched_stalls; + uint64_t fetch_stalls; uint64_t ibuf_stalls; uint64_t scrb_stalls; uint64_t alu_stalls; uint64_t lsu_stalls; uint64_t fpu_stalls; uint64_t sfu_stalls; + uint64_t scrb_alu; + uint64_t scrb_fpu; + uint64_t scrb_lsu; + uint64_t scrb_sfu; uint64_t ifetches; uint64_t loads; uint64_t stores; @@ -62,12 +70,18 @@ public: PerfStats() : cycles(0) , instrs(0) + , sched_stalls(0) + , fetch_stalls(0) , ibuf_stalls(0) , scrb_stalls(0) , alu_stalls(0) , lsu_stalls(0) , fpu_stalls(0) , sfu_stalls(0) + , scrb_alu(0) + , scrb_fpu(0) + , scrb_lsu(0) + , scrb_sfu(0) , ifetches(0) , loads(0) , stores(0) @@ -173,7 +187,6 @@ private: PipelineLatch decode_latch_; HashTable pending_icache_; - std::vector committed_traces_; WarpMask active_warps_; WarpMask stalled_warps_; uint64_t issued_instrs_; @@ -190,7 +203,9 @@ private: Cluster* cluster_; - uint32_t commit_exe_; + std::vector commit_arbs_; + + uint32_t ibuffer_idx_; friend class Warp; friend class LsuUnit; diff --git a/sim/simx/dispatcher.h b/sim/simx/dispatcher.h index a5c44b64..fe83e9de 100644 --- a/sim/simx/dispatcher.h +++ b/sim/simx/dispatcher.h @@ -66,6 +66,7 @@ public: } auto& output = Outputs.at(i); auto trace = input.front(); + auto new_trace = trace; if (pid_count_ != 1) { auto start_p = start_p_.at(b); if (start_p == -1) { @@ -81,33 +82,30 @@ public: end = j; } start /= num_lanes_; - end /= num_lanes_; - auto new_trace = new pipeline_trace_t(*trace); - new_trace->tmask.reset(); - for (int j = start * num_lanes_, n = j + num_lanes_; j < n; ++j) { - new_trace->tmask[j] = trace->tmask[j]; - } - new_trace->pid = start; - new_trace->sop = (start_p == 0); - if (start == end) { - new_trace->eop = 1; + end /= num_lanes_; + if (start != end) { + new_trace = new pipeline_trace_t(*trace); + new_trace->eop = false; + start_p_.at(b) = start + 1; + } else { start_p_.at(b) = -1; input.pop(); ++block_sent; - delete trace; - } else { - new_trace->eop = 0; - start_p_.at(b) = start + 1; - } - output.send(new_trace, 1); - DT(3, "pipeline-dispatch: " << *new_trace); + } + new_trace->pid = start; + new_trace->sop = (0 == start_p); + ThreadMask tmask; + for (int j = start * num_lanes_, n = j + num_lanes_; j < n; ++j) { + tmask[j] = trace->tmask[j]; + } + new_trace->tmask = tmask; } else { - trace->pid = 0; + new_trace->pid = 0; input.pop(); - output.send(trace, 1); - DT(3, "pipeline-dispatch: " << *trace); ++block_sent; - } + } + DT(3, "pipeline-dispatch: " << *new_trace); + output.send(new_trace, 1); } if (block_sent == block_size_) { batch_idx_ = (batch_idx_ + 1) % batch_count_; @@ -138,4 +136,4 @@ private: std::vector start_p_; }; -} \ No newline at end of file +} diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index da151b62..77021dbd 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -32,18 +32,17 @@ ProcessorImpl::ProcessorImpl(const Arch& arch) l3cache_ = CacheSim::Create("l3cache", CacheSim::Config{ !L3_ENABLED, log2ceil(L3_CACHE_SIZE), // C - log2ceil(MEM_BLOCK_SIZE), // B - log2ceil(L3_NUM_WAYS), // W - 0, // A - XLEN, // address bits - L3_NUM_BANKS, // number of banks - 1, // number of ports + log2ceil(MEM_BLOCK_SIZE), // L + log2ceil(L3_NUM_WAYS), // W + 0, // A + log2ceil(L3_NUM_BANKS), // B + XLEN, // address bits + 1, // number of ports uint8_t(arch.num_clusters()), // request size - true, // write-through - false, // write response - 0, // victim size - L3_MSHR_SIZE, // mshr - 2, // pipeline latency + true, // write-through + false, // write response + L3_MSHR_SIZE, // mshr + 2, // pipeline latency } ); diff --git a/sim/simx/scoreboard.h b/sim/simx/scoreboard.h index 4d311846..5c247b73 100644 --- a/sim/simx/scoreboard.h +++ b/sim/simx/scoreboard.h @@ -22,9 +22,10 @@ class Scoreboard { public: struct reg_use_t { - RegType type; - uint32_t reg; - uint64_t owner; + RegType reg_type; + uint32_t reg_id; + ExeType exe_type; + uint64_t uuid; }; Scoreboard(const Arch &arch) @@ -44,89 +45,81 @@ public: owners_.clear(); } - bool in_use(pipeline_trace_t* state) const { - return (state->used_iregs & in_use_iregs_.at(state->wid)) != 0 - || (state->used_fregs & in_use_fregs_.at(state->wid)) != 0 - || (state->used_vregs & in_use_vregs_.at(state->wid)) != 0; + bool in_use(pipeline_trace_t* trace) const { + return (trace->used_iregs & in_use_iregs_.at(trace->wid)) != 0 + || (trace->used_fregs & in_use_fregs_.at(trace->wid)) != 0 + || (trace->used_vregs & in_use_vregs_.at(trace->wid)) != 0; } - std::vector get_uses(pipeline_trace_t* state) const { - std::vector out; - { - uint32_t r = 0; - auto used_iregs = state->used_iregs & in_use_iregs_.at(state->wid); - while (used_iregs.any()) { - if (used_iregs.test(0)) { - uint32_t tag = (r << 16) | (state->wid << 4) | (int)RegType::Integer; - out.push_back({RegType::Integer, r, owners_.at(tag)}); - } - used_iregs >>= 1; - ++r; + std::vector get_uses(pipeline_trace_t* trace) const { + std::vector out; + + auto used_iregs = trace->used_iregs & in_use_iregs_.at(trace->wid); + auto used_fregs = trace->used_fregs & in_use_fregs_.at(trace->wid); + auto used_vregs = trace->used_vregs & in_use_vregs_.at(trace->wid); + + for (uint32_t r = 0; r < MAX_NUM_REGS; ++r) { + if (used_iregs.test(r)) { + uint32_t tag = (r << 16) | (trace->wid << 4) | (int)RegType::Integer; + auto owner = owners_.at(tag); + out.push_back({RegType::Integer, r, owner->exe_type, owner->uuid}); } } - { - uint32_t r = 0; - auto used_fregs = state->used_fregs & in_use_fregs_.at(state->wid); - while (used_fregs.any()) { - if (used_fregs.test(0)) { - uint32_t tag = (r << 16) | (state->wid << 4) | (int)RegType::Float; - out.push_back({RegType::Float, r, owners_.at(tag)}); - } - used_fregs >>= 1; - ++r; + + for (uint32_t r = 0; r < MAX_NUM_REGS; ++r) { + if (used_fregs.test(r)) { + uint32_t tag = (r << 16) | (trace->wid << 4) | (int)RegType::Float; + auto owner = owners_.at(tag); + out.push_back({RegType::Float, r, owner->exe_type, owner->uuid}); } } - { - uint32_t r = 0; - auto used_vregs = state->used_vregs & in_use_vregs_.at(state->wid); - while (used_vregs.any()) { - if (used_vregs.test(0)) { - uint32_t tag = (r << 16) | (state->wid << 4) | (int)RegType::Vector; - out.push_back({RegType::Vector, r, owners_.at(tag)}); - } - used_vregs >>= 1; - ++r; + + for (uint32_t r = 0; r < MAX_NUM_REGS; ++r) { + if (used_vregs.test(r)) { + uint32_t tag = (r << 16) | (trace->wid << 4) | (int)RegType::Vector; + auto owner = owners_.at(tag); + out.push_back({RegType::Vector, r, owner->exe_type, owner->uuid}); } } + return out; } - void reserve(pipeline_trace_t* state) { - assert(state->wb); - switch (state->rdest_type) { + void reserve(pipeline_trace_t* trace) { + assert(trace->wb); + switch (trace->rdest_type) { case RegType::Integer: - in_use_iregs_.at(state->wid).set(state->rdest); + in_use_iregs_.at(trace->wid).set(trace->rdest); break; case RegType::Float: - in_use_fregs_.at(state->wid).set(state->rdest); + in_use_fregs_.at(trace->wid).set(trace->rdest); break; case RegType::Vector: - in_use_vregs_.at(state->wid).set(state->rdest); - break; - default: + in_use_vregs_.at(trace->wid).set(trace->rdest); break; + default: assert(false); } - uint32_t tag = (state->rdest << 16) | (state->wid << 4) | (int)state->rdest_type; + uint32_t tag = (trace->rdest << 16) | (trace->wid << 4) | (int)trace->rdest_type; assert(owners_.count(tag) == 0); - owners_[tag] = state->uuid; + owners_[tag] = trace; + assert((int)trace->exe_type < 5); } - void release(pipeline_trace_t* state) { - assert(state->wb); - switch (state->rdest_type) { + void release(pipeline_trace_t* trace) { + assert(trace->wb); + switch (trace->rdest_type) { case RegType::Integer: - in_use_iregs_.at(state->wid).reset(state->rdest); + in_use_iregs_.at(trace->wid).reset(trace->rdest); break; case RegType::Float: - in_use_fregs_.at(state->wid).reset(state->rdest); + in_use_fregs_.at(trace->wid).reset(trace->rdest); break; case RegType::Vector: - in_use_vregs_.at(state->wid).reset(state->rdest); - break; - default: + in_use_vregs_.at(trace->wid).reset(trace->rdest); break; + default: assert(false); } - uint32_t tag = (state->rdest << 16) | (state->wid << 4) | (int)state->rdest_type; + uint32_t tag = (trace->rdest << 16) | (trace->wid << 4) | (int)trace->rdest_type; owners_.erase(tag); } @@ -135,7 +128,7 @@ private: std::vector in_use_iregs_; std::vector in_use_fregs_; std::vector in_use_vregs_; - std::unordered_map owners_; + std::unordered_map owners_; }; } \ No newline at end of file diff --git a/sim/simx/types.h b/sim/simx/types.h index 88b3ce0e..6bba7f9c 100644 --- a/sim/simx/types.h +++ b/sim/simx/types.h @@ -81,7 +81,7 @@ enum class ExeType { LSU, FPU, SFU, - MAX, + ExeTypeCount }; inline std::ostream &operator<<(std::ostream &os, const ExeType& type) { @@ -90,7 +90,7 @@ inline std::ostream &operator<<(std::ostream &os, const ExeType& type) { case ExeType::LSU: os << "LSU"; break; case ExeType::FPU: os << "FPU"; break; case ExeType::SFU: os << "SFU"; break; - case ExeType::MAX: break; + default: assert(false); } return os; } @@ -138,7 +138,7 @@ inline std::ostream &operator<<(std::ostream &os, const LsuType& type) { enum class AddrType { Global, Shared, - IO, + IO }; inline std::ostream &operator<<(std::ostream &os, const AddrType& type) { @@ -164,7 +164,7 @@ enum class FpuType { FMA, FDIV, FSQRT, - FCVT, + FCVT }; inline std::ostream &operator<<(std::ostream &os, const FpuType& type) { @@ -190,7 +190,7 @@ enum class SfuType { CSRRW, CSRRS, CSRRC, - CMOV + CMOV }; inline std::ostream &operator<<(std::ostream &os, const SfuType& type) { @@ -351,6 +351,92 @@ private: /////////////////////////////////////////////////////////////////////////////// +template +class Mux : public SimObject> { +public: + std::vector> Inputs; + std::vector> Outputs; + + Mux( + const SimContext& ctx, + const char* name, + ArbiterType type, + uint32_t num_inputs, + uint32_t num_outputs = 1, + uint32_t delay = 1 + ) : SimObject>(ctx, name) + , Inputs(num_inputs, this) + , Outputs(num_outputs, this) + , type_(type) + , delay_(delay) + , cursors_(num_outputs, 0) + , num_reqs_(num_inputs / num_outputs) + { + assert(delay != 0); + assert(num_inputs <= 32); + assert(num_outputs <= 32); + assert(num_inputs >= num_outputs); + + // bypass mode + if (num_inputs == num_outputs) { + for (uint32_t i = 0; i < num_inputs; ++i) { + Inputs.at(i).bind(&Outputs.at(i)); + } + } + } + + void reset() { + for (auto& cursor : cursors_) { + cursor = 0; + } + } + + void tick() { + uint32_t I = Inputs.size(); + uint32_t O = Outputs.size(); + uint32_t R = num_reqs_; + + // skip bypass mode + if (I == O) + return; + + // process inputs + for (uint32_t o = 0; o < O; ++o) { + for (uint32_t r = 0; r < R; ++r) { + uint32_t i = (cursors_.at(o) + r) & (R-1); + uint32_t j = o * R + i; + if (j >= I) + continue; + + auto& req_in = Inputs.at(j); + if (!req_in.empty()) { + auto& req = req_in.front(); + DT(4, this->name() << "-" << req); + Outputs.at(o).send(req, delay_); + req_in.pop(); + this->update_cursor(o, i); + break; + } + } + } + } + +private: + + void update_cursor(uint32_t index, uint32_t grant) { + if (type_ == ArbiterType::RoundRobin) { + cursors_.at(index) = grant + 1; + } + } + + ArbiterType type_; + uint32_t delay_; + std::vector cursors_; + uint32_t num_reqs_; +}; + +/////////////////////////////////////////////////////////////////////////////// + template class Switch : public SimObject> { public: @@ -364,13 +450,13 @@ public: const SimContext& ctx, const char* name, ArbiterType type, - uint32_t num_inputs = 1, + uint32_t num_inputs, uint32_t num_outputs = 1, uint32_t delay = 1 ) : SimObject>(ctx, name) - , ReqIn(num_inputs, this) - , RspIn(num_inputs, this) + , ReqIn(num_inputs, this) + , RspIn(num_inputs, this) , ReqOut(num_outputs, this) , RspOut(num_outputs, this) , type_(type) @@ -383,8 +469,8 @@ public: assert(num_outputs <= 32); assert(num_inputs >= num_outputs); + // bypass mode if (num_inputs == num_outputs) { - // bypass mode for (uint32_t i = 0; i < num_inputs; ++i) { ReqIn.at(i).bind(&ReqOut.at(i)); RspOut.at(i).bind(&RspIn.at(i)); @@ -462,14 +548,14 @@ private: class SMemDemux : public SimObject { public: - SimPort ReqIn; - SimPort RspIn; + SimPort ReqIn; + SimPort RspIn; - SimPort ReqSm; - SimPort RspSm; + SimPort ReqSM; + SimPort RspSM; - SimPort ReqDc; - SimPort RspDc; + SimPort ReqDC; + SimPort RspDC; SMemDemux( const SimContext& ctx, @@ -478,45 +564,49 @@ public: ) : SimObject(ctx, name) , ReqIn(this) , RspIn(this) - , ReqSm(this) - , RspSm(this) - , ReqDc(this) - , RspDc(this) + , ReqSM(this) + , RspSM(this) + , ReqDC(this) + , RspDC(this) , delay_(delay) {} void reset() {} - void tick() { + void tick() { + // process incoming reponses + if (!RspSM.empty()) { + auto& rsp = RspSM.front(); + DT(4, this->name() << "-" << rsp); + RspIn.send(rsp, 1); + RspSM.pop(); + } + if (!RspDC.empty()) { + auto& rsp = RspDC.front(); + DT(4, this->name() << "-" << rsp); + RspIn.send(rsp, 1); + RspDC + .pop(); + } // process incomming requests if (!ReqIn.empty()) { auto& req = ReqIn.front(); DT(4, this->name() << "-" << req); if (req.type == AddrType::Shared) { - ReqSm.send(req, delay_); + ReqSM.send(req, delay_); } else { - ReqDc.send(req, delay_); + ReqDC.send(req, delay_); } ReqIn.pop(); } - - // process incoming reponses - if (!RspSm.empty()) { - auto& rsp = RspSm.front(); - DT(4, this->name() << "-" << rsp); - RspIn.send(rsp, 1); - RspSm.pop(); - } - if (!RspDc.empty()) { - auto& rsp = RspDc.front(); - DT(4, this->name() << "-" << rsp); - RspIn.send(rsp, 1); - RspDc.pop(); - } } private: uint32_t delay_; }; -} \ No newline at end of file +/////////////////////////////////////////////////////////////////////////////// + +using MemSwitch = Switch; + +} From 24973ffca018e6a32e69cd523145c63a590fa250 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 27 Nov 2023 05:53:36 -0800 Subject: [PATCH 17/57] scoreboard optimization & profiling --- hw/rtl/core/VX_commit.sv | 46 +++--- hw/rtl/core/VX_core.sv | 6 +- hw/rtl/core/VX_csr_data.sv | 27 +++- hw/rtl/core/VX_issue.sv | 16 +- hw/rtl/core/VX_schedule.sv | 21 +++ hw/rtl/core/VX_scoreboard.sv | 182 ++++++++++++++--------- hw/rtl/interfaces/VX_pipeline_perf_if.sv | 14 +- hw/rtl/libs/VX_stream_xbar.sv | 6 +- 8 files changed, 206 insertions(+), 112 deletions(-) diff --git a/hw/rtl/core/VX_commit.sv b/hw/rtl/core/VX_commit.sv index e5dbe97c..a76f395b 100644 --- a/hw/rtl/core/VX_commit.sv +++ b/hw/rtl/core/VX_commit.sv @@ -44,7 +44,7 @@ module VX_commit import VX_gpu_pkg::*; #( VX_commit_if commit_if[`ISSUE_WIDTH](); - wire [`ISSUE_WIDTH-1:0] commit_fire; + wire [`ISSUE_WIDTH-1:0] commit_fire; wire [`ISSUE_WIDTH-1:0][`NW_WIDTH-1:0] commit_wid; wire [`ISSUE_WIDTH-1:0][`NUM_THREADS-1:0] commit_tmask; wire [`ISSUE_WIDTH-1:0] commit_eop; @@ -91,24 +91,22 @@ module VX_commit import VX_gpu_pkg::*; #( `UNUSED_PIN (sel_out) ); - assign commit_fire[i] = commit_if[i].valid && commit_if[i].ready; - assign commit_tmask[i] = {`NUM_THREADS{commit_fire[i]}} & commit_if[i].data.tmask; - assign commit_wid[i] = commit_if[i].data.wid; - assign commit_eop[i] = commit_if[i].data.eop; + assign commit_fire[i] = commit_if[i].valid && commit_if[i].ready; + assign commit_tmask[i]= {`NUM_THREADS{commit_fire[i]}} & commit_if[i].data.tmask; + assign commit_wid[i] = commit_if[i].data.wid; + assign commit_eop[i] = commit_if[i].data.eop; end // CSRs update wire [`ISSUE_WIDTH-1:0][COMMIT_SIZEW-1:0] commit_size, commit_size_r; - wire [COMMIT_ALL_SIZEW-1:0] commit_size_all, commit_size_all_r; + wire [COMMIT_ALL_SIZEW-1:0] commit_size_all_r, commit_size_all_rr; wire commit_fire_any, commit_fire_any_r, commit_fire_any_rr; assign commit_fire_any = (| commit_fire); for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin - wire [COMMIT_SIZEW-1:0] pop_count; - `POP_COUNT(pop_count, commit_tmask[i]); - assign commit_size[i] = pop_count; + `POP_COUNT(commit_size[i], commit_tmask[i]); end VX_pipe_register #( @@ -129,7 +127,7 @@ module VX_commit import VX_gpu_pkg::*; #( .OP ("+") ) commit_size_reduce ( .data_in (commit_size_r), - .data_out (commit_size_all) + .data_out (commit_size_all_r) ); VX_pipe_register #( @@ -139,26 +137,26 @@ module VX_commit import VX_gpu_pkg::*; #( .clk (clk), .reset (reset), .enable (1'b1), - .data_in ({commit_fire_any_r, commit_size_all}), - .data_out ({commit_fire_any_rr, commit_size_all_r}) + .data_in ({commit_fire_any_r, commit_size_all_r}), + .data_out ({commit_fire_any_rr, commit_size_all_rr}) ); reg [`PERF_CTR_BITS-1:0] instret; - always @(posedge clk) begin if (reset) begin instret <= '0; end else begin if (commit_fire_any_rr) begin - instret <= instret + `PERF_CTR_BITS'(commit_size_all_r); + instret <= instret + `PERF_CTR_BITS'(commit_size_all_rr); end end end - assign commit_csr_if.instret = instret; // Committed instructions + wire [`ISSUE_WIDTH-1:0] committed = commit_fire & commit_eop; + VX_pipe_register #( .DATAW (`ISSUE_WIDTH * (1 + `NW_WIDTH)), .RESETW (`ISSUE_WIDTH) @@ -166,23 +164,23 @@ module VX_commit import VX_gpu_pkg::*; #( .clk (clk), .reset (reset), .enable (1'b1), - .data_in ({(commit_fire & commit_eop), commit_wid}), + .data_in ({committed, commit_wid}), .data_out ({commit_sched_if.committed, commit_sched_if.committed_wid}) ); // Writeback for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin - assign writeback_if[i].valid = commit_if[i].valid && commit_if[i].data.wb; + assign writeback_if[i].valid = commit_if[i].valid && commit_if[i].data.wb; assign writeback_if[i].data.uuid = commit_if[i].data.uuid; - assign writeback_if[i].data.wis = wid_to_wis(commit_if[i].data.wid); - assign writeback_if[i].data.PC = commit_if[i].data.PC; - assign writeback_if[i].data.tmask = commit_if[i].data.tmask; - assign writeback_if[i].data.rd = commit_if[i].data.rd; + assign writeback_if[i].data.wis = wid_to_wis(commit_if[i].data.wid); + assign writeback_if[i].data.PC = commit_if[i].data.PC; + assign writeback_if[i].data.tmask= commit_if[i].data.tmask; + assign writeback_if[i].data.rd = commit_if[i].data.rd; assign writeback_if[i].data.data = commit_if[i].data.data; - assign writeback_if[i].data.sop = commit_if[i].data.sop; - assign writeback_if[i].data.eop = commit_if[i].data.eop; - assign commit_if[i].ready = 1'b1; + assign writeback_if[i].data.sop = commit_if[i].data.sop; + assign writeback_if[i].data.eop = commit_if[i].data.eop; + assign commit_if[i].ready = 1'b1; // writeback has no backpressure end // simulation helper signal to get RISC-V tests Pass/Fail status diff --git a/hw/rtl/core/VX_core.sv b/hw/rtl/core/VX_core.sv index 8aaea911..684a9b84 100644 --- a/hw/rtl/core/VX_core.sv +++ b/hw/rtl/core/VX_core.sv @@ -116,7 +116,11 @@ module VX_core import VX_gpu_pkg::*; #( .CORE_ID (CORE_ID) ) schedule ( .clk (clk), - .reset (schedule_reset), + .reset (schedule_reset), + + `ifdef PERF_ENABLE + .perf_schedule_if (pipeline_perf_if.schedule), + `endif .base_dcrs (base_dcrs), diff --git a/hw/rtl/core/VX_csr_data.sv b/hw/rtl/core/VX_csr_data.sv index 9ba0ffd0..44e997ff 100644 --- a/hw/rtl/core/VX_csr_data.sv +++ b/hw/rtl/core/VX_csr_data.sv @@ -179,14 +179,18 @@ import VX_fpu_pkg::*; default: begin read_addr_valid_r = 0; - if ((read_addr >= `VX_CSR_MPM_BASE && read_addr < (`VX_CSR_MPM_BASE + 32)) - || (read_addr >= `VX_CSR_MPM_BASE_H && read_addr < (`VX_CSR_MPM_BASE_H + 32))) begin + if ((read_addr >= `VX_CSR_MPM_USER && read_addr < (`VX_CSR_MPM_USER + 32)) + || (read_addr >= `VX_CSR_MPM_USER_H && read_addr < (`VX_CSR_MPM_USER_H + 32))) begin read_addr_valid_r = 1; `ifdef PERF_ENABLE case (base_dcrs.mpm_class) `VX_DCR_MPM_CLASS_CORE: begin case (read_addr) - // PERF: pipeline + // PERF: pipeline + `VX_CSR_MPM_SCHED_ST : read_data_ro_r = pipeline_perf_if.sched_stalls[31:0]; + `VX_CSR_MPM_SCHED_ST_H : read_data_ro_r = 32'(pipeline_perf_if.sched_stalls[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_FETCH_ST : read_data_ro_r = pipeline_perf_if.fetch_stalls[31:0]; + `VX_CSR_MPM_FETCH_ST_H : read_data_ro_r = 32'(pipeline_perf_if.fetch_stalls[`PERF_CTR_BITS-1:32]); `VX_CSR_MPM_IBUF_ST : read_data_ro_r = pipeline_perf_if.ibf_stalls[31:0]; `VX_CSR_MPM_IBUF_ST_H : read_data_ro_r = 32'(pipeline_perf_if.ibf_stalls[`PERF_CTR_BITS-1:32]); `VX_CSR_MPM_SCRB_ST : read_data_ro_r = pipeline_perf_if.scb_stalls[31:0]; @@ -204,6 +208,19 @@ import VX_fpu_pkg::*; `endif `VX_CSR_MPM_SFU_ST : read_data_ro_r = pipeline_perf_if.dsp_stalls[`EX_SFU][31:0]; `VX_CSR_MPM_SFU_ST_H : read_data_ro_r = 32'(pipeline_perf_if.dsp_stalls[`EX_SFU][`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SCRB_ALU : read_data_ro_r = 32'(pipeline_perf_if.scb_uses[`EX_ALU][`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SCRB_ALU_H : read_data_ro_r = pipeline_perf_if.scb_uses[`EX_ALU][31:0]; + `ifdef EXT_F_ENABLE + `VX_CSR_MPM_SCRB_FPU : read_data_ro_r = 32'(pipeline_perf_if.scb_uses[`EX_FPU][`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SCRB_FPU_H : read_data_ro_r = pipeline_perf_if.scb_uses[`EX_FPU][31:0]; + `else + `VX_CSR_MPM_SCRB_FPU : read_data_ro_r = '0; + `VX_CSR_MPM_SCRB_FPU_H : read_data_ro_r = '0; + `endif + `VX_CSR_MPM_SCRB_LSU : read_data_ro_r = 32'(pipeline_perf_if.scb_uses[`EX_LSU][`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SCRB_LSU_H : read_data_ro_r = pipeline_perf_if.scb_uses[`EX_LSU][31:0]; + `VX_CSR_MPM_SCRB_SFU : read_data_ro_r = 32'(pipeline_perf_if.scb_uses[`EX_SFU][`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SCRB_SFU_H : read_data_ro_r = pipeline_perf_if.scb_uses[`EX_SFU][31:0]; // PERF: memory `VX_CSR_MPM_IFETCHES : read_data_ro_r = pipeline_perf_if.ifetches[31:0]; `VX_CSR_MPM_IFETCHES_H : read_data_ro_r = 32'(pipeline_perf_if.ifetches[`PERF_CTR_BITS-1:32]); @@ -214,7 +231,7 @@ import VX_fpu_pkg::*; `VX_CSR_MPM_IFETCH_LAT : read_data_ro_r = pipeline_perf_if.ifetch_latency[31:0]; `VX_CSR_MPM_IFETCH_LAT_H : read_data_ro_r = 32'(pipeline_perf_if.ifetch_latency[`PERF_CTR_BITS-1:32]); `VX_CSR_MPM_LOAD_LAT : read_data_ro_r = pipeline_perf_if.load_latency[31:0]; - `VX_CSR_MPM_LOAD_LAT_H : read_data_ro_r = 32'(pipeline_perf_if.load_latency[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_LOAD_LAT_H : read_data_ro_r = 32'(pipeline_perf_if.load_latency[`PERF_CTR_BITS-1:32]); default:; endcase end @@ -225,6 +242,8 @@ import VX_fpu_pkg::*; `VX_CSR_MPM_ICACHE_READS_H : read_data_ro_r = 32'(mem_perf_if.icache.reads[`PERF_CTR_BITS-1:32]); `VX_CSR_MPM_ICACHE_MISS_R : read_data_ro_r = mem_perf_if.icache.read_misses[31:0]; `VX_CSR_MPM_ICACHE_MISS_R_H : read_data_ro_r = 32'(mem_perf_if.icache.read_misses[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_ICACHE_MSHR_ST : read_data_ro_r = mem_perf_if.icache.mshr_stalls[31:0]; + `VX_CSR_MPM_ICACHE_MSHR_ST_H : read_data_ro_r = 32'(mem_perf_if.icache.mshr_stalls[`PERF_CTR_BITS-1:32]); // PERF: dcache `VX_CSR_MPM_DCACHE_READS : read_data_ro_r = mem_perf_if.dcache.reads[31:0]; `VX_CSR_MPM_DCACHE_READS_H : read_data_ro_r = 32'(mem_perf_if.dcache.reads[`PERF_CTR_BITS-1:32]); diff --git a/hw/rtl/core/VX_issue.sv b/hw/rtl/core/VX_issue.sv index af00014e..53701cc8 100644 --- a/hw/rtl/core/VX_issue.sv +++ b/hw/rtl/core/VX_issue.sv @@ -59,6 +59,10 @@ module VX_issue #( ) scoreboard ( .clk (clk), .reset (scoreboard_reset), + `ifdef PERF_ENABLE + .perf_scb_stalls(perf_issue_if.scb_stalls), + .perf_scb_uses (perf_issue_if.scb_uses), + `endif .writeback_if (writeback_if), .ibuffer_if (ibuffer_if), .scoreboard_if (scoreboard_if) @@ -152,29 +156,17 @@ module VX_issue #( `ifdef PERF_ENABLE reg [`PERF_CTR_BITS-1:0] perf_ibf_stalls; - reg [`PERF_CTR_BITS-1:0] perf_scb_stalls; - - wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] scoreboard_stalls_per_cycle; - reg [`ISSUE_WIDTH-1:0] scoreboard_stalls; - for (genvar i=0; i < `ISSUE_WIDTH; ++i) begin - assign scoreboard_stalls[i] = ibuffer_if[i].valid && ~ibuffer_if[i].ready; - end - `POP_COUNT(scoreboard_stalls_per_cycle, scoreboard_stalls); - always @(posedge clk) begin if (reset) begin perf_ibf_stalls <= '0; - perf_scb_stalls <= '0; end else begin if (decode_if.valid && ~decode_if.ready) begin perf_ibf_stalls <= perf_ibf_stalls + `PERF_CTR_BITS'(1); end - perf_scb_stalls <= perf_scb_stalls + `PERF_CTR_BITS'(scoreboard_stalls_per_cycle); end end assign perf_issue_if.ibf_stalls = perf_ibf_stalls; - assign perf_issue_if.scb_stalls = perf_scb_stalls; `endif endmodule diff --git a/hw/rtl/core/VX_schedule.sv b/hw/rtl/core/VX_schedule.sv index ea96178e..0ffeafc2 100644 --- a/hw/rtl/core/VX_schedule.sv +++ b/hw/rtl/core/VX_schedule.sv @@ -19,6 +19,10 @@ module VX_schedule import VX_gpu_pkg::*; #( input wire clk, input wire reset, +`ifdef PERF_ENABLE + VX_pipeline_perf_if.schedule perf_schedule_if, +`endif + // configuration input base_dcrs_t base_dcrs, @@ -376,4 +380,21 @@ module VX_schedule import VX_gpu_pkg::*; #( end `RUNTIME_ASSERT(timeout_ctr < `STALL_TIMEOUT, ("%t: *** core%0d-scheduler-timeout: stalled_warps=%b", $time, CORE_ID, stalled_warps)); +`ifdef PERF_ENABLE + reg [`PERF_CTR_BITS-1:0] perf_sched_stalls; + reg [`PERF_CTR_BITS-1:0] perf_fetch_stalls; + always @(posedge clk) begin + if (reset) begin + perf_sched_stalls <= '0; + perf_fetch_stalls <= '0; + end else begin + perf_sched_stalls <= perf_sched_stalls + `PERF_CTR_BITS'(!schedule_valid); + perf_fetch_stalls <= perf_fetch_stalls + `PERF_CTR_BITS'(schedule_if.valid && !schedule_if.ready); + end + end + + assign perf_schedule_if.sched_stalls = perf_sched_stalls; + assign perf_schedule_if.fetch_stalls = perf_fetch_stalls; +`endif + endmodule diff --git a/hw/rtl/core/VX_scoreboard.sv b/hw/rtl/core/VX_scoreboard.sv index 90a58134..e3eaa44a 100644 --- a/hw/rtl/core/VX_scoreboard.sv +++ b/hw/rtl/core/VX_scoreboard.sv @@ -19,6 +19,11 @@ module VX_scoreboard import VX_gpu_pkg::*; #( input wire clk, input wire reset, +`ifdef PERF_ENABLE + output reg [`PERF_CTR_BITS-1:0] perf_scb_stalls, + output reg [`PERF_CTR_BITS-1:0] perf_scb_uses [`NUM_EX_UNITS], +`endif + VX_writeback_if.slave writeback_if [`ISSUE_WIDTH], VX_ibuffer_if.slave ibuffer_if [`ISSUE_WIDTH], VX_ibuffer_if.master scoreboard_if [`ISSUE_WIDTH] @@ -26,81 +31,102 @@ module VX_scoreboard import VX_gpu_pkg::*; #( `UNUSED_PARAM (CORE_ID) localparam DATAW = `UUID_WIDTH + ISSUE_WIS_W + `NUM_THREADS + `XLEN + `EX_BITS + `INST_OP_BITS + `INST_MOD_BITS + 1 + 1 + `XLEN + (`NR_BITS * 4) + 1; +`ifdef PERF_ENABLE + wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] scoreboard_alu_per_cycle; +`ifdef EXT_F_ENABLE + wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] scoreboard_fpu_per_cycle; +`endif + wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] scoreboard_lsu_per_cycle; + wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] scoreboard_sfu_per_cycle; + wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] scoreboard_stalls_per_cycle; + reg [`EX_BITS-1:0][`ISSUE_WIDTH-1:0] scoreboard_uses; + wire [`ISSUE_WIDTH-1:0] scoreboard_stalls; + `POP_COUNT(scoreboard_stalls_per_cycle, scoreboard_stalls); + `POP_COUNT(scoreboard_alu_per_cycle, scoreboard_uses[`EX_ALU]); +`ifdef EXT_F_ENABLE + `POP_COUNT(scoreboard_fpu_per_cycle, scoreboard_uses[`EX_FPU]); +`endif + `POP_COUNT(scoreboard_lsu_per_cycle, scoreboard_uses[`EX_LSU]); + `POP_COUNT(scoreboard_sfu_per_cycle, scoreboard_uses[`EX_SFU]); +`endif + for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin - reg [`UP(ISSUE_RATIO)-1:0][`NUM_REGS-1:0] inuse_regs, inuse_regs_n; - reg [3:0] ready_masks, ready_masks_n; + reg [`UP(ISSUE_RATIO)-1:0][`NUM_REGS-1:0] inuse_regs; VX_ibuffer_if staging_if(); - + wire writeback_fire = writeback_if[i].valid && writeback_if[i].data.eop; + wire inuse_rd = inuse_regs[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd]; + wire inuse_rs1 = inuse_regs[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs1]; + wire inuse_rs2 = inuse_regs[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs2]; + wire inuse_rs3 = inuse_regs[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs3]; + + `ifdef PERF_ENABLE + reg [`UP(ISSUE_RATIO)-1:0][`NUM_REGS-1:0][`EX_BITS-1:0] inuse_units; always @(*) begin - inuse_regs_n = inuse_regs; - ready_masks_n = ready_masks; - if (writeback_fire) begin - inuse_regs_n[writeback_if[i].data.wis][writeback_if[i].data.rd] = 0; - ready_masks_n |= {4{(ISSUE_RATIO == 0) || writeback_if[i].data.wis == staging_if.data.wis}} - & {(writeback_if[i].data.rd == staging_if.data.rd), - (writeback_if[i].data.rd == staging_if.data.rs1), - (writeback_if[i].data.rd == staging_if.data.rs2), - (writeback_if[i].data.rd == staging_if.data.rs3)}; - end - if (staging_if.valid && staging_if.ready && staging_if.data.wb) begin - inuse_regs_n[staging_if.data.wis][staging_if.data.rd] = 1; - ready_masks_n = '0; + scoreboard_uses = '0; + if (ibuffer_if[i].valid) begin + if (inuse_rd) begin + scoreboard_uses[inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd]][i] = 1; + end + if (inuse_rs1) begin + scoreboard_uses[inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs1]][i] = 1; + end + if (inuse_rs2) begin + scoreboard_uses[inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs2]][i] = 1; + end + if (inuse_rs3) begin + scoreboard_uses[inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs3]][i] = 1; + end end - if (ibuffer_if[i].valid && ibuffer_if[i].ready) begin - ready_masks_n = ~{inuse_regs_n[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd], - inuse_regs_n[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs1], - inuse_regs_n[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs2], - inuse_regs_n[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs3]}; - end - end + end + assign scoreboard_stalls[i] = ibuffer_if[i].valid && ~ibuffer_if[i].ready; + `endif + + reg [DATAW-1:0] data_out_r; + reg valid_out_r; + + wire [3:0] ready_masks = ~{inuse_rd, inuse_rs1, inuse_rs2, inuse_rs3}; + wire deps_ready = (& ready_masks); always @(posedge clk) begin if (reset) begin - inuse_regs <= '0; - ready_masks <= '0; - end else begin - inuse_regs <= inuse_regs_n; - ready_masks <= ready_masks_n; + valid_out_r <= 0; + inuse_regs <= '0; + end else begin + if (writeback_fire) begin + inuse_regs[writeback_if[i].data.wis][writeback_if[i].data.rd] <= 0; + end + if (~valid_out_r) begin + valid_out_r <= ibuffer_if[i].valid && deps_ready; + end else if (staging_if.ready) begin + if (staging_if.data.wb) begin + inuse_regs[staging_if.data.wis][staging_if.data.rd] <= 1; + `ifdef PERF_ENABLE + inuse_units[staging_if.data.wis][staging_if.data.rd] <= staging_if.data.ex_type; + `endif + end + valid_out_r <= 0; + end + end + if (~valid_out_r) begin + data_out_r <= ibuffer_if[i].data; end end - // staging buffer - - `RESET_RELAY (stg_buf_reset, reset); - - VX_elastic_buffer #( - .DATAW (DATAW) - ) stg_buf ( - .clk (clk), - .reset (stg_buf_reset), - .valid_in (ibuffer_if[i].valid), - .ready_in (ibuffer_if[i].ready), - .data_in (ibuffer_if[i].data), - .data_out (staging_if.data), - .valid_out (staging_if.valid), - .ready_out (staging_if.ready) - ); - - // output buffer - - wire valid_stg, ready_stg; - wire regs_ready = (& ready_masks); - assign valid_stg = staging_if.valid && regs_ready; - assign staging_if.ready = ready_stg && regs_ready; - - `RESET_RELAY (out_buf_reset, reset); + assign ibuffer_if[i].ready = ~valid_out_r && deps_ready; + assign staging_if.valid = valid_out_r; + assign staging_if.data = data_out_r; VX_elastic_buffer #( .DATAW (DATAW), - .SIZE (2), + .SIZE (0), .OUT_REG (2) ) out_buf ( .clk (clk), - .reset (out_buf_reset), - .valid_in (valid_stg), - .ready_in (ready_stg), + .reset (reset), + .valid_in (staging_if.valid), + .ready_in (staging_if.ready), .data_in (staging_if.data), .data_out (scoreboard_if[i].data), .valid_out (scoreboard_if[i].valid), @@ -108,29 +134,29 @@ module VX_scoreboard import VX_gpu_pkg::*; #( ); `ifdef SIMULATION - reg [31:0] timeout_ctr; - + reg [31:0] timeout_ctr; + always @(posedge clk) begin if (reset) begin timeout_ctr <= '0; end else begin - if (staging_if.valid && ~regs_ready) begin + if (ibuffer_if[i].valid && ~ibuffer_if[i].ready) begin `ifdef DBG_TRACE_CORE_PIPELINE `TRACE(3, ("%d: *** core%0d-scoreboard-stall: wid=%0d, PC=0x%0h, tmask=%b, cycles=%0d, inuse=%b (#%0d)\n", - $time, CORE_ID, wis_to_wid(staging_if.data.wis, i), staging_if.data.PC, staging_if.data.tmask, timeout_ctr, - ~ready_masks, staging_if.data.uuid)); + $time, CORE_ID, wis_to_wid(ibuffer_if[i].data.wis, i), ibuffer_if[i].data.PC, ibuffer_if[i].data.tmask, timeout_ctr, + ~ready_masks, ibuffer_if[i].data.uuid)); `endif timeout_ctr <= timeout_ctr + 1; - end else if (staging_if.valid && staging_if.ready) begin + end else if (ibuffer_if[i].valid && ibuffer_if[i].ready) begin timeout_ctr <= '0; end end - end - + end + `RUNTIME_ASSERT((timeout_ctr < `STALL_TIMEOUT), ("%t: *** core%0d-scoreboard-timeout: wid=%0d, PC=0x%0h, tmask=%b, cycles=%0d, inuse=%b (#%0d)", - $time, CORE_ID, wis_to_wid(staging_if.data.wis, i), staging_if.data.PC, staging_if.data.tmask, timeout_ctr, - ~ready_masks, staging_if.data.uuid)); + $time, CORE_ID, wis_to_wid(ibuffer_if[i].data.wis, i), ibuffer_if[i].data.PC, ibuffer_if[i].data.tmask, timeout_ctr, + ~ready_masks, ibuffer_if[i].data.uuid)); `RUNTIME_ASSERT(~writeback_fire || inuse_regs[writeback_if[i].data.wis][writeback_if[i].data.rd] != 0, ("%t: *** core%0d: invalid writeback register: wid=%0d, PC=0x%0h, tmask=%b, rd=%0d (#%0d)", @@ -139,4 +165,26 @@ module VX_scoreboard import VX_gpu_pkg::*; #( end +`ifdef PERF_ENABLE + always @(posedge clk) begin + if (reset) begin + perf_scb_stalls <= '0; + perf_scb_uses[`EX_ALU] <= '0; + `ifdef EXT_F_ENABLE + perf_scb_uses[`EX_FPU] <= '0; + `endif + perf_scb_uses[`EX_LSU] <= '0; + perf_scb_uses[`EX_SFU] <= '0; + end else begin + perf_scb_stalls <= perf_scb_stalls + `PERF_CTR_BITS'(scoreboard_stalls_per_cycle); + perf_scb_uses[`EX_ALU] <= perf_scb_uses[`EX_ALU] + `PERF_CTR_BITS'(scoreboard_alu_per_cycle); + `ifdef EXT_F_ENABLE + perf_scb_uses[`EX_FPU] <= perf_scb_uses[`EX_FPU] + `PERF_CTR_BITS'(scoreboard_fpu_per_cycle); + `endif + perf_scb_uses[`EX_LSU] <= perf_scb_uses[`EX_LSU] + `PERF_CTR_BITS'(scoreboard_lsu_per_cycle); + perf_scb_uses[`EX_SFU] <= perf_scb_uses[`EX_SFU] + `PERF_CTR_BITS'(scoreboard_sfu_per_cycle); + end + end +`endif + endmodule diff --git a/hw/rtl/interfaces/VX_pipeline_perf_if.sv b/hw/rtl/interfaces/VX_pipeline_perf_if.sv index b6123b7f..4f6ffb5d 100644 --- a/hw/rtl/interfaces/VX_pipeline_perf_if.sv +++ b/hw/rtl/interfaces/VX_pipeline_perf_if.sv @@ -14,8 +14,11 @@ `include "VX_define.vh" interface VX_pipeline_perf_if (); + wire [`PERF_CTR_BITS-1:0] sched_stalls; + wire [`PERF_CTR_BITS-1:0] fetch_stalls; wire [`PERF_CTR_BITS-1:0] ibf_stalls; wire [`PERF_CTR_BITS-1:0] scb_stalls; + wire [`PERF_CTR_BITS-1:0] scb_uses [`NUM_EX_UNITS]; wire [`PERF_CTR_BITS-1:0] dsp_stalls [`NUM_EX_UNITS]; wire [`PERF_CTR_BITS-1:0] ifetches; @@ -24,15 +27,24 @@ interface VX_pipeline_perf_if (); wire [`PERF_CTR_BITS-1:0] ifetch_latency; wire [`PERF_CTR_BITS-1:0] load_latency; + modport schedule ( + output sched_stalls, + output fetch_stalls + ); + modport issue ( output ibf_stalls, output scb_stalls, + output scb_uses, output dsp_stalls - ); + ); modport slave ( + input sched_stalls, + input fetch_stalls, input ibf_stalls, input scb_stalls, + input scb_uses, input dsp_stalls, input ifetches, input loads, diff --git a/hw/rtl/libs/VX_stream_xbar.sv b/hw/rtl/libs/VX_stream_xbar.sv index a7de9341..7c1f0f7a 100644 --- a/hw/rtl/libs/VX_stream_xbar.sv +++ b/hw/rtl/libs/VX_stream_xbar.sv @@ -22,7 +22,7 @@ module VX_stream_xbar #( parameter OUT_WIDTH = `LOG2UP(NUM_OUTPUTS), parameter ARBITER = "P", parameter LOCK_ENABLE = 0, - parameter OUT_REG = 0, + parameter OUT_REG = 0, parameter MAX_FANOUT = `MAX_FANOUT, parameter PERF_CTR_BITS = `CLOG2(NUM_INPUTS+1) ) ( @@ -173,8 +173,8 @@ module VX_stream_xbar #( end // compute inputs collision - // we have a collision when there exists a valid transfer with mutiple input candicates - // we caount the unique duplicates each cycle. + // we have a collision when there exists a valid transfer with multiple input candicates + // we count the unique duplicates each cycle. reg [PERF_CTR_BITS-1:0] collisions_r; reg [NUM_INPUTS-1:0] per_cycle_collision; From e8d56dc013f2b1fa0981e112f522b086915f4da1 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Mon, 27 Nov 2023 22:16:36 -0800 Subject: [PATCH 18/57] minor update --- hw/rtl/core/VX_commit.sv | 4 ++- hw/rtl/core/VX_scoreboard.sv | 57 ++++++++++++++++-------------------- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/hw/rtl/core/VX_commit.sv b/hw/rtl/core/VX_commit.sv index a76f395b..09667d11 100644 --- a/hw/rtl/core/VX_commit.sv +++ b/hw/rtl/core/VX_commit.sv @@ -106,7 +106,9 @@ module VX_commit import VX_gpu_pkg::*; #( assign commit_fire_any = (| commit_fire); for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin - `POP_COUNT(commit_size[i], commit_tmask[i]); + wire [COMMIT_SIZEW-1:0] count; + `POP_COUNT(count, commit_tmask[i]); + assign commit_size[i] = count; end VX_pipe_register #( diff --git a/hw/rtl/core/VX_scoreboard.sv b/hw/rtl/core/VX_scoreboard.sv index e3eaa44a..c1d09c07 100644 --- a/hw/rtl/core/VX_scoreboard.sv +++ b/hw/rtl/core/VX_scoreboard.sv @@ -32,22 +32,20 @@ module VX_scoreboard import VX_gpu_pkg::*; #( localparam DATAW = `UUID_WIDTH + ISSUE_WIS_W + `NUM_THREADS + `XLEN + `EX_BITS + `INST_OP_BITS + `INST_MOD_BITS + 1 + 1 + `XLEN + (`NR_BITS * 4) + 1; `ifdef PERF_ENABLE - wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] scoreboard_alu_per_cycle; -`ifdef EXT_F_ENABLE - wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] scoreboard_fpu_per_cycle; -`endif - wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] scoreboard_lsu_per_cycle; - wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] scoreboard_sfu_per_cycle; - wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] scoreboard_stalls_per_cycle; - reg [`EX_BITS-1:0][`ISSUE_WIDTH-1:0] scoreboard_uses; + wire [`NUM_EX_UNITS-1:0] scoreboard_uses_per_cycle; + wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] scoreboard_stalls_per_cycle; + reg [`ISSUE_WIDTH-1:0][`NUM_EX_UNITS-1:0] scoreboard_uses; wire [`ISSUE_WIDTH-1:0] scoreboard_stalls; + `POP_COUNT(scoreboard_stalls_per_cycle, scoreboard_stalls); - `POP_COUNT(scoreboard_alu_per_cycle, scoreboard_uses[`EX_ALU]); -`ifdef EXT_F_ENABLE - `POP_COUNT(scoreboard_fpu_per_cycle, scoreboard_uses[`EX_FPU]); -`endif - `POP_COUNT(scoreboard_lsu_per_cycle, scoreboard_uses[`EX_LSU]); - `POP_COUNT(scoreboard_sfu_per_cycle, scoreboard_uses[`EX_SFU]); + VX_reduce #( + .DATAW_IN (`NUM_EX_UNITS), + .N (`ISSUE_WIDTH), + .OP ("|") + ) reduce ( + .data_in (scoreboard_uses), + .data_out (scoreboard_uses_per_cycle) + ); `endif for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin @@ -64,19 +62,19 @@ module VX_scoreboard import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE reg [`UP(ISSUE_RATIO)-1:0][`NUM_REGS-1:0][`EX_BITS-1:0] inuse_units; always @(*) begin - scoreboard_uses = '0; + scoreboard_uses[i] = '0; if (ibuffer_if[i].valid) begin if (inuse_rd) begin - scoreboard_uses[inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd]][i] = 1; + scoreboard_uses[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd]] = 1; end if (inuse_rs1) begin - scoreboard_uses[inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs1]][i] = 1; + scoreboard_uses[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs1]] = 1; end if (inuse_rs2) begin - scoreboard_uses[inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs2]][i] = 1; + scoreboard_uses[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs2]] = 1; end if (inuse_rs3) begin - scoreboard_uses[inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs3]][i] = 1; + scoreboard_uses[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs3]] = 1; end end end @@ -169,20 +167,17 @@ module VX_scoreboard import VX_gpu_pkg::*; #( always @(posedge clk) begin if (reset) begin perf_scb_stalls <= '0; - perf_scb_uses[`EX_ALU] <= '0; - `ifdef EXT_F_ENABLE - perf_scb_uses[`EX_FPU] <= '0; - `endif - perf_scb_uses[`EX_LSU] <= '0; - perf_scb_uses[`EX_SFU] <= '0; end else begin perf_scb_stalls <= perf_scb_stalls + `PERF_CTR_BITS'(scoreboard_stalls_per_cycle); - perf_scb_uses[`EX_ALU] <= perf_scb_uses[`EX_ALU] + `PERF_CTR_BITS'(scoreboard_alu_per_cycle); - `ifdef EXT_F_ENABLE - perf_scb_uses[`EX_FPU] <= perf_scb_uses[`EX_FPU] + `PERF_CTR_BITS'(scoreboard_fpu_per_cycle); - `endif - perf_scb_uses[`EX_LSU] <= perf_scb_uses[`EX_LSU] + `PERF_CTR_BITS'(scoreboard_lsu_per_cycle); - perf_scb_uses[`EX_SFU] <= perf_scb_uses[`EX_SFU] + `PERF_CTR_BITS'(scoreboard_sfu_per_cycle); + end + end + for (genvar i = 0; i < `NUM_EX_UNITS; ++i) begin + always @(posedge clk) begin + if (reset) begin + perf_scb_uses[i] <= '0; + end else begin + perf_scb_uses[i] <= perf_scb_uses[i] + `PERF_CTR_BITS'(scoreboard_uses_per_cycle[i]); + end end end `endif From 9c2916f3fc9136d611e43d8d3ea96f219fc76092 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 28 Nov 2023 12:03:48 -0800 Subject: [PATCH 19/57] minor update --- hw/rtl/cache/VX_cache_top.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/rtl/cache/VX_cache_top.sv b/hw/rtl/cache/VX_cache_top.sv index 9be08dde..00b2f048 100644 --- a/hw/rtl/cache/VX_cache_top.sv +++ b/hw/rtl/cache/VX_cache_top.sv @@ -13,7 +13,7 @@ `include "VX_cache_define.vh" -module VX_cache_top #( +module VX_cache_top import VX_gpu_pkg::*; #( parameter `STRING INSTANCE_ID = "", // Number of Word requests per cycle From b20320236dd151f5eb1b1097b31f1eccdb6eb237 Mon Sep 17 00:00:00 2001 From: Udit Subramanya Date: Fri, 1 Dec 2023 08:22:44 -0500 Subject: [PATCH 20/57] adding documemtation for contributing and documentation --- docs/continuous_integration.md | 36 ++++++++++++++++++++++++++++++++++ docs/contributing.md | 18 +++++++++++++++++ docs/testing.md | 24 ++++++++++++++++++----- 3 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 docs/continuous_integration.md create mode 100644 docs/contributing.md diff --git a/docs/continuous_integration.md b/docs/continuous_integration.md new file mode 100644 index 00000000..abb90580 --- /dev/null +++ b/docs/continuous_integration.md @@ -0,0 +1,36 @@ +# Continuous Integration +- Each time you push to the repo, the Continuous Integration pipeline will run +- This pipeline consists of creating the correct development environment, building your code, and running all tests +- This is an extensive pipeline so it might take some time to complete + + +## Protecting Master Branch +Navigate to your Repository: +Open your repository on GitHub. + +Click on "Settings": +In the upper-right corner of your repository page, click on the "Settings" tab. + +Select "Branches" in the left sidebar: +On the left sidebar, look for the "Branches" option and click on it. + +Choose the Branch: +Under "Branch protection rules," select the branch you want to protect. In this case, choose the main branch. + +Enable Branch Protection:`` +Check the box that says "Protect this branch." + +Configure Protection Settings: +You can configure various protection settings. Some common settings include: + +Require pull request reviews before merging: This ensures that changes are reviewed before being merged. +Require status checks to pass before merging: This ensures that automated tests and checks are passing. +Require signed commits: This enforces that commits are signed with a verified signature. +Restrict Who Can Push: +You can further restrict who can push directly to the branch. You might want to limit this privilege to specific people or teams. + +Save Changes: +Once you've configured the protection settings, scroll down and click on the "Save changes" button. + +Now, your main branch is protected, and certain criteria must be met before changes can be pushed directly to it. Contributors will need to create pull requests, have their changes reviewed, and meet other specified criteria before the changes can be merged into the main branch. + diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 00000000..14e0ccd0 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,18 @@ +# Contributing to Vortex on Github + +## Github Details +- There are two main repos, `vortex` (public, this one) and `vortex-dev` (private) +- todo: Most current development is on `vortex` +- If you have a legacy version of `vortex`, you can use the releases branch or tags to access the repo at that point in time + +## Contribution Process +- You should create a new branch from develop that is clearly named with the feature that you want to add +- Avoid pushing directly to the `master` branch instead you will need to make a Pull Request (PR) +- There should be protections in place that prevent pushing directly to the main branch, but don't rely on it +- When you make a PR it will be tested against the continuous integration (ci) pipeline (see `continuous_integration.md`) +- It is not sufficient to just write some tests, they need to be incorporated into the ci pipeline to make sure they are run +- During a PR, you might receive feedback regarding your changes and you might need to make further commits to your branch + + +## Creating and Adding Tests +see `testing.md` \ No newline at end of file diff --git a/docs/testing.md b/docs/testing.md index 552008f3..0103e7bc 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -2,18 +2,18 @@ ## Running a Vortex application -The framework provides a utility script: blakcbox.sh under the /ci/ folder for executing applications in the tests tree. +The framework provides a utility script: blackbox.sh under the /ci/ folder for executing applications in the tests tree. You can query the commandline options of the tool using: - $ ./ci/blakcbox.sh --help + $ ./ci/blackbox.sh --help To execute sgemm test program on the simx driver and passing "-n10" as argument to sgemm: - $ ./ci/blakcbox.sh --driver=simx --app=sgemm --args="-n10" + $ ./ci/blackbox.sh --driver=simx --app=sgemm --args="-n10" You can execute the same application of a GPU architecture with 2 cores: - $ ./ci/blakcbox.sh --core=2 --driver=simx --app=sgemm --args="-n10" + $ ./ci/blackbox.sh --core=2 --driver=simx --app=sgemm --args="-n10" When excuting, Blackbox needs to recompile the driver if the desired architecture changes. It tracks the latest configuration in a file under the current directory blackbox..cache. @@ -30,4 +30,18 @@ You can execute the default regression suite by running the following commands a You can execute the default opncl suite by running the following commands at the root folder. $ make -C tests/opencl run-simx - $ make -C tests/opencl run-rtlsim \ No newline at end of file + $ make -C tests/opencl run-rtlsim + +## Creating Your Own Regression Tests +- Inside `test/` you will find a series of folders which are named based on what they test +- You can view the tests to see which ones have tests similar to what you are trying to create new tests for +- once you have found a similar baseline, you can copy the folder and rename it to what you are planning to test +- `testcases.h` contains each of the test case templates +- `main.cpp` contains the implementation of each of the test cases and builds a test suite of all the tests cases you want + +Compile the test case: `make -C tests/regression// clean-all && make -C tests/regression//` + +Run the test case: `./ci/blackbox.sh --driver=simx --cores=4 --app= --debug` + +## Adding Your Tests to the CI Pipeline +see `continuous_integration.md` \ No newline at end of file From a43b7432a0dd573eb54c152e0f06d95288c44b58 Mon Sep 17 00:00:00 2001 From: Udit Subramanya Date: Fri, 1 Dec 2023 08:55:01 -0500 Subject: [PATCH 21/57] add environment setup readme --- docs/environment_setup.md | 71 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 docs/environment_setup.md diff --git a/docs/environment_setup.md b/docs/environment_setup.md new file mode 100644 index 00000000..1c15495f --- /dev/null +++ b/docs/environment_setup.md @@ -0,0 +1,71 @@ +# Environment Setup# Vortex Dev Environment Setup +These instructions apply to the development vortex repo using the *updated toolchain*. The updated toolchain is considered to be any commit of `master` pulled from *July 2, 2023* onwards. The toolchain update in question can be viewed in this [commit](https://github.com/vortexgpgpu/vortex-dev/commit/0048496ba28d7b9a209a0e569d52d60f2b68fc04). Therefore, if you are unsure whether you are using the new toolchain or not, then you should check the `ci` folder for the existence of the `toolchain_prebuilt.sh` script. Furthermore, you should notice that the `toolchain_install.sh` script has the legacy `llvm()` split into `llvm-vortex()` and `llvm-pocl()`. + +> Note: As it stands right now, there a few test suites which are not working due to this toolchain migration. We are working to determine an exact list of which ones are working and which ones are not. For now, if the repo builds at a minimum, then you can consider all these steps to have worked successfully. + +## Choosing an Development Environment +There are three primary environments you can use. Each has its own pros and cons. Refer to this section to help you determine which environment best suits your needs. +1. Volvo +2. Docker +3. Local + +### Volvo +Volvo is a server provided by Georgia Tech. As such, it provides high performance compute, but you need valid credentials to access it. If you don't already have credentials, you can get in contact with your mentor to ask about setting your account up. + +Pros: + +1. Native x86_64 architecture, AMD EPYC 7702P 64-Core Processor (*fast*) +2. Packages and difficult configurations are already done for you +3. Consistent environment as others, allowing for easier troubleshooting +4. Just need to SSH into Volvo, minimal impact on local computer resources +5. VScode remote development tools are phenomenal over SSH + +Cons: +1. Volvo is accessed via gatech vpn, external contributors might encounter issues with it -- especially from other university networks +2. Account creation is not immediate and is subject to processing time +3. Volvo might have outtages (*pretty uncommon*) +5. SSH development requires internet and other remote development tools (*vscode works!*) + +### Docker + +Docker allows for isolated pre-built environments to be created, shared and used. They are much more resource efficient than a Virtual Machine, and have great tooling and support available. The main motivation for Docker is bringing a consistent development environment to your local computer, across all platforms. + +Pros: + +1. If you are native to x86_64, the container will also run natively, yielding better performance. However, if you have aarch64 (arm) processor, you can still run the Docker container without configuration changes. +2. Consistent environment as others, allowing for easier troubleshooting +3. Works out of the box, just have a working installation of Docker +4. Vortex uses a build system, so once you build the repo once, only new code changes need to be recompiled +5. Docker offers helpful tools and extensions to monitor the performance of your container + +Cons: + +1. If you are using an arm processor, the container will be run in emulation mode, so it will inherently run slower, as it needs to translate all the x86_64 instructions. It's still usable on Apple Silicon, however. +2. Limited to your computer's performance, and Vortex is a large repo to build +3. Will utilize a few gigabytes of storage on your computer for saving binaries to run the container + + +### Local +You can reverse engineer the Dockerfile and scripts above to get a working environment setup locally. This option is for experienced users, who have already considered the pros and cons of Volvo and Docker. + +## Setup on Volvo +1. Clone Repo Recursively: `git clone --recursive https://github.com/vortexgpgpu/vortex-dev.git` +2. Source `/opt/set_vortex_env_dev.sh` to initialize pre-installed toolchain +3. `make -s` in `vortex-dev` root directory +4. Run a test program: `./ci/blackbox.sh --cores=2 --app=dogfood` + +## Setup with Docker +Currently the Dockerfile is not included with the official vortex-dev repository, however you can quickly add it to repo and get started. +1. Clone repo recursively onto your local machine: `git clone --recursive https://github.com/vortexgpgpu/vortex-dev.git` +2. Download a copy of `Dockerfile.dev` and place it in the root of the repo. +3. Build the Dockerfile into an image: `docker build --platform=linux/amd64 -t vortex-dev -f Dockerfile.dev .` +4. Run a container based on the image: `docker run --rm -v ./:/root/vortex-dev/ -it --name vtx-dev --privileged=true --platform=linux/amd64 vortex-dev` +5. Install the toolchain `./ci/toolchain_install.sh --all` (once per container) +6. `make -s` in `vortex-dev` root directory +7. Run a test program: `./ci/blackbox.sh --cores=2 --app=dogfood` + + +### Additional Docker Commands +- Exit from a container (does not stop or remove it) +- Resume a container you have exited or start a second terminal session `docker exec -it bash` + From 900a1efaca7ea62ad3185f17555b503acbcba018 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 5 Dec 2023 04:55:50 -0800 Subject: [PATCH 22/57] BUFFER_EX refactoring --- hw/rtl/VX_cluster.sv | 2 +- hw/rtl/VX_define.vh | 28 ++++++++++++++-------------- hw/rtl/VX_socket.sv | 2 +- hw/rtl/Vortex.sv | 2 +- hw/rtl/core/VX_schedule.sv | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/hw/rtl/VX_cluster.sv b/hw/rtl/VX_cluster.sv index d537249d..90076673 100644 --- a/hw/rtl/VX_cluster.sv +++ b/hw/rtl/VX_cluster.sv @@ -167,6 +167,6 @@ module VX_cluster import VX_gpu_pkg::*; #( ); end - `BUFFER_BUSY (busy, (| per_socket_busy), (`NUM_SOCKETS > 1)); + `BUFFER_EX(busy, (| per_socket_busy), 1'b1, (`NUM_SOCKETS > 1)); endmodule diff --git a/hw/rtl/VX_define.vh b/hw/rtl/VX_define.vh index 5dcf1f2f..95d206ce 100644 --- a/hw/rtl/VX_define.vh +++ b/hw/rtl/VX_define.vh @@ -307,20 +307,20 @@ /////////////////////////////////////////////////////////////////////////////// -`define BUFFER_BUSY(dst, src, enable) \ - logic __busy; \ - if (enable) begin \ - always @(posedge clk) begin \ - if (reset) begin \ - __busy <= 1'b0; \ - end else begin \ - __busy <= src; \ - end \ - end \ - end else begin \ - assign __busy = src; \ - end \ - assign dst = __busy +`define BUFFER_EX(dst, src, ena, latency) \ + VX_pipe_register #( \ + .DATAW ($bits(dst)), \ + .RESETW ($bits(dst)), \ + .DEPTH (latency) \ + ) __``dst ( \ + .clk (clk), \ + .reset (reset), \ + .enable (ena), \ + .data_in (src), \ + .data_out (dst) \ + ) + +`define BUFFER(dst, src) `BUFFER_EX(dst, src, 1'b1, 1) `define POP_COUNT_EX(out, in, model) \ VX_popcount #( \ diff --git a/hw/rtl/VX_socket.sv b/hw/rtl/VX_socket.sv index 1e61fdff..139598d9 100644 --- a/hw/rtl/VX_socket.sv +++ b/hw/rtl/VX_socket.sv @@ -245,6 +245,6 @@ module VX_socket import VX_gpu_pkg::*; #( ); end - `BUFFER_BUSY (busy, (| per_core_busy), (`SOCKET_SIZE > 1)); + `BUFFER_EX(busy, (| per_core_busy), 1'b1, (`SOCKET_SIZE > 1)); endmodule diff --git a/hw/rtl/Vortex.sv b/hw/rtl/Vortex.sv index 5bd628d5..594204e4 100644 --- a/hw/rtl/Vortex.sv +++ b/hw/rtl/Vortex.sv @@ -166,7 +166,7 @@ module Vortex import VX_gpu_pkg::*; ( ); end - `BUFFER_BUSY (busy, (| per_cluster_busy), (`NUM_CLUSTERS > 1)); + `BUFFER_EX(busy, (| per_cluster_busy), 1'b1, (`NUM_CLUSTERS > 1)); `ifdef PERF_ENABLE diff --git a/hw/rtl/core/VX_schedule.sv b/hw/rtl/core/VX_schedule.sv index 0ffeafc2..9008f605 100644 --- a/hw/rtl/core/VX_schedule.sv +++ b/hw/rtl/core/VX_schedule.sv @@ -353,7 +353,7 @@ module VX_schedule import VX_gpu_pkg::*; #( .empty (no_pending_instr) ); - `BUFFER_BUSY (busy, (active_warps != 0 || ~no_pending_instr), 1); + `BUFFER_EX(busy, (active_warps != 0 || ~no_pending_instr), 1'b1, 1); // export CSRs assign sched_csr_if.cycles = cycles; From 1912f52bee48e8e058d531568e979b84733b8d30 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 5 Dec 2023 04:56:46 -0800 Subject: [PATCH 23/57] profiling bug fix --- hw/rtl/cache/VX_cache.sv | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/rtl/cache/VX_cache.sv b/hw/rtl/cache/VX_cache.sv index 30594f1a..65efc607 100644 --- a/hw/rtl/cache/VX_cache.sv +++ b/hw/rtl/cache/VX_cache.sv @@ -537,7 +537,7 @@ module VX_cache import VX_gpu_pkg::*; #( wire [`CLOG2(NUM_BANKS+1)-1:0] perf_read_miss_per_cycle; wire [`CLOG2(NUM_BANKS+1)-1:0] perf_write_miss_per_cycle; wire [`CLOG2(NUM_BANKS+1)-1:0] perf_mshr_stall_per_cycle; - wire [`CLOG2(NUM_BANKS+1)-1:0] perf_crsp_stall_per_cycle; + wire [`CLOG2(NUM_REQS+1)-1:0] perf_crsp_stall_per_cycle; `POP_COUNT(perf_core_reads_per_cycle, perf_core_reads_per_req); `POP_COUNT(perf_core_writes_per_cycle, perf_core_writes_per_req); @@ -562,6 +562,12 @@ module VX_cache import VX_gpu_pkg::*; #( reg [`PERF_CTR_BITS-1:0] perf_mem_stalls; reg [`PERF_CTR_BITS-1:0] perf_crsp_stalls; + wire [`CLOG2(NUM_REQS+1)-1:0] perf_core_reads_per_cycle_r; + wire [`CLOG2(NUM_REQS+1)-1:0] perf_core_writes_per_cycle_r; + + `BUFFER(perf_core_reads_per_cycle_r, perf_core_reads_per_cycle); + `BUFFER(perf_core_writes_per_cycle_r, perf_core_writes_per_cycle); + always @(posedge clk) begin if (reset) begin perf_core_reads <= '0; @@ -572,8 +578,8 @@ module VX_cache import VX_gpu_pkg::*; #( perf_mem_stalls <= '0; perf_crsp_stalls <= '0; end else begin - perf_core_reads <= perf_core_reads + `PERF_CTR_BITS'(perf_core_reads_per_cycle); - perf_core_writes <= perf_core_writes + `PERF_CTR_BITS'(perf_core_writes_per_cycle); + perf_core_reads <= perf_core_reads + `PERF_CTR_BITS'(perf_core_reads_per_cycle_r); + perf_core_writes <= perf_core_writes + `PERF_CTR_BITS'(perf_core_writes_per_cycle_r); perf_read_misses <= perf_read_misses + `PERF_CTR_BITS'(perf_read_miss_per_cycle); perf_write_misses <= perf_write_misses + `PERF_CTR_BITS'(perf_write_miss_per_cycle); perf_mshr_stalls <= perf_mshr_stalls + `PERF_CTR_BITS'(perf_mshr_stall_per_cycle); From e5b41bcd6648919570d245bd7edd0747189460a7 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 5 Dec 2023 04:57:52 -0800 Subject: [PATCH 24/57] wctl unit bug fix --- hw/rtl/core/VX_wctl_unit.sv | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/rtl/core/VX_wctl_unit.sv b/hw/rtl/core/VX_wctl_unit.sv index d628e16c..35503add 100644 --- a/hw/rtl/core/VX_wctl_unit.sv +++ b/hw/rtl/core/VX_wctl_unit.sv @@ -29,7 +29,6 @@ module VX_wctl_unit import VX_gpu_pkg::*; #( ); `UNUSED_PARAM (CORE_ID) localparam LANE_BITS = `CLOG2(NUM_LANES); - localparam LANE_WIDTH = `UP(LANE_BITS); localparam PID_BITS = `CLOG2(`NUM_THREADS / NUM_LANES); localparam PID_WIDTH = `UP(PID_BITS); localparam WCTL_WIDTH = $bits(tmc_t) + $bits(wspawn_t) + $bits(split_t) + $bits(join_t) + $bits(barrier_t); @@ -50,7 +49,7 @@ module VX_wctl_unit import VX_gpu_pkg::*; #( wire is_join = (execute_if.data.op_type == `INST_SFU_JOIN); wire is_bar = (execute_if.data.op_type == `INST_SFU_BAR); - wire [LANE_WIDTH-1:0] tid; + wire [LANE_BITS-1:0] tid; if (LANE_BITS != 0) begin assign tid = execute_if.data.tid[0 +: LANE_BITS]; end else begin From 6c7ac3505414630f611a809749243fb7174071b3 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 5 Dec 2023 05:12:13 -0800 Subject: [PATCH 25/57] profiling optimizations minor updates --- hw/rtl/VX_config.vh | 2 +- hw/rtl/core/VX_dispatch.sv | 44 +++++++++++++++++++++-------------- hw/rtl/core/VX_scoreboard.sv | 40 ++++++++++++++++++------------- hw/rtl/libs/VX_stream_xbar.sv | 12 ++++++---- hw/rtl/mem/VX_shared_mem.sv | 9 +++++-- 5 files changed, 65 insertions(+), 42 deletions(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index c7b2a2c3..d57de0c3 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -436,7 +436,7 @@ // Number of Banks `ifndef DCACHE_NUM_BANKS -`define DCACHE_NUM_BANKS (`NUM_LSU_LANES) +`define DCACHE_NUM_BANKS `MIN(`NUM_LSU_LANES, 4) `endif // Core Response Queue Size diff --git a/hw/rtl/core/VX_dispatch.sv b/hw/rtl/core/VX_dispatch.sv index efd719be..087c4080 100644 --- a/hw/rtl/core/VX_dispatch.sv +++ b/hw/rtl/core/VX_dispatch.sv @@ -174,30 +174,38 @@ module VX_dispatch import VX_gpu_pkg::*; #( || (sfu_operands_if[i].ready && (operands_if[i].data.ex_type == `EX_SFU)); end -`ifdef PERF_ENABLE - reg [`NUM_EX_UNITS-1:0][`PERF_CTR_BITS-1:0] perf_stalls_n, perf_stalls_r; - wire [`ISSUE_WIDTH-1:0] operands_stall; - wire [`ISSUE_WIDTH-1:0][`EX_BITS-1:0] operands_ex_type; +`ifdef PERF_ENABLE + wire [`NUM_EX_UNITS-1:0] perf_unit_stalls_per_cycle, perf_unit_stalls_per_cycle_r; + reg [`ISSUE_WIDTH-1:0][`NUM_EX_UNITS-1:0] perf_issue_unit_stalls_per_cycle; + reg [`NUM_EX_UNITS-1:0][`PERF_CTR_BITS-1:0] perf_stalls_r; for (genvar i=0; i < `ISSUE_WIDTH; ++i) begin - assign operands_stall[i] = operands_if[i].valid && ~operands_if[i].ready; - assign operands_ex_type[i] = operands_if[i].data.ex_type; - end - - always @(*) begin - perf_stalls_n = perf_stalls_r; - for (integer i=0; i < `ISSUE_WIDTH; ++i) begin - if (operands_stall[i]) begin - perf_stalls_n[operands_ex_type[i]] += `PERF_CTR_BITS'(1); + always @(*) begin + perf_issue_unit_stalls_per_cycle[i] = '0; + if (operands_if[i].valid && ~operands_if[i].ready) begin + perf_issue_unit_stalls_per_cycle[i][operands_if[i].data.ex_type] = 1; end end end - always @(posedge clk) begin - if (reset) begin - perf_stalls_r <= '0; - end else begin - perf_stalls_r <= perf_stalls_n; + VX_reduce #( + .DATAW_IN (`NUM_EX_UNITS), + .N (`ISSUE_WIDTH), + .OP ("|") + ) reduce ( + .data_in (perf_issue_unit_stalls_per_cycle), + .data_out (perf_unit_stalls_per_cycle) + ); + + `BUFFER(perf_unit_stalls_per_cycle_r, perf_unit_stalls_per_cycle); + + for (genvar i = 0; i < `NUM_EX_UNITS; ++i) begin + always @(posedge clk) begin + if (reset) begin + perf_stalls_r[i] <= '0; + end else begin + perf_stalls_r[i] <= perf_stalls_r[i] + `PERF_CTR_BITS'(perf_unit_stalls_per_cycle_r[i]); + end end end diff --git a/hw/rtl/core/VX_scoreboard.sv b/hw/rtl/core/VX_scoreboard.sv index c1d09c07..2206df25 100644 --- a/hw/rtl/core/VX_scoreboard.sv +++ b/hw/rtl/core/VX_scoreboard.sv @@ -32,19 +32,20 @@ module VX_scoreboard import VX_gpu_pkg::*; #( localparam DATAW = `UUID_WIDTH + ISSUE_WIS_W + `NUM_THREADS + `XLEN + `EX_BITS + `INST_OP_BITS + `INST_MOD_BITS + 1 + 1 + `XLEN + (`NR_BITS * 4) + 1; `ifdef PERF_ENABLE - wire [`NUM_EX_UNITS-1:0] scoreboard_uses_per_cycle; - wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] scoreboard_stalls_per_cycle; - reg [`ISSUE_WIDTH-1:0][`NUM_EX_UNITS-1:0] scoreboard_uses; - wire [`ISSUE_WIDTH-1:0] scoreboard_stalls; + wire [`NUM_EX_UNITS-1:0] perf_uses_per_cycle; + wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] perf_stalls_per_cycle; + reg [`ISSUE_WIDTH-1:0][`NUM_EX_UNITS-1:0] perf_issue_uses_per_cycle; + wire [`ISSUE_WIDTH-1:0] perf_issue_stalls_per_cycle; + + `POP_COUNT(perf_stalls_per_cycle, perf_issue_stalls_per_cycle); - `POP_COUNT(scoreboard_stalls_per_cycle, scoreboard_stalls); VX_reduce #( .DATAW_IN (`NUM_EX_UNITS), .N (`ISSUE_WIDTH), .OP ("|") ) reduce ( - .data_in (scoreboard_uses), - .data_out (scoreboard_uses_per_cycle) + .data_in (perf_issue_uses_per_cycle), + .data_out (perf_uses_per_cycle) ); `endif @@ -62,23 +63,23 @@ module VX_scoreboard import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE reg [`UP(ISSUE_RATIO)-1:0][`NUM_REGS-1:0][`EX_BITS-1:0] inuse_units; always @(*) begin - scoreboard_uses[i] = '0; + perf_issue_uses_per_cycle[i] = '0; if (ibuffer_if[i].valid) begin if (inuse_rd) begin - scoreboard_uses[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd]] = 1; + perf_issue_uses_per_cycle[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd]] = 1; end if (inuse_rs1) begin - scoreboard_uses[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs1]] = 1; + perf_issue_uses_per_cycle[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs1]] = 1; end if (inuse_rs2) begin - scoreboard_uses[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs2]] = 1; + perf_issue_uses_per_cycle[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs2]] = 1; end if (inuse_rs3) begin - scoreboard_uses[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs3]] = 1; + perf_issue_uses_per_cycle[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs3]] = 1; end end end - assign scoreboard_stalls[i] = ibuffer_if[i].valid && ~ibuffer_if[i].ready; + assign perf_issue_stalls_per_cycle[i] = ibuffer_if[i].valid && ~ibuffer_if[i].ready; `endif reg [DATAW-1:0] data_out_r; @@ -164,19 +165,26 @@ module VX_scoreboard import VX_gpu_pkg::*; #( end `ifdef PERF_ENABLE + wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] perf_stalls_per_cycle_r; + wire [`NUM_EX_UNITS-1:0] perf_uses_per_cycle_r; + + `BUFFER(perf_stalls_per_cycle_r, perf_stalls_per_cycle); + `BUFFER(perf_uses_per_cycle_r, perf_uses_per_cycle); + always @(posedge clk) begin if (reset) begin - perf_scb_stalls <= '0; + perf_scb_stalls <= '0; end else begin - perf_scb_stalls <= perf_scb_stalls + `PERF_CTR_BITS'(scoreboard_stalls_per_cycle); + perf_scb_stalls <= perf_scb_stalls + `PERF_CTR_BITS'(perf_stalls_per_cycle_r); end end + for (genvar i = 0; i < `NUM_EX_UNITS; ++i) begin always @(posedge clk) begin if (reset) begin perf_scb_uses[i] <= '0; end else begin - perf_scb_uses[i] <= perf_scb_uses[i] + `PERF_CTR_BITS'(scoreboard_uses_per_cycle[i]); + perf_scb_uses[i] <= perf_scb_uses[i] + `PERF_CTR_BITS'(perf_uses_per_cycle_r[i]); end end end diff --git a/hw/rtl/libs/VX_stream_xbar.sv b/hw/rtl/libs/VX_stream_xbar.sv index 7c1f0f7a..fbae5c7a 100644 --- a/hw/rtl/libs/VX_stream_xbar.sv +++ b/hw/rtl/libs/VX_stream_xbar.sv @@ -183,21 +183,23 @@ module VX_stream_xbar #( per_cycle_collision = 0; for (integer i = 0; i < NUM_INPUTS; ++i) begin for (integer j = 1; j < (NUM_INPUTS-i); ++j) begin - if (valid_in[i] && valid_in[j+i] && sel_in[i] == sel_in[j+i]) begin - per_cycle_collision[i] |= ready_in[i] | ready_in[j+i]; - end + per_cycle_collision[i] |= valid_in[i] + && valid_in[j+i] + && (sel_in[i] == sel_in[j+i]) + && (ready_in[i] | ready_in[j+i]); end end end - wire [`CLOG2(NUM_INPUTS+1)-1:0] collision_count; + wire [`CLOG2(NUM_INPUTS+1)-1:0] collision_count, collision_count_r; `POP_COUNT(collision_count, per_cycle_collision); + `BUFFER(collision_count_r, collision_count); always @(posedge clk) begin if (reset) begin collisions_r <= '0; end else begin - collisions_r <= collisions_r + PERF_CTR_BITS'(collision_count); + collisions_r <= collisions_r + PERF_CTR_BITS'(collision_count_r); end end diff --git a/hw/rtl/mem/VX_shared_mem.sv b/hw/rtl/mem/VX_shared_mem.sv index a44c68a8..1c25c7cf 100644 --- a/hw/rtl/mem/VX_shared_mem.sv +++ b/hw/rtl/mem/VX_shared_mem.sv @@ -245,14 +245,19 @@ module VX_shared_mem import VX_gpu_pkg::*; #( reg [`PERF_CTR_BITS-1:0] perf_writes; reg [`PERF_CTR_BITS-1:0] perf_crsp_stalls; + wire [`CLOG2(NUM_REQS+1)-1:0] perf_reads_per_cycle_r; + wire [`CLOG2(NUM_REQS+1)-1:0] perf_writes_per_cycle_r; + `BUFFER(perf_reads_per_cycle_r, perf_reads_per_cycle); + `BUFFER(perf_writes_per_cycle_r, perf_writes_per_cycle); + always @(posedge clk) begin if (reset) begin perf_reads <= '0; perf_writes <= '0; perf_crsp_stalls <= '0; end else begin - perf_reads <= perf_reads + `PERF_CTR_BITS'(perf_reads_per_cycle); - perf_writes <= perf_writes + `PERF_CTR_BITS'(perf_writes_per_cycle); + perf_reads <= perf_reads + `PERF_CTR_BITS'(perf_reads_per_cycle_r); + perf_writes <= perf_writes + `PERF_CTR_BITS'(perf_writes_per_cycle_r); perf_crsp_stalls <= perf_crsp_stalls + `PERF_CTR_BITS'(perf_crsp_stall_per_cycle); end end From f5f9e3dfdba742acb35aebbeb29c37d380821e52 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Tue, 5 Dec 2023 17:10:30 -0800 Subject: [PATCH 26/57] profiling timing optimization --- hw/rtl/core/VX_core.sv | 14 ++++++++------ hw/rtl/mem/VX_shared_mem.sv | 6 ++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/rtl/core/VX_core.sv b/hw/rtl/core/VX_core.sv index 684a9b84..1776024f 100644 --- a/hw/rtl/core/VX_core.sv +++ b/hw/rtl/core/VX_core.sv @@ -266,9 +266,8 @@ module VX_core import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE - wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_rd_req_per_cycle; - wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_wr_req_per_cycle; - + wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_rd_req_per_cycle, perf_dcache_rd_req_per_cycle_r; + wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_wr_req_per_cycle, perf_dcache_wr_req_per_cycle_r; wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_rsp_per_cycle; wire [1:0] perf_icache_pending_read_cycle; @@ -295,9 +294,12 @@ module VX_core import VX_gpu_pkg::*; #( `POP_COUNT(perf_dcache_rd_req_per_cycle, perf_dcache_rd_req_fire); `POP_COUNT(perf_dcache_wr_req_per_cycle, perf_dcache_wr_req_fire); `POP_COUNT(perf_dcache_rsp_per_cycle, perf_dcache_rsp_fire); + + `BUFFER(perf_dcache_rd_req_per_cycle_r, perf_dcache_rd_req_per_cycle); + `BUFFER(perf_dcache_wr_req_per_cycle_r, perf_dcache_wr_req_per_cycle); assign perf_icache_pending_read_cycle = perf_icache_req_fire - perf_icache_rsp_fire; - assign perf_dcache_pending_read_cycle = perf_dcache_rd_req_per_cycle - perf_dcache_rsp_per_cycle; + assign perf_dcache_pending_read_cycle = perf_dcache_rd_req_per_cycle_r - perf_dcache_rsp_per_cycle; always @(posedge clk) begin if (reset) begin @@ -321,8 +323,8 @@ module VX_core import VX_gpu_pkg::*; #( perf_dcache_lat <= '0; end else begin perf_ifetches <= perf_ifetches + `PERF_CTR_BITS'(perf_icache_req_fire); - perf_loads <= perf_loads + `PERF_CTR_BITS'(perf_dcache_rd_req_per_cycle); - perf_stores <= perf_stores + `PERF_CTR_BITS'(perf_dcache_wr_req_per_cycle); + perf_loads <= perf_loads + `PERF_CTR_BITS'(perf_dcache_rd_req_per_cycle_r); + perf_stores <= perf_stores + `PERF_CTR_BITS'(perf_dcache_wr_req_per_cycle_r); perf_icache_lat <= perf_icache_lat + perf_icache_pending_reads; perf_dcache_lat <= perf_dcache_lat + perf_dcache_pending_reads; end diff --git a/hw/rtl/mem/VX_shared_mem.sv b/hw/rtl/mem/VX_shared_mem.sv index 1c25c7cf..0f1f4171 100644 --- a/hw/rtl/mem/VX_shared_mem.sv +++ b/hw/rtl/mem/VX_shared_mem.sv @@ -229,8 +229,8 @@ module VX_shared_mem import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE // per cycle: reads, writes - wire [`CLOG2(NUM_REQS+1)-1:0] perf_reads_per_cycle; - wire [`CLOG2(NUM_REQS+1)-1:0] perf_writes_per_cycle; + wire [`CLOG2(NUM_REQS+1)-1:0] perf_reads_per_cycle, perf_reads_per_cycle_r; + wire [`CLOG2(NUM_REQS+1)-1:0] perf_writes_per_cycle, perf_writes_per_cycle_r; wire [`CLOG2(NUM_REQS+1)-1:0] perf_crsp_stall_per_cycle; wire [NUM_REQS-1:0] perf_reads_per_req = req_valid & req_ready & ~req_rw; @@ -245,8 +245,6 @@ module VX_shared_mem import VX_gpu_pkg::*; #( reg [`PERF_CTR_BITS-1:0] perf_writes; reg [`PERF_CTR_BITS-1:0] perf_crsp_stalls; - wire [`CLOG2(NUM_REQS+1)-1:0] perf_reads_per_cycle_r; - wire [`CLOG2(NUM_REQS+1)-1:0] perf_writes_per_cycle_r; `BUFFER(perf_reads_per_cycle_r, perf_reads_per_cycle); `BUFFER(perf_writes_per_cycle_r, perf_writes_per_cycle); From c6845a4c8d634510154686ea2af3c64e68fc9a84 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 13 Dec 2023 18:04:12 -0800 Subject: [PATCH 27/57] profiling timing optimization minor update minor update minor update --- hw/rtl/VX_config.vh | 10 +++++++--- hw/rtl/Vortex.sv | 13 ++++++------- hw/rtl/cache/VX_cache.sv | 19 ++++++++----------- hw/rtl/core/VX_core.sv | 24 +++++++++++++----------- hw/rtl/core/VX_issue.sv | 7 ++++--- hw/rtl/core/VX_schedule.sv | 7 +++++-- hw/rtl/core/VX_sfu_unit.sv | 5 ++++- hw/rtl/core/VX_wctl_unit.sv | 2 +- hw/rtl/libs/VX_stream_xbar.sv | 12 ++++++------ hw/rtl/mem/VX_shared_mem.sv | 17 ++++++++--------- tests/opencl/Makefile | 4 ++-- 11 files changed, 64 insertions(+), 56 deletions(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index d57de0c3..3af544c6 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -194,10 +194,14 @@ `ifndef FPU_FPNEW `ifndef FPU_DSP `ifndef FPU_DPI -`ifdef SYNTHESIS -`define FPU_DSP -`else +`ifndef SYNTHESIS +`ifndef DPI_DISABLE `define FPU_DPI +`else +`define FPU_DSP +`endif +`else +`define FPU_DSP `endif `endif `endif diff --git a/hw/rtl/Vortex.sv b/hw/rtl/Vortex.sv index 594204e4..b29f0802 100644 --- a/hw/rtl/Vortex.sv +++ b/hw/rtl/Vortex.sv @@ -181,16 +181,15 @@ module Vortex import VX_gpu_pkg::*; ( end end + wire mem_rd_req_fire = mem_req_fire && ~mem_bus_if.req_data.rw; + wire mem_wr_req_fire = mem_req_fire && mem_bus_if.req_data.rw; + always @(posedge clk) begin if (reset) begin mem_perf <= '0; - end else begin - if (mem_req_fire && ~mem_bus_if.req_data.rw) begin - mem_perf.reads <= mem_perf.reads + `PERF_CTR_BITS'(1); - end - if (mem_req_fire && mem_bus_if.req_data.rw) begin - mem_perf.writes <= mem_perf.writes + `PERF_CTR_BITS'(1); - end + end else begin + mem_perf.reads <= mem_perf.reads + `PERF_CTR_BITS'(mem_rd_req_fire); + mem_perf.writes <= mem_perf.writes + `PERF_CTR_BITS'(mem_wr_req_fire); mem_perf.latency <= mem_perf.latency + perf_mem_pending_reads; end end diff --git a/hw/rtl/cache/VX_cache.sv b/hw/rtl/cache/VX_cache.sv index 65efc607..891512da 100644 --- a/hw/rtl/cache/VX_cache.sv +++ b/hw/rtl/cache/VX_cache.sv @@ -530,14 +530,17 @@ module VX_cache import VX_gpu_pkg::*; #( wire [`CLOG2(NUM_REQS+1)-1:0] perf_core_reads_per_cycle; wire [`CLOG2(NUM_REQS+1)-1:0] perf_core_writes_per_cycle; - wire [NUM_REQS-1:0] perf_core_reads_per_req = core_req_valid & core_req_ready & ~core_req_rw; - wire [NUM_REQS-1:0] perf_core_writes_per_req = core_req_valid & core_req_ready & core_req_rw; + wire [NUM_REQS-1:0] perf_core_reads_per_req; + wire [NUM_REQS-1:0] perf_core_writes_per_req; // per cycle: read misses, write misses, msrq stalls, pipeline stalls wire [`CLOG2(NUM_BANKS+1)-1:0] perf_read_miss_per_cycle; wire [`CLOG2(NUM_BANKS+1)-1:0] perf_write_miss_per_cycle; wire [`CLOG2(NUM_BANKS+1)-1:0] perf_mshr_stall_per_cycle; wire [`CLOG2(NUM_REQS+1)-1:0] perf_crsp_stall_per_cycle; + + `BUFFER(perf_core_reads_per_req, core_req_valid & core_req_ready & ~core_req_rw); + `BUFFER(perf_core_writes_per_req, core_req_valid & core_req_ready & core_req_rw); `POP_COUNT(perf_core_reads_per_cycle, perf_core_reads_per_req); `POP_COUNT(perf_core_writes_per_cycle, perf_core_writes_per_req); @@ -560,13 +563,7 @@ module VX_cache import VX_gpu_pkg::*; #( reg [`PERF_CTR_BITS-1:0] perf_write_misses; reg [`PERF_CTR_BITS-1:0] perf_mshr_stalls; reg [`PERF_CTR_BITS-1:0] perf_mem_stalls; - reg [`PERF_CTR_BITS-1:0] perf_crsp_stalls; - - wire [`CLOG2(NUM_REQS+1)-1:0] perf_core_reads_per_cycle_r; - wire [`CLOG2(NUM_REQS+1)-1:0] perf_core_writes_per_cycle_r; - - `BUFFER(perf_core_reads_per_cycle_r, perf_core_reads_per_cycle); - `BUFFER(perf_core_writes_per_cycle_r, perf_core_writes_per_cycle); + reg [`PERF_CTR_BITS-1:0] perf_crsp_stalls; always @(posedge clk) begin if (reset) begin @@ -578,8 +575,8 @@ module VX_cache import VX_gpu_pkg::*; #( perf_mem_stalls <= '0; perf_crsp_stalls <= '0; end else begin - perf_core_reads <= perf_core_reads + `PERF_CTR_BITS'(perf_core_reads_per_cycle_r); - perf_core_writes <= perf_core_writes + `PERF_CTR_BITS'(perf_core_writes_per_cycle_r); + perf_core_reads <= perf_core_reads + `PERF_CTR_BITS'(perf_core_reads_per_cycle); + perf_core_writes <= perf_core_writes + `PERF_CTR_BITS'(perf_core_writes_per_cycle); perf_read_misses <= perf_read_misses + `PERF_CTR_BITS'(perf_read_miss_per_cycle); perf_write_misses <= perf_write_misses + `PERF_CTR_BITS'(perf_write_miss_per_cycle); perf_mshr_stalls <= perf_mshr_stalls + `PERF_CTR_BITS'(perf_mshr_stall_per_cycle); diff --git a/hw/rtl/core/VX_core.sv b/hw/rtl/core/VX_core.sv index 1776024f..5aba3075 100644 --- a/hw/rtl/core/VX_core.sv +++ b/hw/rtl/core/VX_core.sv @@ -266,8 +266,8 @@ module VX_core import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE - wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_rd_req_per_cycle, perf_dcache_rd_req_per_cycle_r; - wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_wr_req_per_cycle, perf_dcache_wr_req_per_cycle_r; + wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_rd_req_per_cycle; + wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_wr_req_per_cycle; wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_rsp_per_cycle; wire [1:0] perf_icache_pending_read_cycle; @@ -283,7 +283,9 @@ module VX_core import VX_gpu_pkg::*; #( wire perf_icache_req_fire = icache_bus_if.req_valid & icache_bus_if.req_ready; wire perf_icache_rsp_fire = icache_bus_if.rsp_valid & icache_bus_if.rsp_ready; - wire [DCACHE_NUM_REQS-1:0] perf_dcache_rd_req_fire, perf_dcache_wr_req_fire, perf_dcache_rsp_fire; + wire [DCACHE_NUM_REQS-1:0] perf_dcache_rd_req_fire, perf_dcache_rd_req_fire_r; + wire [DCACHE_NUM_REQS-1:0] perf_dcache_wr_req_fire, perf_dcache_wr_req_fire_r; + wire [DCACHE_NUM_REQS-1:0] perf_dcache_rsp_fire; for (genvar i = 0; i < DCACHE_NUM_REQS; ++i) begin assign perf_dcache_rd_req_fire[i] = dcache_bus_if[i].req_valid && ~dcache_bus_if[i].req_data.rw && dcache_bus_if[i].req_ready; @@ -291,15 +293,15 @@ module VX_core import VX_gpu_pkg::*; #( assign perf_dcache_rsp_fire[i] = dcache_bus_if[i].rsp_valid && dcache_bus_if[i].rsp_ready; end - `POP_COUNT(perf_dcache_rd_req_per_cycle, perf_dcache_rd_req_fire); - `POP_COUNT(perf_dcache_wr_req_per_cycle, perf_dcache_wr_req_fire); - `POP_COUNT(perf_dcache_rsp_per_cycle, perf_dcache_rsp_fire); + `BUFFER(perf_dcache_rd_req_fire_r, perf_dcache_rd_req_fire); + `BUFFER(perf_dcache_wr_req_fire_r, perf_dcache_wr_req_fire); - `BUFFER(perf_dcache_rd_req_per_cycle_r, perf_dcache_rd_req_per_cycle); - `BUFFER(perf_dcache_wr_req_per_cycle_r, perf_dcache_wr_req_per_cycle); + `POP_COUNT(perf_dcache_rd_req_per_cycle, perf_dcache_rd_req_fire_r); + `POP_COUNT(perf_dcache_wr_req_per_cycle, perf_dcache_wr_req_fire_r); + `POP_COUNT(perf_dcache_rsp_per_cycle, perf_dcache_rsp_fire); assign perf_icache_pending_read_cycle = perf_icache_req_fire - perf_icache_rsp_fire; - assign perf_dcache_pending_read_cycle = perf_dcache_rd_req_per_cycle_r - perf_dcache_rsp_per_cycle; + assign perf_dcache_pending_read_cycle = perf_dcache_rd_req_per_cycle - perf_dcache_rsp_per_cycle; always @(posedge clk) begin if (reset) begin @@ -323,8 +325,8 @@ module VX_core import VX_gpu_pkg::*; #( perf_dcache_lat <= '0; end else begin perf_ifetches <= perf_ifetches + `PERF_CTR_BITS'(perf_icache_req_fire); - perf_loads <= perf_loads + `PERF_CTR_BITS'(perf_dcache_rd_req_per_cycle_r); - perf_stores <= perf_stores + `PERF_CTR_BITS'(perf_dcache_wr_req_per_cycle_r); + perf_loads <= perf_loads + `PERF_CTR_BITS'(perf_dcache_rd_req_per_cycle); + perf_stores <= perf_stores + `PERF_CTR_BITS'(perf_dcache_wr_req_per_cycle); perf_icache_lat <= perf_icache_lat + perf_icache_pending_reads; perf_dcache_lat <= perf_dcache_lat + perf_dcache_pending_reads; end diff --git a/hw/rtl/core/VX_issue.sv b/hw/rtl/core/VX_issue.sv index 53701cc8..8d0eaff6 100644 --- a/hw/rtl/core/VX_issue.sv +++ b/hw/rtl/core/VX_issue.sv @@ -156,13 +156,14 @@ module VX_issue #( `ifdef PERF_ENABLE reg [`PERF_CTR_BITS-1:0] perf_ibf_stalls; + + wire decode_stall = decode_if.valid && ~decode_if.ready; + always @(posedge clk) begin if (reset) begin perf_ibf_stalls <= '0; end else begin - if (decode_if.valid && ~decode_if.ready) begin - perf_ibf_stalls <= perf_ibf_stalls + `PERF_CTR_BITS'(1); - end + perf_ibf_stalls <= perf_ibf_stalls + `PERF_CTR_BITS'(decode_stall); end end diff --git a/hw/rtl/core/VX_schedule.sv b/hw/rtl/core/VX_schedule.sv index 9008f605..f11e4324 100644 --- a/hw/rtl/core/VX_schedule.sv +++ b/hw/rtl/core/VX_schedule.sv @@ -383,13 +383,16 @@ module VX_schedule import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE reg [`PERF_CTR_BITS-1:0] perf_sched_stalls; reg [`PERF_CTR_BITS-1:0] perf_fetch_stalls; + + wire schedule_stall = schedule_if.valid && ~schedule_if.ready; + always @(posedge clk) begin if (reset) begin perf_sched_stalls <= '0; perf_fetch_stalls <= '0; end else begin - perf_sched_stalls <= perf_sched_stalls + `PERF_CTR_BITS'(!schedule_valid); - perf_fetch_stalls <= perf_fetch_stalls + `PERF_CTR_BITS'(schedule_if.valid && !schedule_if.ready); + perf_sched_stalls <= perf_sched_stalls + `PERF_CTR_BITS'(~schedule_valid); + perf_fetch_stalls <= perf_fetch_stalls + `PERF_CTR_BITS'(schedule_stall); end end diff --git a/hw/rtl/core/VX_sfu_unit.sv b/hw/rtl/core/VX_sfu_unit.sv index fd5dd59f..b531e75b 100644 --- a/hw/rtl/core/VX_sfu_unit.sv +++ b/hw/rtl/core/VX_sfu_unit.sv @@ -196,11 +196,14 @@ module VX_sfu_unit import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE reg [`PERF_CTR_BITS-1:0] perf_wctl_stalls; + + wire wctl_execute_stall = wctl_execute_if.valid && ~wctl_execute_if.ready; + always @(posedge clk) begin if (reset) begin perf_wctl_stalls <= '0; end else begin - perf_wctl_stalls <= perf_wctl_stalls + `PERF_CTR_BITS'(wctl_execute_if.valid && ~wctl_execute_if.ready); + perf_wctl_stalls <= perf_wctl_stalls + `PERF_CTR_BITS'(wctl_execute_stall); end end assign sfu_perf_if.wctl_stalls = perf_wctl_stalls; diff --git a/hw/rtl/core/VX_wctl_unit.sv b/hw/rtl/core/VX_wctl_unit.sv index 35503add..88b2f71e 100644 --- a/hw/rtl/core/VX_wctl_unit.sv +++ b/hw/rtl/core/VX_wctl_unit.sv @@ -49,7 +49,7 @@ module VX_wctl_unit import VX_gpu_pkg::*; #( wire is_join = (execute_if.data.op_type == `INST_SFU_JOIN); wire is_bar = (execute_if.data.op_type == `INST_SFU_BAR); - wire [LANE_BITS-1:0] tid; + wire [`UP(LANE_BITS)-1:0] tid; if (LANE_BITS != 0) begin assign tid = execute_if.data.tid[0 +: LANE_BITS]; end else begin diff --git a/hw/rtl/libs/VX_stream_xbar.sv b/hw/rtl/libs/VX_stream_xbar.sv index fbae5c7a..2a8e4bb4 100644 --- a/hw/rtl/libs/VX_stream_xbar.sv +++ b/hw/rtl/libs/VX_stream_xbar.sv @@ -176,8 +176,9 @@ module VX_stream_xbar #( // we have a collision when there exists a valid transfer with multiple input candicates // we count the unique duplicates each cycle. + reg [NUM_INPUTS-1:0] per_cycle_collision, per_cycle_collision_r; + wire [`CLOG2(NUM_INPUTS+1)-1:0] collision_count; reg [PERF_CTR_BITS-1:0] collisions_r; - reg [NUM_INPUTS-1:0] per_cycle_collision; always @(*) begin per_cycle_collision = 0; @@ -190,16 +191,15 @@ module VX_stream_xbar #( end end end - - wire [`CLOG2(NUM_INPUTS+1)-1:0] collision_count, collision_count_r; - `POP_COUNT(collision_count, per_cycle_collision); - `BUFFER(collision_count_r, collision_count); + + `BUFFER(per_cycle_collision_r, per_cycle_collision); + `POP_COUNT(collision_count, per_cycle_collision_r); always @(posedge clk) begin if (reset) begin collisions_r <= '0; end else begin - collisions_r <= collisions_r + PERF_CTR_BITS'(collision_count_r); + collisions_r <= collisions_r + PERF_CTR_BITS'(collision_count); end end diff --git a/hw/rtl/mem/VX_shared_mem.sv b/hw/rtl/mem/VX_shared_mem.sv index 0f1f4171..97082468 100644 --- a/hw/rtl/mem/VX_shared_mem.sv +++ b/hw/rtl/mem/VX_shared_mem.sv @@ -229,14 +229,16 @@ module VX_shared_mem import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE // per cycle: reads, writes - wire [`CLOG2(NUM_REQS+1)-1:0] perf_reads_per_cycle, perf_reads_per_cycle_r; - wire [`CLOG2(NUM_REQS+1)-1:0] perf_writes_per_cycle, perf_writes_per_cycle_r; + wire [`CLOG2(NUM_REQS+1)-1:0] perf_reads_per_cycle; + wire [`CLOG2(NUM_REQS+1)-1:0] perf_writes_per_cycle; wire [`CLOG2(NUM_REQS+1)-1:0] perf_crsp_stall_per_cycle; - wire [NUM_REQS-1:0] perf_reads_per_req = req_valid & req_ready & ~req_rw; - wire [NUM_REQS-1:0] perf_writes_per_req = req_valid & req_ready & req_rw; + wire [NUM_REQS-1:0] perf_reads_per_req, perf_writes_per_req; wire [NUM_REQS-1:0] perf_crsp_stall_per_req = rsp_valid & ~rsp_ready; + `BUFFER(perf_reads_per_req, req_valid & req_ready & ~req_rw); + `BUFFER(perf_writes_per_req, req_valid & req_ready & req_rw); + `POP_COUNT(perf_reads_per_cycle, perf_reads_per_req); `POP_COUNT(perf_writes_per_cycle, perf_writes_per_req); `POP_COUNT(perf_crsp_stall_per_cycle, perf_crsp_stall_per_req); @@ -245,17 +247,14 @@ module VX_shared_mem import VX_gpu_pkg::*; #( reg [`PERF_CTR_BITS-1:0] perf_writes; reg [`PERF_CTR_BITS-1:0] perf_crsp_stalls; - `BUFFER(perf_reads_per_cycle_r, perf_reads_per_cycle); - `BUFFER(perf_writes_per_cycle_r, perf_writes_per_cycle); - always @(posedge clk) begin if (reset) begin perf_reads <= '0; perf_writes <= '0; perf_crsp_stalls <= '0; end else begin - perf_reads <= perf_reads + `PERF_CTR_BITS'(perf_reads_per_cycle_r); - perf_writes <= perf_writes + `PERF_CTR_BITS'(perf_writes_per_cycle_r); + perf_reads <= perf_reads + `PERF_CTR_BITS'(perf_reads_per_cycle); + perf_writes <= perf_writes + `PERF_CTR_BITS'(perf_writes_per_cycle); perf_crsp_stalls <= perf_crsp_stalls + `PERF_CTR_BITS'(perf_crsp_stall_per_cycle); end end diff --git a/tests/opencl/Makefile b/tests/opencl/Makefile index 27ef6f38..c7ba1ed7 100644 --- a/tests/opencl/Makefile +++ b/tests/opencl/Makefile @@ -37,10 +37,10 @@ run-simx: $(MAKE) -C blackscholes run-simx $(MAKE) -C transpose run-simx $(MAKE) -C convolution run-simx - $(MAKE) -C cutcp run-simx - $(MAKE) -C sgemm2 run-simx + $(MAKE) -C cutcp run-simx $(MAKE) -C vectorhypot run-simx $(MAKE) -C mri-q run-simx +# $(MAKE) -C sgemm2 run-simx run-rtlsim: $(MAKE) -C vecadd run-rtlsim From e04e026a1466ca9186458db374f06e11897fcde5 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Fri, 15 Dec 2023 01:01:39 -0800 Subject: [PATCH 28/57] profiling update minor updates --- hw/rtl/VX_gpu_pkg.sv | 2 +- hw/rtl/VX_types.vh | 20 ++++----- hw/rtl/Vortex.sv | 8 ++-- hw/rtl/core/VX_core_top.sv | 6 +++ hw/rtl/core/VX_csr_data.sv | 20 ++++----- hw/rtl/core/VX_dispatch_unit.sv | 4 +- hw/rtl/core/VX_lsu_unit.sv | 2 +- hw/rtl/core/VX_schedule.sv | 15 ++++--- hw/rtl/fpu/VX_fpu_cvt.sv | 11 +++-- hw/rtl/interfaces/VX_pipeline_perf_if.sv | 8 ++-- hw/rtl/libs/VX_fifo_queue.sv | 4 +- runtime/common/utils.cpp | 54 ++++++++++++------------ sim/simx/core.cpp | 18 ++++---- sim/simx/core.h | 4 +- tests/opencl/Makefile | 33 +++++++-------- 15 files changed, 109 insertions(+), 100 deletions(-) diff --git a/hw/rtl/VX_gpu_pkg.sv b/hw/rtl/VX_gpu_pkg.sv index cdb48db4..4ece6c9c 100644 --- a/hw/rtl/VX_gpu_pkg.sv +++ b/hw/rtl/VX_gpu_pkg.sv @@ -217,7 +217,7 @@ package VX_gpu_pkg; function logic [ISSUE_WIS_W-1:0] wid_to_wis( input logic [`NW_WIDTH-1:0] wid ); - wid_to_wis = ISSUE_WIS_W'(wid >> `CLOG2(`ISSUE_WIDTH)); + wid_to_wis = ISSUE_WIS_W'({1'b0, wid} >> `CLOG2(`ISSUE_WIDTH)); endfunction function logic [ISSUE_ADDRW-1:0] wis_to_addr( diff --git a/hw/rtl/VX_types.vh b/hw/rtl/VX_types.vh index 80a4a7d7..4fb03783 100644 --- a/hw/rtl/VX_types.vh +++ b/hw/rtl/VX_types.vh @@ -70,10 +70,10 @@ `define VX_CSR_MINSTRET 12'hB02 `define VX_CSR_MINSTRET_H 12'hB82 // PERF: pipeline -`define VX_CSR_MPM_SCHED_ST 12'hB03 -`define VX_CSR_MPM_SCHED_ST_H 12'hB83 -`define VX_CSR_MPM_FETCH_ST 12'hB04 -`define VX_CSR_MPM_FETCH_ST_H 12'hB84 +`define VX_CSR_MPM_SCHED_ID 12'hB03 +`define VX_CSR_MPM_SCHED_ID_H 12'hB83 +`define VX_CSR_MPM_SCHED_ST 12'hB04 +`define VX_CSR_MPM_SCHED_ST_H 12'hB84 `define VX_CSR_MPM_IBUF_ST 12'hB05 `define VX_CSR_MPM_IBUF_ST_H 12'hB85 `define VX_CSR_MPM_SCRB_ST 12'hB06 @@ -101,10 +101,10 @@ `define VX_CSR_MPM_LOADS_H 12'hB90 `define VX_CSR_MPM_STORES 12'hB11 `define VX_CSR_MPM_STORES_H 12'hB91 -`define VX_CSR_MPM_IFETCH_LAT 12'hB12 -`define VX_CSR_MPM_IFETCH_LAT_H 12'hB92 -`define VX_CSR_MPM_LOAD_LAT 12'hB13 -`define VX_CSR_MPM_LOAD_LAT_H 12'hB93 +`define VX_CSR_MPM_IFETCH_LT 12'hB12 +`define VX_CSR_MPM_IFETCH_LT_H 12'hB92 +`define VX_CSR_MPM_LOAD_LT 12'hB13 +`define VX_CSR_MPM_LOAD_LT_H 12'hB93 // Machine Performance-monitoring memory counters // PERF: icache @@ -158,8 +158,8 @@ `define VX_CSR_MPM_MEM_READS_H 12'hB98 `define VX_CSR_MPM_MEM_WRITES 12'hB19 // total writes `define VX_CSR_MPM_MEM_WRITES_H 12'hB99 -`define VX_CSR_MPM_MEM_LAT 12'hB1A // memory latency -`define VX_CSR_MPM_MEM_LAT_H 12'hB9A +`define VX_CSR_MPM_MEM_LT 12'hB1A // memory latency +`define VX_CSR_MPM_MEM_LT_H 12'hB9A // PERF: smem `define VX_CSR_MPM_SMEM_READS 12'hB1B // memory reads `define VX_CSR_MPM_SMEM_READS_H 12'hB9B diff --git a/hw/rtl/Vortex.sv b/hw/rtl/Vortex.sv index b29f0802..e9d068f7 100644 --- a/hw/rtl/Vortex.sv +++ b/hw/rtl/Vortex.sv @@ -49,12 +49,12 @@ module Vortex import VX_gpu_pkg::*; ( cache_perf_t perf_l3cache; mem_perf_t mem_perf; - assign mem_perf_if.icache = 'x; - assign mem_perf_if.dcache = 'x; + assign mem_perf_if.smem = 'x; + assign mem_perf_if.icache = 'x; + assign mem_perf_if.dcache = 'x; assign mem_perf_if.l2cache = 'x; assign mem_perf_if.l3cache = perf_l3cache; - assign mem_perf_if.smem = 'x; - assign mem_perf_if.mem = mem_perf; + assign mem_perf_if.mem = mem_perf; `endif VX_mem_bus_if #( diff --git a/hw/rtl/core/VX_core_top.sv b/hw/rtl/core/VX_core_top.sv index 8d126f96..6ecd4772 100644 --- a/hw/rtl/core/VX_core_top.sv +++ b/hw/rtl/core/VX_core_top.sv @@ -130,6 +130,12 @@ module VX_core_top import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE VX_mem_perf_if mem_perf_if(); + assign mem_perf_if.smem = '0; + assign mem_perf_if.icache = '0; + assign mem_perf_if.dcache = '0; + assign mem_perf_if.l2cache = '0; + assign mem_perf_if.l3cache = '0; + assign mem_perf_if.mem = '0; `endif `ifdef SCOPE diff --git a/hw/rtl/core/VX_csr_data.sv b/hw/rtl/core/VX_csr_data.sv index 44e997ff..6d7c41f8 100644 --- a/hw/rtl/core/VX_csr_data.sv +++ b/hw/rtl/core/VX_csr_data.sv @@ -186,11 +186,11 @@ import VX_fpu_pkg::*; case (base_dcrs.mpm_class) `VX_DCR_MPM_CLASS_CORE: begin case (read_addr) - // PERF: pipeline + // PERF: pipeline + `VX_CSR_MPM_SCHED_ID : read_data_ro_r = pipeline_perf_if.sched_idles[31:0]; + `VX_CSR_MPM_SCHED_ID_H : read_data_ro_r = 32'(pipeline_perf_if.sched_idles[`PERF_CTR_BITS-1:32]); `VX_CSR_MPM_SCHED_ST : read_data_ro_r = pipeline_perf_if.sched_stalls[31:0]; - `VX_CSR_MPM_SCHED_ST_H : read_data_ro_r = 32'(pipeline_perf_if.sched_stalls[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_FETCH_ST : read_data_ro_r = pipeline_perf_if.fetch_stalls[31:0]; - `VX_CSR_MPM_FETCH_ST_H : read_data_ro_r = 32'(pipeline_perf_if.fetch_stalls[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SCHED_ST_H : read_data_ro_r = 32'(pipeline_perf_if.sched_stalls[`PERF_CTR_BITS-1:32]); `VX_CSR_MPM_IBUF_ST : read_data_ro_r = pipeline_perf_if.ibf_stalls[31:0]; `VX_CSR_MPM_IBUF_ST_H : read_data_ro_r = 32'(pipeline_perf_if.ibf_stalls[`PERF_CTR_BITS-1:32]); `VX_CSR_MPM_SCRB_ST : read_data_ro_r = pipeline_perf_if.scb_stalls[31:0]; @@ -228,10 +228,10 @@ import VX_fpu_pkg::*; `VX_CSR_MPM_LOADS_H : read_data_ro_r = 32'(pipeline_perf_if.loads[`PERF_CTR_BITS-1:32]); `VX_CSR_MPM_STORES : read_data_ro_r = pipeline_perf_if.stores[31:0]; `VX_CSR_MPM_STORES_H : read_data_ro_r = 32'(pipeline_perf_if.stores[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_IFETCH_LAT : read_data_ro_r = pipeline_perf_if.ifetch_latency[31:0]; - `VX_CSR_MPM_IFETCH_LAT_H : read_data_ro_r = 32'(pipeline_perf_if.ifetch_latency[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_LOAD_LAT : read_data_ro_r = pipeline_perf_if.load_latency[31:0]; - `VX_CSR_MPM_LOAD_LAT_H : read_data_ro_r = 32'(pipeline_perf_if.load_latency[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_IFETCH_LT : read_data_ro_r = pipeline_perf_if.ifetch_latency[31:0]; + `VX_CSR_MPM_IFETCH_LT_H : read_data_ro_r = 32'(pipeline_perf_if.ifetch_latency[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_LOAD_LT : read_data_ro_r = pipeline_perf_if.load_latency[31:0]; + `VX_CSR_MPM_LOAD_LT_H : read_data_ro_r = 32'(pipeline_perf_if.load_latency[`PERF_CTR_BITS-1:32]); default:; endcase end @@ -295,8 +295,8 @@ import VX_fpu_pkg::*; `VX_CSR_MPM_MEM_READS_H : read_data_ro_r = 32'(mem_perf_if.mem.reads[`PERF_CTR_BITS-1:32]); `VX_CSR_MPM_MEM_WRITES : read_data_ro_r = mem_perf_if.mem.writes[31:0]; `VX_CSR_MPM_MEM_WRITES_H : read_data_ro_r = 32'(mem_perf_if.mem.writes[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_MEM_LAT : read_data_ro_r = mem_perf_if.mem.latency[31:0]; - `VX_CSR_MPM_MEM_LAT_H : read_data_ro_r = 32'(mem_perf_if.mem.latency[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_MEM_LT : read_data_ro_r = mem_perf_if.mem.latency[31:0]; + `VX_CSR_MPM_MEM_LT_H : read_data_ro_r = 32'(mem_perf_if.mem.latency[`PERF_CTR_BITS-1:32]); default:; endcase end diff --git a/hw/rtl/core/VX_dispatch_unit.sv b/hw/rtl/core/VX_dispatch_unit.sv index 86564187..586acc0b 100644 --- a/hw/rtl/core/VX_dispatch_unit.sv +++ b/hw/rtl/core/VX_dispatch_unit.sv @@ -70,8 +70,8 @@ module VX_dispatch_unit import VX_gpu_pkg::*; #( always @(posedge clk) begin if (reset) begin batch_idx <= '0; - end else if (batch_done) begin - batch_idx <= batch_idx + BATCH_COUNT_W'(1); + end else begin + batch_idx <= batch_idx + BATCH_COUNT_W'(batch_done); end end end else begin diff --git a/hw/rtl/core/VX_lsu_unit.sv b/hw/rtl/core/VX_lsu_unit.sv index b939b081..3383f70f 100644 --- a/hw/rtl/core/VX_lsu_unit.sv +++ b/hw/rtl/core/VX_lsu_unit.sv @@ -554,7 +554,7 @@ module VX_lsu_unit import VX_gpu_pkg::*; #( VX_stream_arb #( .NUM_INPUTS (2), .DATAW (RSP_ARB_DATAW), - .OUT_REG (1) + .OUT_REG (2) ) rsp_arb ( .clk (clk), .reset (commit_reset), diff --git a/hw/rtl/core/VX_schedule.sv b/hw/rtl/core/VX_schedule.sv index f11e4324..4f74af36 100644 --- a/hw/rtl/core/VX_schedule.sv +++ b/hw/rtl/core/VX_schedule.sv @@ -381,23 +381,24 @@ module VX_schedule import VX_gpu_pkg::*; #( `RUNTIME_ASSERT(timeout_ctr < `STALL_TIMEOUT, ("%t: *** core%0d-scheduler-timeout: stalled_warps=%b", $time, CORE_ID, stalled_warps)); `ifdef PERF_ENABLE + reg [`PERF_CTR_BITS-1:0] perf_sched_idles; reg [`PERF_CTR_BITS-1:0] perf_sched_stalls; - reg [`PERF_CTR_BITS-1:0] perf_fetch_stalls; + wire schedule_idle = ~schedule_valid; wire schedule_stall = schedule_if.valid && ~schedule_if.ready; always @(posedge clk) begin if (reset) begin - perf_sched_stalls <= '0; - perf_fetch_stalls <= '0; + perf_sched_idles <= '0; + perf_sched_stalls <= '0; end else begin - perf_sched_stalls <= perf_sched_stalls + `PERF_CTR_BITS'(~schedule_valid); - perf_fetch_stalls <= perf_fetch_stalls + `PERF_CTR_BITS'(schedule_stall); + perf_sched_idles <= perf_sched_idles + `PERF_CTR_BITS'(schedule_idle); + perf_sched_stalls <= perf_sched_stalls + `PERF_CTR_BITS'(schedule_stall); end end - assign perf_schedule_if.sched_stalls = perf_sched_stalls; - assign perf_schedule_if.fetch_stalls = perf_fetch_stalls; + assign perf_schedule_if.sched_idles = perf_sched_idles; + assign perf_schedule_if.sched_stalls = perf_sched_stalls; `endif endmodule diff --git a/hw/rtl/fpu/VX_fpu_cvt.sv b/hw/rtl/fpu/VX_fpu_cvt.sv index e12e51ad..7ba6330e 100644 --- a/hw/rtl/fpu/VX_fpu_cvt.sv +++ b/hw/rtl/fpu/VX_fpu_cvt.sv @@ -355,11 +355,14 @@ module VX_fpu_cvt import VX_fpu_pkg::*; #( wire [NUM_LANES-1:0][INT_WIDTH-1:0] tmp_result_s3; for (genvar i = 0; i < NUM_LANES; ++i) begin - fflags_t i2f_regular_status_s3 = i2f_round_has_sticky_s3[i] ? 5'h1 : 5'h0; - fflags_t f2i_regular_status_s3 = f2i_round_has_sticky_s3[i] ? 5'h1 : 5'h0; + fflags_t i2f_regular_status_s3, f2i_regular_status_s3; + fflags_t i2f_status_s3, f2i_status_s3; - fflags_t i2f_status_s3 = i2f_regular_status_s3; - fflags_t f2i_status_s3 = f2i_result_is_special_s3[i] ? f2i_special_status_s3[i] : f2i_regular_status_s3; + assign i2f_regular_status_s3 = {4'h0, i2f_round_has_sticky_s3[i]}; + assign f2i_regular_status_s3 = {4'h0, f2i_round_has_sticky_s3[i]}; + + assign i2f_status_s3 = i2f_regular_status_s3; + assign f2i_status_s3 = f2i_result_is_special_s3[i] ? f2i_special_status_s3[i] : f2i_regular_status_s3; wire [INT_WIDTH-1:0] i2f_result_s3 = fmt_result_s3[i]; wire [INT_WIDTH-1:0] f2i_result_s3 = f2i_result_is_special_s3[i] ? f2i_special_result_s3[i] : rounded_int_res_s3[i]; diff --git a/hw/rtl/interfaces/VX_pipeline_perf_if.sv b/hw/rtl/interfaces/VX_pipeline_perf_if.sv index 4f6ffb5d..66225336 100644 --- a/hw/rtl/interfaces/VX_pipeline_perf_if.sv +++ b/hw/rtl/interfaces/VX_pipeline_perf_if.sv @@ -14,8 +14,8 @@ `include "VX_define.vh" interface VX_pipeline_perf_if (); + wire [`PERF_CTR_BITS-1:0] sched_idles; wire [`PERF_CTR_BITS-1:0] sched_stalls; - wire [`PERF_CTR_BITS-1:0] fetch_stalls; wire [`PERF_CTR_BITS-1:0] ibf_stalls; wire [`PERF_CTR_BITS-1:0] scb_stalls; wire [`PERF_CTR_BITS-1:0] scb_uses [`NUM_EX_UNITS]; @@ -28,8 +28,8 @@ interface VX_pipeline_perf_if (); wire [`PERF_CTR_BITS-1:0] load_latency; modport schedule ( - output sched_stalls, - output fetch_stalls + output sched_idles, + output sched_stalls ); modport issue ( @@ -40,8 +40,8 @@ interface VX_pipeline_perf_if (); ); modport slave ( + input sched_idles, input sched_stalls, - input fetch_stalls, input ibf_stalls, input scb_stalls, input scb_uses, diff --git a/hw/rtl/libs/VX_fifo_queue.sv b/hw/rtl/libs/VX_fifo_queue.sv index 78a2785c..1eda9fff 100644 --- a/hw/rtl/libs/VX_fifo_queue.sv +++ b/hw/rtl/libs/VX_fifo_queue.sv @@ -201,9 +201,7 @@ module VX_fifo_queue #( rd_ptr_r <= '0; rd_ptr_n_r <= 1; end else begin - if (push) begin - wr_ptr_r <= wr_ptr_r + ADDRW'(1); - end + wr_ptr_r <= wr_ptr_r + ADDRW'(push); if (pop) begin rd_ptr_r <= rd_ptr_n_r; if (DEPTH > 2) begin diff --git a/runtime/common/utils.cpp b/runtime/common/utils.cpp index 574f64a7..c0199a86 100644 --- a/runtime/common/utils.cpp +++ b/runtime/common/utils.cpp @@ -175,8 +175,9 @@ static uint64_t get_csr_64(const void* ptr, int addr) { extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { int ret = 0; - uint64_t instrs = 0; - uint64_t cycles = 0; + uint64_t total_instrs = 0; + uint64_t total_cycles = 0; + uint64_t max_cycles = 0; #ifdef PERF_ENABLE @@ -199,8 +200,8 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { auto perf_class = gAutoPerfDump.get_perf_class(); // PERF: pipeline stalls - uint64_t scheduler_stalls = 0; - uint64_t fetch_stalls = 0; + uint64_t sched_idles = 0; + uint64_t sched_stalls = 0; uint64_t ibuffer_stalls = 0; uint64_t scrb_stalls = 0; uint64_t lsu_stalls = 0; @@ -269,19 +270,19 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { switch (perf_class) { case VX_DCR_MPM_CLASS_CORE: { // PERF: pipeline - // schedule stalls + // scheduler idles { - uint64_t scheduler_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCHED_ST); - int scheduler_percent_per_core = calcAvgPercent(scheduler_stalls_per_core, cycles_per_core); - if (num_cores > 1) fprintf(stream, "PERF: core%d: schedule stalls=%ld (%d%%)\n", core_id, scheduler_stalls_per_core, scheduler_percent_per_core); - scheduler_stalls += scheduler_stalls_per_core; + uint64_t sched_idles_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCHED_ID); + int idles_percent_per_core = calcAvgPercent(sched_idles_per_core, cycles_per_core); + if (num_cores > 1) fprintf(stream, "PERF: core%d: scheduler idles=%ld (%d%%)\n", core_id, sched_idles_per_core, idles_percent_per_core); + sched_idles += sched_idles_per_core; } - // fetch stalls + // scheduler stalls { - uint64_t fetch_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_FETCH_ST); - int fetch_percent_per_core = calcAvgPercent(fetch_stalls_per_core, cycles_per_core); - if (num_cores > 1) fprintf(stream, "PERF: core%d: ifetch stalls=%ld (%d%%)\n", core_id, fetch_stalls_per_core, fetch_percent_per_core); - fetch_stalls += fetch_stalls_per_core; + uint64_t sched_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCHED_ST); + int stalls_percent_per_core = calcAvgPercent(sched_stalls_per_core, cycles_per_core); + if (num_cores > 1) fprintf(stream, "PERF: core%d: scheduler stalls=%ld (%d%%)\n", core_id, sched_stalls_per_core, stalls_percent_per_core); + sched_stalls += sched_stalls_per_core; } // ibuffer_stalls { @@ -340,7 +341,7 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { if (num_cores > 1) fprintf(stream, "PERF: core%d: ifetches=%ld\n", core_id, ifetches_per_core); ifetches += ifetches_per_core; - uint64_t ifetch_lat_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_IFETCH_LAT); + uint64_t ifetch_lat_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_IFETCH_LT); int mem_avg_lat = caclAverage(ifetch_lat_per_core, ifetches_per_core); if (num_cores > 1) fprintf(stream, "PERF: core%d: ifetch latency=%d cycles\n", core_id, mem_avg_lat); ifetch_lat += ifetch_lat_per_core; @@ -351,7 +352,7 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { if (num_cores > 1) fprintf(stream, "PERF: core%d: loads=%ld\n", core_id, loads_per_core); loads += loads_per_core; - uint64_t load_lat_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_LOAD_LAT); + uint64_t load_lat_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_LOAD_LT); int mem_avg_lat = caclAverage(load_lat_per_core, loads_per_core); if (num_cores > 1) fprintf(stream, "PERF: core%d: load latency=%d cycles\n", core_id, mem_avg_lat); load_lat += load_lat_per_core; @@ -431,7 +432,7 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { // PERF: memory mem_reads = get_csr_64(staging_buf.data(), VX_CSR_MPM_MEM_READS); mem_writes = get_csr_64(staging_buf.data(), VX_CSR_MPM_MEM_WRITES); - mem_lat = get_csr_64(staging_buf.data(), VX_CSR_MPM_MEM_LAT); + mem_lat = get_csr_64(staging_buf.data(), VX_CSR_MPM_MEM_LT); } } break; default: @@ -441,21 +442,22 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { float IPC = (float)(double(instrs_per_core) / double(cycles_per_core)); if (num_cores > 1) fprintf(stream, "PERF: core%d: instrs=%ld, cycles=%ld, IPC=%f\n", core_id, instrs_per_core, cycles_per_core, IPC); - instrs += instrs_per_core; - cycles = std::max(cycles_per_core, cycles); + total_instrs += instrs_per_core; + total_cycles += cycles_per_core; + max_cycles = std::max(cycles_per_core, max_cycles); } #ifdef PERF_ENABLE switch (perf_class) { case VX_DCR_MPM_CLASS_CORE: { - int scheduler_percent = calcAvgPercent(scheduler_stalls, cycles); - int fetch_percent = calcAvgPercent(fetch_stalls, cycles); - int ibuffer_percent = calcAvgPercent(ibuffer_stalls, cycles); + int sched_idles_percent = calcAvgPercent(sched_idles, total_cycles); + int sched_stalls_percent = calcAvgPercent(sched_stalls, total_cycles); + int ibuffer_percent = calcAvgPercent(ibuffer_stalls, total_cycles); int ifetch_avg_lat = (int)(double(ifetch_lat) / double(ifetches)); int load_avg_lat = (int)(double(load_lat) / double(loads)); uint64_t scrb_total = scrb_alu + scrb_fpu + scrb_lsu + scrb_sfu; - fprintf(stream, "PERF: scheduler stalls=%ld (%d%%)\n", scheduler_stalls, scheduler_percent); - fprintf(stream, "PERF: fetch stalls=%ld (%d%%)\n", fetch_stalls, fetch_percent); + fprintf(stream, "PERF: scheduler idles=%ld (%d%%)\n", sched_idles, sched_idles_percent); + fprintf(stream, "PERF: scheduler stalls=%ld (%d%%)\n", sched_stalls, sched_stalls_percent); fprintf(stream, "PERF: ibuffer stalls=%ld (%d%%)\n", ibuffer_stalls, ibuffer_percent); fprintf(stream, "PERF: scoreboard stalls=%ld (alu=%d%%, fpu=%d%%, lsu=%d%%, sfu=%d%%)\n", scrb_stalls, calcAvgPercent(scrb_alu, scrb_total), @@ -514,8 +516,8 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { } #endif - float IPC = (float)(double(instrs) / double(cycles)); - fprintf(stream, "PERF: instrs=%ld, cycles=%ld, IPC=%f\n", instrs, cycles, IPC); + float IPC = (float)(double(total_instrs) / double(max_cycles)); + fprintf(stream, "PERF: instrs=%ld, cycles=%ld, IPC=%f\n", total_instrs, max_cycles, IPC); fflush(stream); diff --git a/sim/simx/core.cpp b/sim/simx/core.cpp index b2fe7ea2..49c2ec35 100644 --- a/sim/simx/core.cpp +++ b/sim/simx/core.cpp @@ -167,7 +167,7 @@ void Core::schedule() { } } if (scheduled_warp == -1) { - ++perf_stats_.sched_stalls; + ++perf_stats_.sched_idles; return; } @@ -548,10 +548,10 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { break; case VX_DCR_MPM_CLASS_CORE: { switch (addr) { + case VX_CSR_MPM_SCHED_ID: return perf_stats_.sched_idles & 0xffffffff; + case VX_CSR_MPM_SCHED_ID_H:return perf_stats_.sched_idles >> 32; case VX_CSR_MPM_SCHED_ST: return perf_stats_.sched_stalls & 0xffffffff; case VX_CSR_MPM_SCHED_ST_H:return perf_stats_.sched_stalls >> 32; - case VX_CSR_MPM_FETCH_ST: return perf_stats_.fetch_stalls & 0xffffffff; - case VX_CSR_MPM_FETCH_ST_H:return perf_stats_.fetch_stalls >> 32; case VX_CSR_MPM_IBUF_ST: return perf_stats_.ibuf_stalls & 0xffffffff; case VX_CSR_MPM_IBUF_ST_H: return perf_stats_.ibuf_stalls >> 32; case VX_CSR_MPM_SCRB_ST: return perf_stats_.scrb_stalls & 0xffffffff; @@ -579,10 +579,10 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { case VX_CSR_MPM_LOADS_H: return perf_stats_.loads >> 32; case VX_CSR_MPM_STORES: return perf_stats_.stores & 0xffffffff; case VX_CSR_MPM_STORES_H: return perf_stats_.stores >> 32; - case VX_CSR_MPM_IFETCH_LAT: return perf_stats_.ifetch_latency & 0xffffffff; - case VX_CSR_MPM_IFETCH_LAT_H: return perf_stats_.ifetch_latency >> 32; - case VX_CSR_MPM_LOAD_LAT: return perf_stats_.load_latency & 0xffffffff; - case VX_CSR_MPM_LOAD_LAT_H: return perf_stats_.load_latency >> 32; + case VX_CSR_MPM_IFETCH_LT: return perf_stats_.ifetch_latency & 0xffffffff; + case VX_CSR_MPM_IFETCH_LT_H: return perf_stats_.ifetch_latency >> 32; + case VX_CSR_MPM_LOAD_LT: return perf_stats_.load_latency & 0xffffffff; + case VX_CSR_MPM_LOAD_LT_H: return perf_stats_.load_latency >> 32; } } break; case VX_DCR_MPM_CLASS_MEM: { @@ -638,8 +638,8 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { case VX_CSR_MPM_MEM_READS_H: return proc_perf.mem_reads >> 32; case VX_CSR_MPM_MEM_WRITES: return proc_perf.mem_writes & 0xffffffff; case VX_CSR_MPM_MEM_WRITES_H: return proc_perf.mem_writes >> 32; - case VX_CSR_MPM_MEM_LAT: return proc_perf.mem_latency & 0xffffffff; - case VX_CSR_MPM_MEM_LAT_H: return proc_perf.mem_latency >> 32; + case VX_CSR_MPM_MEM_LT: return proc_perf.mem_latency & 0xffffffff; + case VX_CSR_MPM_MEM_LT_H : return proc_perf.mem_latency >> 32; case VX_CSR_MPM_SMEM_READS: return proc_perf.clusters.sharedmem.reads & 0xffffffff; case VX_CSR_MPM_SMEM_READS_H: return proc_perf.clusters.sharedmem.reads >> 32; diff --git a/sim/simx/core.h b/sim/simx/core.h index 60290bef..cef60e81 100644 --- a/sim/simx/core.h +++ b/sim/simx/core.h @@ -49,8 +49,8 @@ public: struct PerfStats { uint64_t cycles; uint64_t instrs; + uint64_t sched_idles; uint64_t sched_stalls; - uint64_t fetch_stalls; uint64_t ibuf_stalls; uint64_t scrb_stalls; uint64_t alu_stalls; @@ -70,8 +70,8 @@ public: PerfStats() : cycles(0) , instrs(0) + , sched_idles(0) , sched_stalls(0) - , fetch_stalls(0) , ibuf_stalls(0) , scrb_stalls(0) , alu_stalls(0) diff --git a/tests/opencl/Makefile b/tests/opencl/Makefile index c7ba1ed7..5d18f9cd 100644 --- a/tests/opencl/Makefile +++ b/tests/opencl/Makefile @@ -9,16 +9,16 @@ all: $(MAKE) -C dotproduct $(MAKE) -C kmeans $(MAKE) -C spmv - $(MAKE) -C transpose - $(MAKE) -C cutcp - $(MAKE) -C vectorhypot $(MAKE) -C stencil - $(MAKE) -C mri-q $(MAKE) -C lbm $(MAKE) -C oclprintf $(MAKE) -C blackscholes - $(MAKE) -C sgemm2 + $(MAKE) -C transpose $(MAKE) -C convolution +# $(MAKE) -C cutcp +# $(MAKE) -C sgemm2 +# $(MAKE) -C vectorhypot +# $(MAKE) -C mri-q run-simx run-simx: $(MAKE) -C vecadd run-simx @@ -37,10 +37,10 @@ run-simx: $(MAKE) -C blackscholes run-simx $(MAKE) -C transpose run-simx $(MAKE) -C convolution run-simx - $(MAKE) -C cutcp run-simx - $(MAKE) -C vectorhypot run-simx - $(MAKE) -C mri-q run-simx +# $(MAKE) -C cutcp run-simx # $(MAKE) -C sgemm2 run-simx +# $(MAKE) -C vectorhypot run-simx +# $(MAKE) -C mri-q run-simx run-rtlsim: $(MAKE) -C vecadd run-rtlsim @@ -98,15 +98,15 @@ clean: $(MAKE) -C kmeans clean $(MAKE) -C spmv clean $(MAKE) -C transpose clean - $(MAKE) -C cutcp clean - $(MAKE) -C vectorhypot clean $(MAKE) -C stencil clean - $(MAKE) -C mri-q clean $(MAKE) -C lbm clean $(MAKE) -C oclprintf clean $(MAKE) -C blackscholes clean - $(MAKE) -C sgemm2 clean $(MAKE) -C convolution clean +# $(MAKE) -C cutcp clean +# $(MAKE) -C sgemm2 clean +# $(MAKE) -C vectorhypot clean +# $(MAKE) -C mri-q clean clean-all: $(MAKE) -C vecadd clean-all @@ -114,19 +114,18 @@ clean-all: $(MAKE) -C psort clean-all $(MAKE) -C saxpy clean-all $(MAKE) -C sfilter clean-all - $(MAKE) -C sfilter clean-all $(MAKE) -C nearn clean-all $(MAKE) -C guassian clean-all $(MAKE) -C dotproduct clean-all $(MAKE) -C kmeans clean-all $(MAKE) -C spmv clean-all $(MAKE) -C transpose clean-all - $(MAKE) -C cutcp clean-all - $(MAKE) -C vectorhypot clean-all $(MAKE) -C stencil clean-all - $(MAKE) -C mri-q clean-all $(MAKE) -C lbm clean-all $(MAKE) -C oclprintf clean-all $(MAKE) -C blackscholes clean-all - $(MAKE) -C sgemm2 clean-all $(MAKE) -C convolution clean-all +# $(MAKE) -C cutcp clean-all +# $(MAKE) -C sgemm2 clean-all +# $(MAKE) -C vectorhypot clean-all +# $(MAKE) -C mri-q clean-all From 5a2bc88d20c8e15394efe0e4470f7e83c555cf61 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Fri, 15 Dec 2023 14:09:51 -0800 Subject: [PATCH 29/57] operands optimization minor updates minor updates --- hw/rtl/VX_gpu_pkg.sv | 50 +++++---- hw/rtl/core/VX_dispatch_unit.sv | 10 +- hw/rtl/core/VX_gather_unit.sv | 14 +-- hw/rtl/core/VX_operands.sv | 184 +++++++++++++++----------------- hw/rtl/core/VX_scoreboard.sv | 41 +++---- 5 files changed, 142 insertions(+), 157 deletions(-) diff --git a/hw/rtl/VX_gpu_pkg.sv b/hw/rtl/VX_gpu_pkg.sv index 4ece6c9c..668b53ee 100644 --- a/hw/rtl/VX_gpu_pkg.sv +++ b/hw/rtl/VX_gpu_pkg.sv @@ -190,42 +190,46 @@ package VX_gpu_pkg; /////////////////////////////// Issue parameters ////////////////////////// - localparam ISSUE_IDX_W = `LOG2UP(`ISSUE_WIDTH); + localparam ISSUE_ISW = `CLOG2(`ISSUE_WIDTH); + localparam ISSUE_ISW_W = `UP(ISSUE_ISW); localparam ISSUE_RATIO = `NUM_WARPS / `ISSUE_WIDTH; - localparam ISSUE_WIS_W = `LOG2UP(ISSUE_RATIO); - localparam ISSUE_ADDRW = `LOG2UP(`NUM_REGS * (ISSUE_RATIO)); - + localparam ISSUE_WIS = `CLOG2(ISSUE_RATIO); + localparam ISSUE_WIS_W = `UP(ISSUE_WIS); + `IGNORE_UNUSED_BEGIN - function logic [ISSUE_IDX_W-1:0] wid_to_isw( + function logic [`NW_WIDTH-1:0] wis_to_wid( + input logic [ISSUE_WIS_W-1:0] wis, + input logic [ISSUE_ISW_W-1:0] isw + ); + if (ISSUE_WIS == 0) begin + wis_to_wid = `NW_WIDTH'(isw); + end else if (ISSUE_ISW == 0) begin + wis_to_wid = `NW_WIDTH'(wis); + end else begin + wis_to_wid = `NW_WIDTH'({wis, isw}); + end + endfunction + + function logic [ISSUE_ISW_W-1:0] wid_to_isw( input logic [`NW_WIDTH-1:0] wid ); - if (`ISSUE_WIDTH > 1) begin - wid_to_isw = ISSUE_IDX_W'(wid); + if (ISSUE_ISW != 0) begin + wid_to_isw = wid[ISSUE_ISW_W-1:0]; end else begin wid_to_isw = 0; end endfunction -`IGNORE_UNUSED_END - - function logic [`NW_WIDTH-1:0] wis_to_wid( - input logic [ISSUE_WIS_W-1:0] wis, - input logic [ISSUE_IDX_W-1:0] isw - ); - wis_to_wid = `NW_WIDTH'({wis, isw} >> (ISSUE_IDX_W-`CLOG2(`ISSUE_WIDTH))); - endfunction function logic [ISSUE_WIS_W-1:0] wid_to_wis( input logic [`NW_WIDTH-1:0] wid ); - wid_to_wis = ISSUE_WIS_W'({1'b0, wid} >> `CLOG2(`ISSUE_WIDTH)); - endfunction - - function logic [ISSUE_ADDRW-1:0] wis_to_addr( - input logic [`NR_BITS-1:0] rid, - input logic [ISSUE_WIS_W-1:0] wis - ); - wis_to_addr = ISSUE_ADDRW'({rid, wis} >> (ISSUE_WIS_W-`CLOG2(ISSUE_RATIO))); + if (ISSUE_WIS != 0) begin + wid_to_wis = ISSUE_WIS_W'(wid >> ISSUE_ISW); + end else begin + wid_to_wis = 0; + end endfunction +`IGNORE_UNUSED_END endpackage diff --git a/hw/rtl/core/VX_dispatch_unit.sv b/hw/rtl/core/VX_dispatch_unit.sv index 586acc0b..6e36a33b 100644 --- a/hw/rtl/core/VX_dispatch_unit.sv +++ b/hw/rtl/core/VX_dispatch_unit.sv @@ -203,20 +203,20 @@ module VX_dispatch_unit import VX_gpu_pkg::*; #( assign block_done[block_idx] = ~valid_p || ready_p; end - wire [ISSUE_IDX_W-1:0] wsi; + wire [ISSUE_ISW_W-1:0] isw; if (BATCH_COUNT != 1) begin if (BLOCK_SIZE != 1) begin - assign wsi = {batch_idx, BLOCK_SIZE_W'(block_idx)}; + assign isw = {batch_idx, BLOCK_SIZE_W'(block_idx)}; end else begin - assign wsi = batch_idx; + assign isw = batch_idx; end end else begin - assign wsi = block_idx; + assign isw = block_idx; end `RESET_RELAY(buf_out_reset, reset); - wire [`NW_WIDTH-1:0] block_wid = wis_to_wid(dispatch_data[issue_idx][DATA_TMASK_OFF+`NUM_THREADS +: ISSUE_WIS_W], wsi); + wire [`NW_WIDTH-1:0] block_wid = wis_to_wid(dispatch_data[issue_idx][DATA_TMASK_OFF+`NUM_THREADS +: ISSUE_WIS_W], isw); VX_elastic_buffer #( .DATAW (OUT_DATAW), diff --git a/hw/rtl/core/VX_gather_unit.sv b/hw/rtl/core/VX_gather_unit.sv index e3dc935d..21ae4485 100644 --- a/hw/rtl/core/VX_gather_unit.sv +++ b/hw/rtl/core/VX_gather_unit.sv @@ -37,7 +37,7 @@ module VX_gather_unit import VX_gpu_pkg::*; #( wire [BLOCK_SIZE-1:0] commit_in_valid; wire [BLOCK_SIZE-1:0][DATAW-1:0] commit_in_data; wire [BLOCK_SIZE-1:0] commit_in_ready; - wire [BLOCK_SIZE-1:0][ISSUE_IDX_W-1:0] commit_in_wsi; + wire [BLOCK_SIZE-1:0][ISSUE_ISW_W-1:0] commit_in_isw; for (genvar i = 0; i < BLOCK_SIZE; ++i) begin assign commit_in_valid[i] = commit_in_if[i].valid; @@ -45,12 +45,12 @@ module VX_gather_unit import VX_gpu_pkg::*; #( assign commit_in_if[i].ready = commit_in_ready[i]; if (BLOCK_SIZE != `ISSUE_WIDTH) begin if (BLOCK_SIZE != 1) begin - assign commit_in_wsi[i] = {commit_in_data[i][DATA_WIS_OFF+BLOCK_SIZE_W +: (ISSUE_IDX_W-BLOCK_SIZE_W)], BLOCK_SIZE_W'(i)}; + assign commit_in_isw[i] = {commit_in_data[i][DATA_WIS_OFF+BLOCK_SIZE_W +: (ISSUE_ISW_W-BLOCK_SIZE_W)], BLOCK_SIZE_W'(i)}; end else begin - assign commit_in_wsi[i] = commit_in_data[i][DATA_WIS_OFF +: ISSUE_IDX_W]; + assign commit_in_isw[i] = commit_in_data[i][DATA_WIS_OFF +: ISSUE_ISW_W]; end end else begin - assign commit_in_wsi[i] = BLOCK_SIZE_W'(i); + assign commit_in_isw[i] = BLOCK_SIZE_W'(i); end end @@ -64,12 +64,12 @@ module VX_gather_unit import VX_gpu_pkg::*; #( commit_out_data[i] = 'x; end for (integer i = 0; i < BLOCK_SIZE; ++i) begin - commit_out_valid[commit_in_wsi[i]] = commit_in_valid[i]; - commit_out_data[commit_in_wsi[i]] = commit_in_data[i]; + commit_out_valid[commit_in_isw[i]] = commit_in_valid[i]; + commit_out_data[commit_in_isw[i]] = commit_in_data[i]; end end for (genvar i = 0; i < BLOCK_SIZE; ++i) begin - assign commit_in_ready[i] = commit_out_ready[commit_in_wsi[i]]; + assign commit_in_ready[i] = commit_out_ready[commit_in_isw[i]]; end for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin diff --git a/hw/rtl/core/VX_operands.sv b/hw/rtl/core/VX_operands.sv index 3ff5df46..ee0c493b 100644 --- a/hw/rtl/core/VX_operands.sv +++ b/hw/rtl/core/VX_operands.sv @@ -26,6 +26,7 @@ module VX_operands import VX_gpu_pkg::*; #( ); `UNUSED_PARAM (CORE_ID) localparam DATAW = `UUID_WIDTH + ISSUE_WIS_W + `NUM_THREADS + `XLEN + 1 + `EX_BITS + `INST_OP_BITS + `INST_MOD_BITS + 1 + 1 + `XLEN + `NR_BITS; + localparam RAM_ADDRW = `LOG2UP(`NUM_REGS * ISSUE_RATIO); localparam STATE_IDLE = 2'd0; localparam STATE_FETCH1 = 2'd1; @@ -46,9 +47,11 @@ module VX_operands import VX_gpu_pkg::*; #( reg [`NUM_THREADS-1:0] cache_tmask_n [ISSUE_RATIO-1:0]; reg [ISSUE_RATIO-1:0] cache_eop, cache_eop_n; + reg valid_out_r; + reg [DATAW-1:0] data_out_r; reg [`NUM_THREADS-1:0][`XLEN-1:0] rs1_data, rs1_data_n; reg [`NUM_THREADS-1:0][`XLEN-1:0] rs2_data, rs2_data_n; - reg [`NUM_THREADS-1:0][`XLEN-1:0] rs3_data, rs3_data_n; + reg [`NUM_THREADS-1:0][`XLEN-1:0] rs3_data, rs3_data_n; reg [STATE_BITS-1:0] state, state_n; reg [`NR_BITS-1:0] rs2, rs2_n; @@ -57,11 +60,11 @@ module VX_operands import VX_gpu_pkg::*; #( reg rs3_ready, rs3_ready_n; reg data_ready, data_ready_n; + wire ready_out = operands_if[i].ready; + wire is_rs1_zero = (scoreboard_if[i].data.rs1 == 0); wire is_rs2_zero = (scoreboard_if[i].data.rs2 == 0); - wire is_rs3_zero = (scoreboard_if[i].data.rs3 == 0); - - VX_operands_if staging_if(); + wire is_rs3_zero = (scoreboard_if[i].data.rs3 == 0); always @(*) begin state_n = state; @@ -82,7 +85,7 @@ module VX_operands import VX_gpu_pkg::*; #( case (state) STATE_IDLE: begin - if (staging_if.valid && staging_if.ready) begin + if (valid_out_r && ready_out) begin data_ready_n = 0; end if (scoreboard_if[i].valid && data_ready_n == 0) begin @@ -170,33 +173,86 @@ module VX_operands import VX_gpu_pkg::*; #( end always @(posedge clk) begin - if (reset) begin + if (reset) begin state <= STATE_IDLE; - gpr_rd_rid <= '0; - gpr_rd_wis <= '0; cache_eop <= {ISSUE_RATIO{1'b1}}; data_ready <= 0; + valid_out_r <= 0; end else begin state <= state_n; - rs2 <= rs2_n; - rs3 <= rs3_n; - rs2_ready <= rs2_ready_n; - rs3_ready <= rs3_ready_n; - rs1_data <= rs1_data_n; - rs2_data <= rs2_data_n; - rs3_data <= rs3_data_n; - gpr_rd_rid <= gpr_rd_rid_n; - gpr_rd_wis <= gpr_rd_wis_n; - cache_data <= cache_data_n; - cache_reg <= cache_reg_n; - cache_tmask <= cache_tmask_n; cache_eop <= cache_eop_n; - data_ready <= data_ready_n; + data_ready <= data_ready_n; + if (~valid_out_r) begin + valid_out_r <= scoreboard_if[i].valid && data_ready; + end else if (ready_out) begin + valid_out_r <= 0; + end end - end + + if (~valid_out_r) begin + data_out_r <= {scoreboard_if[i].data.uuid, + scoreboard_if[i].data.wis, + scoreboard_if[i].data.tmask, + scoreboard_if[i].data.PC, + scoreboard_if[i].data.wb, + scoreboard_if[i].data.ex_type, + scoreboard_if[i].data.op_type, + scoreboard_if[i].data.op_mod, + scoreboard_if[i].data.use_PC, + scoreboard_if[i].data.use_imm, + scoreboard_if[i].data.imm, + scoreboard_if[i].data.rd}; + end + + gpr_rd_rid <= gpr_rd_rid_n; + gpr_rd_wis <= gpr_rd_wis_n; + rs2_ready <= rs2_ready_n; + rs3_ready <= rs3_ready_n; + rs2 <= rs2_n; + rs3 <= rs3_n; + rs1_data <= rs1_data_n; + rs2_data <= rs2_data_n; + rs3_data <= rs3_data_n; + cache_data <= cache_data_n; + cache_reg <= cache_reg_n; + cache_tmask <= cache_tmask_n; + end + + assign operands_if[i].valid = valid_out_r; + assign {operands_if[i].data.uuid, + operands_if[i].data.wis, + operands_if[i].data.tmask, + operands_if[i].data.PC, + operands_if[i].data.wb, + operands_if[i].data.ex_type, + operands_if[i].data.op_type, + operands_if[i].data.op_mod, + operands_if[i].data.use_PC, + operands_if[i].data.use_imm, + operands_if[i].data.imm, + operands_if[i].data.rd} = data_out_r; + assign operands_if[i].data.rs1_data = rs1_data; + assign operands_if[i].data.rs2_data = rs2_data; + assign operands_if[i].data.rs3_data = rs3_data; + + assign scoreboard_if[i].ready = ~valid_out_r && data_ready; // GPR banks + reg [RAM_ADDRW-1:0] gpr_rd_addr; + wire [RAM_ADDRW-1:0] gpr_wr_addr; + if (ISSUE_WIS != 0) begin + assign gpr_wr_addr = {writeback_if[i].data.wis, writeback_if[i].data.rd}; + always @(posedge clk) begin + gpr_rd_addr <= {gpr_rd_wis_n, gpr_rd_rid_n}; + end + end else begin + assign gpr_wr_addr = writeback_if[i].data.rd; + always @(posedge clk) begin + gpr_rd_addr <= gpr_rd_rid_n; + end + end + `ifdef GPR_RESET reg wr_enabled = 0; always @(posedge clk) begin @@ -204,10 +260,8 @@ module VX_operands import VX_gpu_pkg::*; #( wr_enabled <= 1; end end - `else - wire wr_enabled = 1; `endif - + for (genvar j = 0; j < `NUM_THREADS; ++j) begin VX_dp_ram #( .DATAW (`XLEN), @@ -221,81 +275,17 @@ module VX_operands import VX_gpu_pkg::*; #( .clk (clk), .read (1'b1), `UNUSED_PIN (wren), - .write (wr_enabled && writeback_if[i].valid && writeback_if[i].data.tmask[j]), - .waddr (wis_to_addr(writeback_if[i].data.rd, writeback_if[i].data.wis)), + `ifdef GPR_RESET + .write (wr_enabled && writeback_if[i].valid && writeback_if[i].data.tmask[j]), + `else + .write (writeback_if[i].valid && writeback_if[i].data.tmask[j]), + `endif + .waddr (gpr_wr_addr), .wdata (writeback_if[i].data.data[j]), - .raddr (wis_to_addr(gpr_rd_rid, gpr_rd_wis)), + .raddr (gpr_rd_addr), .rdata (gpr_rd_data[j]) ); end - - // staging buffer - - `RESET_RELAY (stg_buf_reset, reset); - - VX_elastic_buffer #( - .DATAW (DATAW) - ) stg_buf ( - .clk (clk), - .reset (stg_buf_reset), - .valid_in (scoreboard_if[i].valid), - .ready_in (scoreboard_if[i].ready), - .data_in ({ - scoreboard_if[i].data.uuid, - scoreboard_if[i].data.wis, - scoreboard_if[i].data.tmask, - scoreboard_if[i].data.PC, - scoreboard_if[i].data.wb, - scoreboard_if[i].data.ex_type, - scoreboard_if[i].data.op_type, - scoreboard_if[i].data.op_mod, - scoreboard_if[i].data.use_PC, - scoreboard_if[i].data.use_imm, - scoreboard_if[i].data.imm, - scoreboard_if[i].data.rd}), - .data_out ({ - staging_if.data.uuid, - staging_if.data.wis, - staging_if.data.tmask, - staging_if.data.PC, - staging_if.data.wb, - staging_if.data.ex_type, - staging_if.data.op_type, - staging_if.data.op_mod, - staging_if.data.use_PC, - staging_if.data.use_imm, - staging_if.data.imm, - staging_if.data.rd}), - .valid_out (staging_if.valid), - .ready_out (staging_if.ready) - ); - - assign staging_if.data.rs1_data = rs1_data; - assign staging_if.data.rs2_data = rs2_data; - assign staging_if.data.rs3_data = rs3_data; - - // output buffer - - wire valid_stg, ready_stg; - assign valid_stg = staging_if.valid && data_ready; - assign staging_if.ready = ready_stg && data_ready; - - `RESET_RELAY (out_buf_reset, reset); - - VX_elastic_buffer #( - .DATAW (DATAW + (3 * `NUM_THREADS * `XLEN)), - .SIZE (2), - .OUT_REG (2) - ) out_buf ( - .clk (clk), - .reset (out_buf_reset), - .valid_in (valid_stg), - .ready_in (ready_stg), - .data_in (staging_if.data), - .data_out (operands_if[i].data), - .valid_out (operands_if[i].valid), - .ready_out (operands_if[i].ready) - ); - end + end endmodule diff --git a/hw/rtl/core/VX_scoreboard.sv b/hw/rtl/core/VX_scoreboard.sv index 2206df25..1c5f3676 100644 --- a/hw/rtl/core/VX_scoreboard.sv +++ b/hw/rtl/core/VX_scoreboard.sv @@ -51,7 +51,6 @@ module VX_scoreboard import VX_gpu_pkg::*; #( for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin reg [`UP(ISSUE_RATIO)-1:0][`NUM_REGS-1:0] inuse_regs; - VX_ibuffer_if staging_if(); wire writeback_fire = writeback_if[i].valid && writeback_if[i].data.eop; @@ -84,10 +83,17 @@ module VX_scoreboard import VX_gpu_pkg::*; #( reg [DATAW-1:0] data_out_r; reg valid_out_r; + wire ready_out; wire [3:0] ready_masks = ~{inuse_rd, inuse_rs1, inuse_rs2, inuse_rs3}; wire deps_ready = (& ready_masks); + wire valid_in = ibuffer_if[i].valid && deps_ready; + wire ready_in = ~valid_out_r && deps_ready; + wire [DATAW-1:0] data_in = ibuffer_if[i].data; + + assign ready_out = scoreboard_if[i].ready; + always @(posedge clk) begin if (reset) begin valid_out_r <= 0; @@ -97,40 +103,25 @@ module VX_scoreboard import VX_gpu_pkg::*; #( inuse_regs[writeback_if[i].data.wis][writeback_if[i].data.rd] <= 0; end if (~valid_out_r) begin - valid_out_r <= ibuffer_if[i].valid && deps_ready; - end else if (staging_if.ready) begin - if (staging_if.data.wb) begin - inuse_regs[staging_if.data.wis][staging_if.data.rd] <= 1; + valid_out_r <= valid_in; + end else if (ready_out) begin + if (scoreboard_if[i].data.wb) begin + inuse_regs[scoreboard_if[i].data.wis][scoreboard_if[i].data.rd] <= 1; `ifdef PERF_ENABLE - inuse_units[staging_if.data.wis][staging_if.data.rd] <= staging_if.data.ex_type; + inuse_units[scoreboard_if[i].data.wis][scoreboard_if[i].data.rd] <= scoreboard_if[i].data.ex_type; `endif end valid_out_r <= 0; end end if (~valid_out_r) begin - data_out_r <= ibuffer_if[i].data; + data_out_r <= data_in; end end - assign ibuffer_if[i].ready = ~valid_out_r && deps_ready; - assign staging_if.valid = valid_out_r; - assign staging_if.data = data_out_r; - - VX_elastic_buffer #( - .DATAW (DATAW), - .SIZE (0), - .OUT_REG (2) - ) out_buf ( - .clk (clk), - .reset (reset), - .valid_in (staging_if.valid), - .ready_in (staging_if.ready), - .data_in (staging_if.data), - .data_out (scoreboard_if[i].data), - .valid_out (scoreboard_if[i].valid), - .ready_out (scoreboard_if[i].ready) - ); + assign ibuffer_if[i].ready = ready_in; + assign scoreboard_if[i].valid = valid_out_r; + assign scoreboard_if[i].data = data_out_r; `ifdef SIMULATION reg [31:0] timeout_ctr; From 39e6f95c2b26738a6a60b76ca2b6c5e3fa45bff6 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Fri, 15 Dec 2023 14:09:51 -0800 Subject: [PATCH 30/57] operands optimization minor updates minor updates minor update --- hw/rtl/VX_gpu_pkg.sv | 50 +++++---- hw/rtl/core/VX_dispatch_unit.sv | 10 +- hw/rtl/core/VX_gather_unit.sv | 14 +-- hw/rtl/core/VX_lsu_unit.sv | 2 +- hw/rtl/core/VX_operands.sv | 184 +++++++++++++++----------------- hw/rtl/core/VX_scoreboard.sv | 41 +++---- 6 files changed, 143 insertions(+), 158 deletions(-) diff --git a/hw/rtl/VX_gpu_pkg.sv b/hw/rtl/VX_gpu_pkg.sv index 4ece6c9c..668b53ee 100644 --- a/hw/rtl/VX_gpu_pkg.sv +++ b/hw/rtl/VX_gpu_pkg.sv @@ -190,42 +190,46 @@ package VX_gpu_pkg; /////////////////////////////// Issue parameters ////////////////////////// - localparam ISSUE_IDX_W = `LOG2UP(`ISSUE_WIDTH); + localparam ISSUE_ISW = `CLOG2(`ISSUE_WIDTH); + localparam ISSUE_ISW_W = `UP(ISSUE_ISW); localparam ISSUE_RATIO = `NUM_WARPS / `ISSUE_WIDTH; - localparam ISSUE_WIS_W = `LOG2UP(ISSUE_RATIO); - localparam ISSUE_ADDRW = `LOG2UP(`NUM_REGS * (ISSUE_RATIO)); - + localparam ISSUE_WIS = `CLOG2(ISSUE_RATIO); + localparam ISSUE_WIS_W = `UP(ISSUE_WIS); + `IGNORE_UNUSED_BEGIN - function logic [ISSUE_IDX_W-1:0] wid_to_isw( + function logic [`NW_WIDTH-1:0] wis_to_wid( + input logic [ISSUE_WIS_W-1:0] wis, + input logic [ISSUE_ISW_W-1:0] isw + ); + if (ISSUE_WIS == 0) begin + wis_to_wid = `NW_WIDTH'(isw); + end else if (ISSUE_ISW == 0) begin + wis_to_wid = `NW_WIDTH'(wis); + end else begin + wis_to_wid = `NW_WIDTH'({wis, isw}); + end + endfunction + + function logic [ISSUE_ISW_W-1:0] wid_to_isw( input logic [`NW_WIDTH-1:0] wid ); - if (`ISSUE_WIDTH > 1) begin - wid_to_isw = ISSUE_IDX_W'(wid); + if (ISSUE_ISW != 0) begin + wid_to_isw = wid[ISSUE_ISW_W-1:0]; end else begin wid_to_isw = 0; end endfunction -`IGNORE_UNUSED_END - - function logic [`NW_WIDTH-1:0] wis_to_wid( - input logic [ISSUE_WIS_W-1:0] wis, - input logic [ISSUE_IDX_W-1:0] isw - ); - wis_to_wid = `NW_WIDTH'({wis, isw} >> (ISSUE_IDX_W-`CLOG2(`ISSUE_WIDTH))); - endfunction function logic [ISSUE_WIS_W-1:0] wid_to_wis( input logic [`NW_WIDTH-1:0] wid ); - wid_to_wis = ISSUE_WIS_W'({1'b0, wid} >> `CLOG2(`ISSUE_WIDTH)); - endfunction - - function logic [ISSUE_ADDRW-1:0] wis_to_addr( - input logic [`NR_BITS-1:0] rid, - input logic [ISSUE_WIS_W-1:0] wis - ); - wis_to_addr = ISSUE_ADDRW'({rid, wis} >> (ISSUE_WIS_W-`CLOG2(ISSUE_RATIO))); + if (ISSUE_WIS != 0) begin + wid_to_wis = ISSUE_WIS_W'(wid >> ISSUE_ISW); + end else begin + wid_to_wis = 0; + end endfunction +`IGNORE_UNUSED_END endpackage diff --git a/hw/rtl/core/VX_dispatch_unit.sv b/hw/rtl/core/VX_dispatch_unit.sv index 586acc0b..6e36a33b 100644 --- a/hw/rtl/core/VX_dispatch_unit.sv +++ b/hw/rtl/core/VX_dispatch_unit.sv @@ -203,20 +203,20 @@ module VX_dispatch_unit import VX_gpu_pkg::*; #( assign block_done[block_idx] = ~valid_p || ready_p; end - wire [ISSUE_IDX_W-1:0] wsi; + wire [ISSUE_ISW_W-1:0] isw; if (BATCH_COUNT != 1) begin if (BLOCK_SIZE != 1) begin - assign wsi = {batch_idx, BLOCK_SIZE_W'(block_idx)}; + assign isw = {batch_idx, BLOCK_SIZE_W'(block_idx)}; end else begin - assign wsi = batch_idx; + assign isw = batch_idx; end end else begin - assign wsi = block_idx; + assign isw = block_idx; end `RESET_RELAY(buf_out_reset, reset); - wire [`NW_WIDTH-1:0] block_wid = wis_to_wid(dispatch_data[issue_idx][DATA_TMASK_OFF+`NUM_THREADS +: ISSUE_WIS_W], wsi); + wire [`NW_WIDTH-1:0] block_wid = wis_to_wid(dispatch_data[issue_idx][DATA_TMASK_OFF+`NUM_THREADS +: ISSUE_WIS_W], isw); VX_elastic_buffer #( .DATAW (OUT_DATAW), diff --git a/hw/rtl/core/VX_gather_unit.sv b/hw/rtl/core/VX_gather_unit.sv index e3dc935d..21ae4485 100644 --- a/hw/rtl/core/VX_gather_unit.sv +++ b/hw/rtl/core/VX_gather_unit.sv @@ -37,7 +37,7 @@ module VX_gather_unit import VX_gpu_pkg::*; #( wire [BLOCK_SIZE-1:0] commit_in_valid; wire [BLOCK_SIZE-1:0][DATAW-1:0] commit_in_data; wire [BLOCK_SIZE-1:0] commit_in_ready; - wire [BLOCK_SIZE-1:0][ISSUE_IDX_W-1:0] commit_in_wsi; + wire [BLOCK_SIZE-1:0][ISSUE_ISW_W-1:0] commit_in_isw; for (genvar i = 0; i < BLOCK_SIZE; ++i) begin assign commit_in_valid[i] = commit_in_if[i].valid; @@ -45,12 +45,12 @@ module VX_gather_unit import VX_gpu_pkg::*; #( assign commit_in_if[i].ready = commit_in_ready[i]; if (BLOCK_SIZE != `ISSUE_WIDTH) begin if (BLOCK_SIZE != 1) begin - assign commit_in_wsi[i] = {commit_in_data[i][DATA_WIS_OFF+BLOCK_SIZE_W +: (ISSUE_IDX_W-BLOCK_SIZE_W)], BLOCK_SIZE_W'(i)}; + assign commit_in_isw[i] = {commit_in_data[i][DATA_WIS_OFF+BLOCK_SIZE_W +: (ISSUE_ISW_W-BLOCK_SIZE_W)], BLOCK_SIZE_W'(i)}; end else begin - assign commit_in_wsi[i] = commit_in_data[i][DATA_WIS_OFF +: ISSUE_IDX_W]; + assign commit_in_isw[i] = commit_in_data[i][DATA_WIS_OFF +: ISSUE_ISW_W]; end end else begin - assign commit_in_wsi[i] = BLOCK_SIZE_W'(i); + assign commit_in_isw[i] = BLOCK_SIZE_W'(i); end end @@ -64,12 +64,12 @@ module VX_gather_unit import VX_gpu_pkg::*; #( commit_out_data[i] = 'x; end for (integer i = 0; i < BLOCK_SIZE; ++i) begin - commit_out_valid[commit_in_wsi[i]] = commit_in_valid[i]; - commit_out_data[commit_in_wsi[i]] = commit_in_data[i]; + commit_out_valid[commit_in_isw[i]] = commit_in_valid[i]; + commit_out_data[commit_in_isw[i]] = commit_in_data[i]; end end for (genvar i = 0; i < BLOCK_SIZE; ++i) begin - assign commit_in_ready[i] = commit_out_ready[commit_in_wsi[i]]; + assign commit_in_ready[i] = commit_out_ready[commit_in_isw[i]]; end for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin diff --git a/hw/rtl/core/VX_lsu_unit.sv b/hw/rtl/core/VX_lsu_unit.sv index 3383f70f..1e0a09b8 100644 --- a/hw/rtl/core/VX_lsu_unit.sv +++ b/hw/rtl/core/VX_lsu_unit.sv @@ -554,7 +554,7 @@ module VX_lsu_unit import VX_gpu_pkg::*; #( VX_stream_arb #( .NUM_INPUTS (2), .DATAW (RSP_ARB_DATAW), - .OUT_REG (2) + .OUT_REG (3) ) rsp_arb ( .clk (clk), .reset (commit_reset), diff --git a/hw/rtl/core/VX_operands.sv b/hw/rtl/core/VX_operands.sv index 3ff5df46..ee0c493b 100644 --- a/hw/rtl/core/VX_operands.sv +++ b/hw/rtl/core/VX_operands.sv @@ -26,6 +26,7 @@ module VX_operands import VX_gpu_pkg::*; #( ); `UNUSED_PARAM (CORE_ID) localparam DATAW = `UUID_WIDTH + ISSUE_WIS_W + `NUM_THREADS + `XLEN + 1 + `EX_BITS + `INST_OP_BITS + `INST_MOD_BITS + 1 + 1 + `XLEN + `NR_BITS; + localparam RAM_ADDRW = `LOG2UP(`NUM_REGS * ISSUE_RATIO); localparam STATE_IDLE = 2'd0; localparam STATE_FETCH1 = 2'd1; @@ -46,9 +47,11 @@ module VX_operands import VX_gpu_pkg::*; #( reg [`NUM_THREADS-1:0] cache_tmask_n [ISSUE_RATIO-1:0]; reg [ISSUE_RATIO-1:0] cache_eop, cache_eop_n; + reg valid_out_r; + reg [DATAW-1:0] data_out_r; reg [`NUM_THREADS-1:0][`XLEN-1:0] rs1_data, rs1_data_n; reg [`NUM_THREADS-1:0][`XLEN-1:0] rs2_data, rs2_data_n; - reg [`NUM_THREADS-1:0][`XLEN-1:0] rs3_data, rs3_data_n; + reg [`NUM_THREADS-1:0][`XLEN-1:0] rs3_data, rs3_data_n; reg [STATE_BITS-1:0] state, state_n; reg [`NR_BITS-1:0] rs2, rs2_n; @@ -57,11 +60,11 @@ module VX_operands import VX_gpu_pkg::*; #( reg rs3_ready, rs3_ready_n; reg data_ready, data_ready_n; + wire ready_out = operands_if[i].ready; + wire is_rs1_zero = (scoreboard_if[i].data.rs1 == 0); wire is_rs2_zero = (scoreboard_if[i].data.rs2 == 0); - wire is_rs3_zero = (scoreboard_if[i].data.rs3 == 0); - - VX_operands_if staging_if(); + wire is_rs3_zero = (scoreboard_if[i].data.rs3 == 0); always @(*) begin state_n = state; @@ -82,7 +85,7 @@ module VX_operands import VX_gpu_pkg::*; #( case (state) STATE_IDLE: begin - if (staging_if.valid && staging_if.ready) begin + if (valid_out_r && ready_out) begin data_ready_n = 0; end if (scoreboard_if[i].valid && data_ready_n == 0) begin @@ -170,33 +173,86 @@ module VX_operands import VX_gpu_pkg::*; #( end always @(posedge clk) begin - if (reset) begin + if (reset) begin state <= STATE_IDLE; - gpr_rd_rid <= '0; - gpr_rd_wis <= '0; cache_eop <= {ISSUE_RATIO{1'b1}}; data_ready <= 0; + valid_out_r <= 0; end else begin state <= state_n; - rs2 <= rs2_n; - rs3 <= rs3_n; - rs2_ready <= rs2_ready_n; - rs3_ready <= rs3_ready_n; - rs1_data <= rs1_data_n; - rs2_data <= rs2_data_n; - rs3_data <= rs3_data_n; - gpr_rd_rid <= gpr_rd_rid_n; - gpr_rd_wis <= gpr_rd_wis_n; - cache_data <= cache_data_n; - cache_reg <= cache_reg_n; - cache_tmask <= cache_tmask_n; cache_eop <= cache_eop_n; - data_ready <= data_ready_n; + data_ready <= data_ready_n; + if (~valid_out_r) begin + valid_out_r <= scoreboard_if[i].valid && data_ready; + end else if (ready_out) begin + valid_out_r <= 0; + end end - end + + if (~valid_out_r) begin + data_out_r <= {scoreboard_if[i].data.uuid, + scoreboard_if[i].data.wis, + scoreboard_if[i].data.tmask, + scoreboard_if[i].data.PC, + scoreboard_if[i].data.wb, + scoreboard_if[i].data.ex_type, + scoreboard_if[i].data.op_type, + scoreboard_if[i].data.op_mod, + scoreboard_if[i].data.use_PC, + scoreboard_if[i].data.use_imm, + scoreboard_if[i].data.imm, + scoreboard_if[i].data.rd}; + end + + gpr_rd_rid <= gpr_rd_rid_n; + gpr_rd_wis <= gpr_rd_wis_n; + rs2_ready <= rs2_ready_n; + rs3_ready <= rs3_ready_n; + rs2 <= rs2_n; + rs3 <= rs3_n; + rs1_data <= rs1_data_n; + rs2_data <= rs2_data_n; + rs3_data <= rs3_data_n; + cache_data <= cache_data_n; + cache_reg <= cache_reg_n; + cache_tmask <= cache_tmask_n; + end + + assign operands_if[i].valid = valid_out_r; + assign {operands_if[i].data.uuid, + operands_if[i].data.wis, + operands_if[i].data.tmask, + operands_if[i].data.PC, + operands_if[i].data.wb, + operands_if[i].data.ex_type, + operands_if[i].data.op_type, + operands_if[i].data.op_mod, + operands_if[i].data.use_PC, + operands_if[i].data.use_imm, + operands_if[i].data.imm, + operands_if[i].data.rd} = data_out_r; + assign operands_if[i].data.rs1_data = rs1_data; + assign operands_if[i].data.rs2_data = rs2_data; + assign operands_if[i].data.rs3_data = rs3_data; + + assign scoreboard_if[i].ready = ~valid_out_r && data_ready; // GPR banks + reg [RAM_ADDRW-1:0] gpr_rd_addr; + wire [RAM_ADDRW-1:0] gpr_wr_addr; + if (ISSUE_WIS != 0) begin + assign gpr_wr_addr = {writeback_if[i].data.wis, writeback_if[i].data.rd}; + always @(posedge clk) begin + gpr_rd_addr <= {gpr_rd_wis_n, gpr_rd_rid_n}; + end + end else begin + assign gpr_wr_addr = writeback_if[i].data.rd; + always @(posedge clk) begin + gpr_rd_addr <= gpr_rd_rid_n; + end + end + `ifdef GPR_RESET reg wr_enabled = 0; always @(posedge clk) begin @@ -204,10 +260,8 @@ module VX_operands import VX_gpu_pkg::*; #( wr_enabled <= 1; end end - `else - wire wr_enabled = 1; `endif - + for (genvar j = 0; j < `NUM_THREADS; ++j) begin VX_dp_ram #( .DATAW (`XLEN), @@ -221,81 +275,17 @@ module VX_operands import VX_gpu_pkg::*; #( .clk (clk), .read (1'b1), `UNUSED_PIN (wren), - .write (wr_enabled && writeback_if[i].valid && writeback_if[i].data.tmask[j]), - .waddr (wis_to_addr(writeback_if[i].data.rd, writeback_if[i].data.wis)), + `ifdef GPR_RESET + .write (wr_enabled && writeback_if[i].valid && writeback_if[i].data.tmask[j]), + `else + .write (writeback_if[i].valid && writeback_if[i].data.tmask[j]), + `endif + .waddr (gpr_wr_addr), .wdata (writeback_if[i].data.data[j]), - .raddr (wis_to_addr(gpr_rd_rid, gpr_rd_wis)), + .raddr (gpr_rd_addr), .rdata (gpr_rd_data[j]) ); end - - // staging buffer - - `RESET_RELAY (stg_buf_reset, reset); - - VX_elastic_buffer #( - .DATAW (DATAW) - ) stg_buf ( - .clk (clk), - .reset (stg_buf_reset), - .valid_in (scoreboard_if[i].valid), - .ready_in (scoreboard_if[i].ready), - .data_in ({ - scoreboard_if[i].data.uuid, - scoreboard_if[i].data.wis, - scoreboard_if[i].data.tmask, - scoreboard_if[i].data.PC, - scoreboard_if[i].data.wb, - scoreboard_if[i].data.ex_type, - scoreboard_if[i].data.op_type, - scoreboard_if[i].data.op_mod, - scoreboard_if[i].data.use_PC, - scoreboard_if[i].data.use_imm, - scoreboard_if[i].data.imm, - scoreboard_if[i].data.rd}), - .data_out ({ - staging_if.data.uuid, - staging_if.data.wis, - staging_if.data.tmask, - staging_if.data.PC, - staging_if.data.wb, - staging_if.data.ex_type, - staging_if.data.op_type, - staging_if.data.op_mod, - staging_if.data.use_PC, - staging_if.data.use_imm, - staging_if.data.imm, - staging_if.data.rd}), - .valid_out (staging_if.valid), - .ready_out (staging_if.ready) - ); - - assign staging_if.data.rs1_data = rs1_data; - assign staging_if.data.rs2_data = rs2_data; - assign staging_if.data.rs3_data = rs3_data; - - // output buffer - - wire valid_stg, ready_stg; - assign valid_stg = staging_if.valid && data_ready; - assign staging_if.ready = ready_stg && data_ready; - - `RESET_RELAY (out_buf_reset, reset); - - VX_elastic_buffer #( - .DATAW (DATAW + (3 * `NUM_THREADS * `XLEN)), - .SIZE (2), - .OUT_REG (2) - ) out_buf ( - .clk (clk), - .reset (out_buf_reset), - .valid_in (valid_stg), - .ready_in (ready_stg), - .data_in (staging_if.data), - .data_out (operands_if[i].data), - .valid_out (operands_if[i].valid), - .ready_out (operands_if[i].ready) - ); - end + end endmodule diff --git a/hw/rtl/core/VX_scoreboard.sv b/hw/rtl/core/VX_scoreboard.sv index 2206df25..1c5f3676 100644 --- a/hw/rtl/core/VX_scoreboard.sv +++ b/hw/rtl/core/VX_scoreboard.sv @@ -51,7 +51,6 @@ module VX_scoreboard import VX_gpu_pkg::*; #( for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin reg [`UP(ISSUE_RATIO)-1:0][`NUM_REGS-1:0] inuse_regs; - VX_ibuffer_if staging_if(); wire writeback_fire = writeback_if[i].valid && writeback_if[i].data.eop; @@ -84,10 +83,17 @@ module VX_scoreboard import VX_gpu_pkg::*; #( reg [DATAW-1:0] data_out_r; reg valid_out_r; + wire ready_out; wire [3:0] ready_masks = ~{inuse_rd, inuse_rs1, inuse_rs2, inuse_rs3}; wire deps_ready = (& ready_masks); + wire valid_in = ibuffer_if[i].valid && deps_ready; + wire ready_in = ~valid_out_r && deps_ready; + wire [DATAW-1:0] data_in = ibuffer_if[i].data; + + assign ready_out = scoreboard_if[i].ready; + always @(posedge clk) begin if (reset) begin valid_out_r <= 0; @@ -97,40 +103,25 @@ module VX_scoreboard import VX_gpu_pkg::*; #( inuse_regs[writeback_if[i].data.wis][writeback_if[i].data.rd] <= 0; end if (~valid_out_r) begin - valid_out_r <= ibuffer_if[i].valid && deps_ready; - end else if (staging_if.ready) begin - if (staging_if.data.wb) begin - inuse_regs[staging_if.data.wis][staging_if.data.rd] <= 1; + valid_out_r <= valid_in; + end else if (ready_out) begin + if (scoreboard_if[i].data.wb) begin + inuse_regs[scoreboard_if[i].data.wis][scoreboard_if[i].data.rd] <= 1; `ifdef PERF_ENABLE - inuse_units[staging_if.data.wis][staging_if.data.rd] <= staging_if.data.ex_type; + inuse_units[scoreboard_if[i].data.wis][scoreboard_if[i].data.rd] <= scoreboard_if[i].data.ex_type; `endif end valid_out_r <= 0; end end if (~valid_out_r) begin - data_out_r <= ibuffer_if[i].data; + data_out_r <= data_in; end end - assign ibuffer_if[i].ready = ~valid_out_r && deps_ready; - assign staging_if.valid = valid_out_r; - assign staging_if.data = data_out_r; - - VX_elastic_buffer #( - .DATAW (DATAW), - .SIZE (0), - .OUT_REG (2) - ) out_buf ( - .clk (clk), - .reset (reset), - .valid_in (staging_if.valid), - .ready_in (staging_if.ready), - .data_in (staging_if.data), - .data_out (scoreboard_if[i].data), - .valid_out (scoreboard_if[i].valid), - .ready_out (scoreboard_if[i].ready) - ); + assign ibuffer_if[i].ready = ready_in; + assign scoreboard_if[i].valid = valid_out_r; + assign scoreboard_if[i].data = data_out_r; `ifdef SIMULATION reg [31:0] timeout_ctr; From 914b680aedafa47154d4cbd796077f00f1b3ea0c Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Fri, 15 Dec 2023 14:09:51 -0800 Subject: [PATCH 31/57] operands optimization minor updates minor updates minor update operands optimization minor updates minor updates --- hw/rtl/VX_gpu_pkg.sv | 50 +++++---- hw/rtl/core/VX_dispatch_unit.sv | 10 +- hw/rtl/core/VX_gather_unit.sv | 14 +-- hw/rtl/core/VX_lsu_unit.sv | 2 +- hw/rtl/core/VX_operands.sv | 184 +++++++++++++++----------------- hw/rtl/core/VX_scoreboard.sv | 41 +++---- 6 files changed, 143 insertions(+), 158 deletions(-) diff --git a/hw/rtl/VX_gpu_pkg.sv b/hw/rtl/VX_gpu_pkg.sv index 4ece6c9c..668b53ee 100644 --- a/hw/rtl/VX_gpu_pkg.sv +++ b/hw/rtl/VX_gpu_pkg.sv @@ -190,42 +190,46 @@ package VX_gpu_pkg; /////////////////////////////// Issue parameters ////////////////////////// - localparam ISSUE_IDX_W = `LOG2UP(`ISSUE_WIDTH); + localparam ISSUE_ISW = `CLOG2(`ISSUE_WIDTH); + localparam ISSUE_ISW_W = `UP(ISSUE_ISW); localparam ISSUE_RATIO = `NUM_WARPS / `ISSUE_WIDTH; - localparam ISSUE_WIS_W = `LOG2UP(ISSUE_RATIO); - localparam ISSUE_ADDRW = `LOG2UP(`NUM_REGS * (ISSUE_RATIO)); - + localparam ISSUE_WIS = `CLOG2(ISSUE_RATIO); + localparam ISSUE_WIS_W = `UP(ISSUE_WIS); + `IGNORE_UNUSED_BEGIN - function logic [ISSUE_IDX_W-1:0] wid_to_isw( + function logic [`NW_WIDTH-1:0] wis_to_wid( + input logic [ISSUE_WIS_W-1:0] wis, + input logic [ISSUE_ISW_W-1:0] isw + ); + if (ISSUE_WIS == 0) begin + wis_to_wid = `NW_WIDTH'(isw); + end else if (ISSUE_ISW == 0) begin + wis_to_wid = `NW_WIDTH'(wis); + end else begin + wis_to_wid = `NW_WIDTH'({wis, isw}); + end + endfunction + + function logic [ISSUE_ISW_W-1:0] wid_to_isw( input logic [`NW_WIDTH-1:0] wid ); - if (`ISSUE_WIDTH > 1) begin - wid_to_isw = ISSUE_IDX_W'(wid); + if (ISSUE_ISW != 0) begin + wid_to_isw = wid[ISSUE_ISW_W-1:0]; end else begin wid_to_isw = 0; end endfunction -`IGNORE_UNUSED_END - - function logic [`NW_WIDTH-1:0] wis_to_wid( - input logic [ISSUE_WIS_W-1:0] wis, - input logic [ISSUE_IDX_W-1:0] isw - ); - wis_to_wid = `NW_WIDTH'({wis, isw} >> (ISSUE_IDX_W-`CLOG2(`ISSUE_WIDTH))); - endfunction function logic [ISSUE_WIS_W-1:0] wid_to_wis( input logic [`NW_WIDTH-1:0] wid ); - wid_to_wis = ISSUE_WIS_W'({1'b0, wid} >> `CLOG2(`ISSUE_WIDTH)); - endfunction - - function logic [ISSUE_ADDRW-1:0] wis_to_addr( - input logic [`NR_BITS-1:0] rid, - input logic [ISSUE_WIS_W-1:0] wis - ); - wis_to_addr = ISSUE_ADDRW'({rid, wis} >> (ISSUE_WIS_W-`CLOG2(ISSUE_RATIO))); + if (ISSUE_WIS != 0) begin + wid_to_wis = ISSUE_WIS_W'(wid >> ISSUE_ISW); + end else begin + wid_to_wis = 0; + end endfunction +`IGNORE_UNUSED_END endpackage diff --git a/hw/rtl/core/VX_dispatch_unit.sv b/hw/rtl/core/VX_dispatch_unit.sv index 586acc0b..6e36a33b 100644 --- a/hw/rtl/core/VX_dispatch_unit.sv +++ b/hw/rtl/core/VX_dispatch_unit.sv @@ -203,20 +203,20 @@ module VX_dispatch_unit import VX_gpu_pkg::*; #( assign block_done[block_idx] = ~valid_p || ready_p; end - wire [ISSUE_IDX_W-1:0] wsi; + wire [ISSUE_ISW_W-1:0] isw; if (BATCH_COUNT != 1) begin if (BLOCK_SIZE != 1) begin - assign wsi = {batch_idx, BLOCK_SIZE_W'(block_idx)}; + assign isw = {batch_idx, BLOCK_SIZE_W'(block_idx)}; end else begin - assign wsi = batch_idx; + assign isw = batch_idx; end end else begin - assign wsi = block_idx; + assign isw = block_idx; end `RESET_RELAY(buf_out_reset, reset); - wire [`NW_WIDTH-1:0] block_wid = wis_to_wid(dispatch_data[issue_idx][DATA_TMASK_OFF+`NUM_THREADS +: ISSUE_WIS_W], wsi); + wire [`NW_WIDTH-1:0] block_wid = wis_to_wid(dispatch_data[issue_idx][DATA_TMASK_OFF+`NUM_THREADS +: ISSUE_WIS_W], isw); VX_elastic_buffer #( .DATAW (OUT_DATAW), diff --git a/hw/rtl/core/VX_gather_unit.sv b/hw/rtl/core/VX_gather_unit.sv index e3dc935d..21ae4485 100644 --- a/hw/rtl/core/VX_gather_unit.sv +++ b/hw/rtl/core/VX_gather_unit.sv @@ -37,7 +37,7 @@ module VX_gather_unit import VX_gpu_pkg::*; #( wire [BLOCK_SIZE-1:0] commit_in_valid; wire [BLOCK_SIZE-1:0][DATAW-1:0] commit_in_data; wire [BLOCK_SIZE-1:0] commit_in_ready; - wire [BLOCK_SIZE-1:0][ISSUE_IDX_W-1:0] commit_in_wsi; + wire [BLOCK_SIZE-1:0][ISSUE_ISW_W-1:0] commit_in_isw; for (genvar i = 0; i < BLOCK_SIZE; ++i) begin assign commit_in_valid[i] = commit_in_if[i].valid; @@ -45,12 +45,12 @@ module VX_gather_unit import VX_gpu_pkg::*; #( assign commit_in_if[i].ready = commit_in_ready[i]; if (BLOCK_SIZE != `ISSUE_WIDTH) begin if (BLOCK_SIZE != 1) begin - assign commit_in_wsi[i] = {commit_in_data[i][DATA_WIS_OFF+BLOCK_SIZE_W +: (ISSUE_IDX_W-BLOCK_SIZE_W)], BLOCK_SIZE_W'(i)}; + assign commit_in_isw[i] = {commit_in_data[i][DATA_WIS_OFF+BLOCK_SIZE_W +: (ISSUE_ISW_W-BLOCK_SIZE_W)], BLOCK_SIZE_W'(i)}; end else begin - assign commit_in_wsi[i] = commit_in_data[i][DATA_WIS_OFF +: ISSUE_IDX_W]; + assign commit_in_isw[i] = commit_in_data[i][DATA_WIS_OFF +: ISSUE_ISW_W]; end end else begin - assign commit_in_wsi[i] = BLOCK_SIZE_W'(i); + assign commit_in_isw[i] = BLOCK_SIZE_W'(i); end end @@ -64,12 +64,12 @@ module VX_gather_unit import VX_gpu_pkg::*; #( commit_out_data[i] = 'x; end for (integer i = 0; i < BLOCK_SIZE; ++i) begin - commit_out_valid[commit_in_wsi[i]] = commit_in_valid[i]; - commit_out_data[commit_in_wsi[i]] = commit_in_data[i]; + commit_out_valid[commit_in_isw[i]] = commit_in_valid[i]; + commit_out_data[commit_in_isw[i]] = commit_in_data[i]; end end for (genvar i = 0; i < BLOCK_SIZE; ++i) begin - assign commit_in_ready[i] = commit_out_ready[commit_in_wsi[i]]; + assign commit_in_ready[i] = commit_out_ready[commit_in_isw[i]]; end for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin diff --git a/hw/rtl/core/VX_lsu_unit.sv b/hw/rtl/core/VX_lsu_unit.sv index 3383f70f..1e0a09b8 100644 --- a/hw/rtl/core/VX_lsu_unit.sv +++ b/hw/rtl/core/VX_lsu_unit.sv @@ -554,7 +554,7 @@ module VX_lsu_unit import VX_gpu_pkg::*; #( VX_stream_arb #( .NUM_INPUTS (2), .DATAW (RSP_ARB_DATAW), - .OUT_REG (2) + .OUT_REG (3) ) rsp_arb ( .clk (clk), .reset (commit_reset), diff --git a/hw/rtl/core/VX_operands.sv b/hw/rtl/core/VX_operands.sv index 3ff5df46..ee0c493b 100644 --- a/hw/rtl/core/VX_operands.sv +++ b/hw/rtl/core/VX_operands.sv @@ -26,6 +26,7 @@ module VX_operands import VX_gpu_pkg::*; #( ); `UNUSED_PARAM (CORE_ID) localparam DATAW = `UUID_WIDTH + ISSUE_WIS_W + `NUM_THREADS + `XLEN + 1 + `EX_BITS + `INST_OP_BITS + `INST_MOD_BITS + 1 + 1 + `XLEN + `NR_BITS; + localparam RAM_ADDRW = `LOG2UP(`NUM_REGS * ISSUE_RATIO); localparam STATE_IDLE = 2'd0; localparam STATE_FETCH1 = 2'd1; @@ -46,9 +47,11 @@ module VX_operands import VX_gpu_pkg::*; #( reg [`NUM_THREADS-1:0] cache_tmask_n [ISSUE_RATIO-1:0]; reg [ISSUE_RATIO-1:0] cache_eop, cache_eop_n; + reg valid_out_r; + reg [DATAW-1:0] data_out_r; reg [`NUM_THREADS-1:0][`XLEN-1:0] rs1_data, rs1_data_n; reg [`NUM_THREADS-1:0][`XLEN-1:0] rs2_data, rs2_data_n; - reg [`NUM_THREADS-1:0][`XLEN-1:0] rs3_data, rs3_data_n; + reg [`NUM_THREADS-1:0][`XLEN-1:0] rs3_data, rs3_data_n; reg [STATE_BITS-1:0] state, state_n; reg [`NR_BITS-1:0] rs2, rs2_n; @@ -57,11 +60,11 @@ module VX_operands import VX_gpu_pkg::*; #( reg rs3_ready, rs3_ready_n; reg data_ready, data_ready_n; + wire ready_out = operands_if[i].ready; + wire is_rs1_zero = (scoreboard_if[i].data.rs1 == 0); wire is_rs2_zero = (scoreboard_if[i].data.rs2 == 0); - wire is_rs3_zero = (scoreboard_if[i].data.rs3 == 0); - - VX_operands_if staging_if(); + wire is_rs3_zero = (scoreboard_if[i].data.rs3 == 0); always @(*) begin state_n = state; @@ -82,7 +85,7 @@ module VX_operands import VX_gpu_pkg::*; #( case (state) STATE_IDLE: begin - if (staging_if.valid && staging_if.ready) begin + if (valid_out_r && ready_out) begin data_ready_n = 0; end if (scoreboard_if[i].valid && data_ready_n == 0) begin @@ -170,33 +173,86 @@ module VX_operands import VX_gpu_pkg::*; #( end always @(posedge clk) begin - if (reset) begin + if (reset) begin state <= STATE_IDLE; - gpr_rd_rid <= '0; - gpr_rd_wis <= '0; cache_eop <= {ISSUE_RATIO{1'b1}}; data_ready <= 0; + valid_out_r <= 0; end else begin state <= state_n; - rs2 <= rs2_n; - rs3 <= rs3_n; - rs2_ready <= rs2_ready_n; - rs3_ready <= rs3_ready_n; - rs1_data <= rs1_data_n; - rs2_data <= rs2_data_n; - rs3_data <= rs3_data_n; - gpr_rd_rid <= gpr_rd_rid_n; - gpr_rd_wis <= gpr_rd_wis_n; - cache_data <= cache_data_n; - cache_reg <= cache_reg_n; - cache_tmask <= cache_tmask_n; cache_eop <= cache_eop_n; - data_ready <= data_ready_n; + data_ready <= data_ready_n; + if (~valid_out_r) begin + valid_out_r <= scoreboard_if[i].valid && data_ready; + end else if (ready_out) begin + valid_out_r <= 0; + end end - end + + if (~valid_out_r) begin + data_out_r <= {scoreboard_if[i].data.uuid, + scoreboard_if[i].data.wis, + scoreboard_if[i].data.tmask, + scoreboard_if[i].data.PC, + scoreboard_if[i].data.wb, + scoreboard_if[i].data.ex_type, + scoreboard_if[i].data.op_type, + scoreboard_if[i].data.op_mod, + scoreboard_if[i].data.use_PC, + scoreboard_if[i].data.use_imm, + scoreboard_if[i].data.imm, + scoreboard_if[i].data.rd}; + end + + gpr_rd_rid <= gpr_rd_rid_n; + gpr_rd_wis <= gpr_rd_wis_n; + rs2_ready <= rs2_ready_n; + rs3_ready <= rs3_ready_n; + rs2 <= rs2_n; + rs3 <= rs3_n; + rs1_data <= rs1_data_n; + rs2_data <= rs2_data_n; + rs3_data <= rs3_data_n; + cache_data <= cache_data_n; + cache_reg <= cache_reg_n; + cache_tmask <= cache_tmask_n; + end + + assign operands_if[i].valid = valid_out_r; + assign {operands_if[i].data.uuid, + operands_if[i].data.wis, + operands_if[i].data.tmask, + operands_if[i].data.PC, + operands_if[i].data.wb, + operands_if[i].data.ex_type, + operands_if[i].data.op_type, + operands_if[i].data.op_mod, + operands_if[i].data.use_PC, + operands_if[i].data.use_imm, + operands_if[i].data.imm, + operands_if[i].data.rd} = data_out_r; + assign operands_if[i].data.rs1_data = rs1_data; + assign operands_if[i].data.rs2_data = rs2_data; + assign operands_if[i].data.rs3_data = rs3_data; + + assign scoreboard_if[i].ready = ~valid_out_r && data_ready; // GPR banks + reg [RAM_ADDRW-1:0] gpr_rd_addr; + wire [RAM_ADDRW-1:0] gpr_wr_addr; + if (ISSUE_WIS != 0) begin + assign gpr_wr_addr = {writeback_if[i].data.wis, writeback_if[i].data.rd}; + always @(posedge clk) begin + gpr_rd_addr <= {gpr_rd_wis_n, gpr_rd_rid_n}; + end + end else begin + assign gpr_wr_addr = writeback_if[i].data.rd; + always @(posedge clk) begin + gpr_rd_addr <= gpr_rd_rid_n; + end + end + `ifdef GPR_RESET reg wr_enabled = 0; always @(posedge clk) begin @@ -204,10 +260,8 @@ module VX_operands import VX_gpu_pkg::*; #( wr_enabled <= 1; end end - `else - wire wr_enabled = 1; `endif - + for (genvar j = 0; j < `NUM_THREADS; ++j) begin VX_dp_ram #( .DATAW (`XLEN), @@ -221,81 +275,17 @@ module VX_operands import VX_gpu_pkg::*; #( .clk (clk), .read (1'b1), `UNUSED_PIN (wren), - .write (wr_enabled && writeback_if[i].valid && writeback_if[i].data.tmask[j]), - .waddr (wis_to_addr(writeback_if[i].data.rd, writeback_if[i].data.wis)), + `ifdef GPR_RESET + .write (wr_enabled && writeback_if[i].valid && writeback_if[i].data.tmask[j]), + `else + .write (writeback_if[i].valid && writeback_if[i].data.tmask[j]), + `endif + .waddr (gpr_wr_addr), .wdata (writeback_if[i].data.data[j]), - .raddr (wis_to_addr(gpr_rd_rid, gpr_rd_wis)), + .raddr (gpr_rd_addr), .rdata (gpr_rd_data[j]) ); end - - // staging buffer - - `RESET_RELAY (stg_buf_reset, reset); - - VX_elastic_buffer #( - .DATAW (DATAW) - ) stg_buf ( - .clk (clk), - .reset (stg_buf_reset), - .valid_in (scoreboard_if[i].valid), - .ready_in (scoreboard_if[i].ready), - .data_in ({ - scoreboard_if[i].data.uuid, - scoreboard_if[i].data.wis, - scoreboard_if[i].data.tmask, - scoreboard_if[i].data.PC, - scoreboard_if[i].data.wb, - scoreboard_if[i].data.ex_type, - scoreboard_if[i].data.op_type, - scoreboard_if[i].data.op_mod, - scoreboard_if[i].data.use_PC, - scoreboard_if[i].data.use_imm, - scoreboard_if[i].data.imm, - scoreboard_if[i].data.rd}), - .data_out ({ - staging_if.data.uuid, - staging_if.data.wis, - staging_if.data.tmask, - staging_if.data.PC, - staging_if.data.wb, - staging_if.data.ex_type, - staging_if.data.op_type, - staging_if.data.op_mod, - staging_if.data.use_PC, - staging_if.data.use_imm, - staging_if.data.imm, - staging_if.data.rd}), - .valid_out (staging_if.valid), - .ready_out (staging_if.ready) - ); - - assign staging_if.data.rs1_data = rs1_data; - assign staging_if.data.rs2_data = rs2_data; - assign staging_if.data.rs3_data = rs3_data; - - // output buffer - - wire valid_stg, ready_stg; - assign valid_stg = staging_if.valid && data_ready; - assign staging_if.ready = ready_stg && data_ready; - - `RESET_RELAY (out_buf_reset, reset); - - VX_elastic_buffer #( - .DATAW (DATAW + (3 * `NUM_THREADS * `XLEN)), - .SIZE (2), - .OUT_REG (2) - ) out_buf ( - .clk (clk), - .reset (out_buf_reset), - .valid_in (valid_stg), - .ready_in (ready_stg), - .data_in (staging_if.data), - .data_out (operands_if[i].data), - .valid_out (operands_if[i].valid), - .ready_out (operands_if[i].ready) - ); - end + end endmodule diff --git a/hw/rtl/core/VX_scoreboard.sv b/hw/rtl/core/VX_scoreboard.sv index 2206df25..1c5f3676 100644 --- a/hw/rtl/core/VX_scoreboard.sv +++ b/hw/rtl/core/VX_scoreboard.sv @@ -51,7 +51,6 @@ module VX_scoreboard import VX_gpu_pkg::*; #( for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin reg [`UP(ISSUE_RATIO)-1:0][`NUM_REGS-1:0] inuse_regs; - VX_ibuffer_if staging_if(); wire writeback_fire = writeback_if[i].valid && writeback_if[i].data.eop; @@ -84,10 +83,17 @@ module VX_scoreboard import VX_gpu_pkg::*; #( reg [DATAW-1:0] data_out_r; reg valid_out_r; + wire ready_out; wire [3:0] ready_masks = ~{inuse_rd, inuse_rs1, inuse_rs2, inuse_rs3}; wire deps_ready = (& ready_masks); + wire valid_in = ibuffer_if[i].valid && deps_ready; + wire ready_in = ~valid_out_r && deps_ready; + wire [DATAW-1:0] data_in = ibuffer_if[i].data; + + assign ready_out = scoreboard_if[i].ready; + always @(posedge clk) begin if (reset) begin valid_out_r <= 0; @@ -97,40 +103,25 @@ module VX_scoreboard import VX_gpu_pkg::*; #( inuse_regs[writeback_if[i].data.wis][writeback_if[i].data.rd] <= 0; end if (~valid_out_r) begin - valid_out_r <= ibuffer_if[i].valid && deps_ready; - end else if (staging_if.ready) begin - if (staging_if.data.wb) begin - inuse_regs[staging_if.data.wis][staging_if.data.rd] <= 1; + valid_out_r <= valid_in; + end else if (ready_out) begin + if (scoreboard_if[i].data.wb) begin + inuse_regs[scoreboard_if[i].data.wis][scoreboard_if[i].data.rd] <= 1; `ifdef PERF_ENABLE - inuse_units[staging_if.data.wis][staging_if.data.rd] <= staging_if.data.ex_type; + inuse_units[scoreboard_if[i].data.wis][scoreboard_if[i].data.rd] <= scoreboard_if[i].data.ex_type; `endif end valid_out_r <= 0; end end if (~valid_out_r) begin - data_out_r <= ibuffer_if[i].data; + data_out_r <= data_in; end end - assign ibuffer_if[i].ready = ~valid_out_r && deps_ready; - assign staging_if.valid = valid_out_r; - assign staging_if.data = data_out_r; - - VX_elastic_buffer #( - .DATAW (DATAW), - .SIZE (0), - .OUT_REG (2) - ) out_buf ( - .clk (clk), - .reset (reset), - .valid_in (staging_if.valid), - .ready_in (staging_if.ready), - .data_in (staging_if.data), - .data_out (scoreboard_if[i].data), - .valid_out (scoreboard_if[i].valid), - .ready_out (scoreboard_if[i].ready) - ); + assign ibuffer_if[i].ready = ready_in; + assign scoreboard_if[i].valid = valid_out_r; + assign scoreboard_if[i].data = data_out_r; `ifdef SIMULATION reg [31:0] timeout_ctr; From c7a81d1493b5e0420546b25c9465a64321418d20 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 20 Dec 2023 11:57:44 -0800 Subject: [PATCH 32/57] adding sockets support to simx and cache subsystem refactoring minor update minor update minor updates --- hw/rtl/VX_cluster.sv | 66 +++++++++- hw/rtl/VX_config.vh | 9 +- hw/rtl/VX_define.vh | 18 ++- hw/rtl/VX_gpu_pkg.sv | 9 +- hw/rtl/VX_socket.sv | 45 +------ hw/rtl/VX_types.vh | 44 +++---- hw/rtl/core/VX_core.sv | 18 +-- hw/rtl/core/VX_csr_data.sv | 15 +-- hw/rtl/core/VX_issue.sv | 2 +- hw/rtl/core/VX_lsu_unit.sv | 8 +- hw/rtl/interfaces/VX_pipeline_perf_if.sv | 25 ++-- runtime/common/utils.cpp | 34 +---- runtime/simx/vortex.cpp | 2 +- sim/simx/Makefile | 2 +- sim/simx/arch.h | 10 +- sim/simx/cluster.cpp | 158 ++++++++--------------- sim/simx/cluster.h | 41 +++--- sim/simx/core.cpp | 111 ++++++++-------- sim/simx/core.h | 26 ++-- sim/simx/exe_unit.cpp | 38 +++--- sim/simx/main.cpp | 8 +- sim/simx/socket.cpp | 146 +++++++++++++++++++++ sim/simx/socket.h | 87 +++++++++++++ sim/simx/types.h | 7 + 24 files changed, 541 insertions(+), 388 deletions(-) create mode 100644 sim/simx/socket.cpp create mode 100644 sim/simx/socket.h diff --git a/hw/rtl/VX_cluster.sv b/hw/rtl/VX_cluster.sv index 90076673..6de47c5f 100644 --- a/hw/rtl/VX_cluster.sv +++ b/hw/rtl/VX_cluster.sv @@ -85,8 +85,8 @@ module VX_cluster import VX_gpu_pkg::*; #( VX_mem_bus_if #( .DATA_SIZE (`L1_LINE_SIZE), - .TAG_WIDTH (L1_MEM_ARB_TAG_WIDTH) - ) per_socket_mem_bus_if[`NUM_SOCKETS](); + .TAG_WIDTH (L1_MEM_TAG_WIDTH) + ) l1_mem_bus_if[2](); `RESET_RELAY (l2_reset, reset); @@ -102,7 +102,7 @@ module VX_cluster import VX_gpu_pkg::*; #( .MSHR_SIZE (`L2_MSHR_SIZE), .MRSQ_SIZE (`L2_MRSQ_SIZE), .MREQ_SIZE (`L2_MREQ_SIZE), - .TAG_WIDTH (L1_MEM_ARB_TAG_WIDTH), + .TAG_WIDTH (L1_MEM_TAG_WIDTH), .WRITE_ENABLE (1), .UUID_WIDTH (`UUID_WIDTH), .CORE_OUT_REG (2), @@ -115,10 +115,65 @@ module VX_cluster import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE .cache_perf (perf_l2cache), `endif - .core_bus_if (per_socket_mem_bus_if), + .core_bus_if (l1_mem_bus_if), .mem_bus_if (mem_bus_if) ); + VX_mem_bus_if #( + .DATA_SIZE (`L1_LINE_SIZE), + .TAG_WIDTH (ICACHE_MEM_TAG_WIDTH) + ) per_socket_icache_mem_bus_if[`NUM_SOCKETS](); + + VX_mem_bus_if #( + .DATA_SIZE (`L1_LINE_SIZE), + .TAG_WIDTH (DCACHE_MEM_TAG_WIDTH) + ) per_socket_dcache_mem_bus_if[`NUM_SOCKETS](); + + VX_mem_bus_if #( + .DATA_SIZE (ICACHE_LINE_SIZE), + .TAG_WIDTH (ICACHE_MEM_ARB_TAG_WIDTH) + ) icache_mem_bus_if[1](); + + VX_mem_bus_if #( + .DATA_SIZE (DCACHE_LINE_SIZE), + .TAG_WIDTH (DCACHE_MEM_ARB_TAG_WIDTH) + ) dcache_mem_bus_if[1](); + + `RESET_RELAY (l1_mem_arb_reset, reset); + + VX_mem_arb #( + .NUM_INPUTS (`NUM_SOCKETS), + .DATA_SIZE (`L1_LINE_SIZE), + .TAG_WIDTH (ICACHE_MEM_TAG_WIDTH), + .TAG_SEL_IDX (1), // Skip 0 for NC flag + .ARBITER ("R"), + .OUT_REG_REQ (2), + .OUT_REG_RSP (2) + ) icache_mem_arb ( + .clk (clk), + .reset (l1_mem_arb_reset), + .bus_in_if (per_socket_icache_mem_bus_if), + .bus_out_if (icache_mem_bus_if) + ); + + VX_mem_arb #( + .NUM_INPUTS (`NUM_SOCKETS), + .DATA_SIZE (`L1_LINE_SIZE), + .TAG_WIDTH (DCACHE_MEM_TAG_WIDTH), + .TAG_SEL_IDX (1), // Skip 0 for NC flag + .ARBITER ("R"), + .OUT_REG_REQ (2), + .OUT_REG_RSP (2) + ) dcache_mem_arb ( + .clk (clk), + .reset (l1_mem_arb_reset), + .bus_in_if (per_socket_dcache_mem_bus_if), + .bus_out_if (dcache_mem_bus_if) + ); + + `ASSIGN_VX_MEM_BUS_IF_X (l1_mem_bus_if[0], icache_mem_bus_if[0], L1_MEM_TAG_WIDTH, ICACHE_MEM_ARB_TAG_WIDTH); + `ASSIGN_VX_MEM_BUS_IF_X (l1_mem_bus_if[1], dcache_mem_bus_if[0], L1_MEM_TAG_WIDTH, DCACHE_MEM_ARB_TAG_WIDTH); + /////////////////////////////////////////////////////////////////////////// wire [`NUM_SOCKETS-1:0] per_socket_sim_ebreak; @@ -155,7 +210,8 @@ module VX_cluster import VX_gpu_pkg::*; #( .dcr_bus_if (socket_dcr_bus_if), - .mem_bus_if (per_socket_mem_bus_if[i]), + .icache_mem_bus_if (per_socket_icache_mem_bus_if[i]), + .dcache_mem_bus_if (per_socket_dcache_mem_bus_if[i]), `ifdef GBAR_ENABLE .gbar_bus_if (per_socket_gbar_bus_if[i]), diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 3af544c6..d35d906b 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -262,7 +262,10 @@ `endif // LSU Duplicate Address Check -`ifdef LSU_DUP +`ifndef LSU_DUP_DISABLE +`define LSU_DUP_ENABLE +`endif +`ifdef LSU_DUP_ENABLE `define LSU_DUP_ENABLED 1 `else `define LSU_DUP_ENABLED 0 @@ -381,7 +384,7 @@ // Number of Cache Units `ifndef NUM_ICACHES -`define NUM_ICACHES `UP(`NUM_CORES / 4) +`define NUM_ICACHES `UP(`SOCKET_SIZE / 4) `endif // Cache Size @@ -430,7 +433,7 @@ // Number of Cache Units `ifndef NUM_DCACHES -`define NUM_DCACHES `UP(`NUM_CORES / 4) +`define NUM_DCACHES `UP(`SOCKET_SIZE / 4) `endif // Cache Size diff --git a/hw/rtl/VX_define.vh b/hw/rtl/VX_define.vh index 95d206ce..f39e7fea 100644 --- a/hw/rtl/VX_define.vh +++ b/hw/rtl/VX_define.vh @@ -410,8 +410,22 @@ assign dst = src; \ end -`define TO_DISPATCH_DATA(data, tid) \ - {data.uuid, data.wis, data.tmask, data.op_type, data.op_mod, data.wb, data.use_PC, data.use_imm, data.PC, data.imm, data.rd, tid, data.rs1_data, data.rs2_data, data.rs3_data} +`define TO_DISPATCH_DATA(data, tid) { \ + data.uuid, \ + data.wis, \ + data.tmask, \ + data.op_type, \ + data.op_mod, \ + data.wb, \ + data.use_PC, \ + data.use_imm, \ + data.PC, \ + data.imm, \ + data.rd, \ + tid, \ + data.rs1_data, \ + data.rs2_data, \ + data.rs3_data} /////////////////////////////////////////////////////////////////////////////// diff --git a/hw/rtl/VX_gpu_pkg.sv b/hw/rtl/VX_gpu_pkg.sv index 668b53ee..b32b9600 100644 --- a/hw/rtl/VX_gpu_pkg.sv +++ b/hw/rtl/VX_gpu_pkg.sv @@ -141,8 +141,9 @@ package VX_gpu_pkg; /////////////////////////////// L1 Parameters ///////////////////////////// - localparam L1_MEM_TAG_WIDTH = `MAX(ICACHE_MEM_TAG_WIDTH, DCACHE_MEM_TAG_WIDTH); - localparam L1_MEM_ARB_TAG_WIDTH = (L1_MEM_TAG_WIDTH + `CLOG2(2)); + localparam ICACHE_MEM_ARB_TAG_WIDTH = (ICACHE_MEM_TAG_WIDTH + `CLOG2(`NUM_SOCKETS)); + localparam DCACHE_MEM_ARB_TAG_WIDTH = (DCACHE_MEM_TAG_WIDTH + `CLOG2(`NUM_SOCKETS)); + localparam L1_MEM_TAG_WIDTH = `MAX(ICACHE_MEM_ARB_TAG_WIDTH, DCACHE_MEM_ARB_TAG_WIDTH); /////////////////////////////// L2 Parameters ///////////////////////////// @@ -150,10 +151,10 @@ package VX_gpu_pkg; localparam L2_WORD_SIZE = `L1_LINE_SIZE; // Input request size - localparam L2_NUM_REQS = `NUM_SOCKETS; + localparam L2_NUM_REQS = 2; // Core request tag bits - localparam L2_TAG_WIDTH = L1_MEM_ARB_TAG_WIDTH; + localparam L2_TAG_WIDTH = L1_MEM_TAG_WIDTH; // Memory request data bits localparam L2_MEM_DATA_WIDTH = (`L2_LINE_SIZE * 8); diff --git a/hw/rtl/VX_socket.sv b/hw/rtl/VX_socket.sv index 139598d9..74a074d1 100644 --- a/hw/rtl/VX_socket.sv +++ b/hw/rtl/VX_socket.sv @@ -30,7 +30,8 @@ module VX_socket import VX_gpu_pkg::*; #( VX_dcr_bus_if.slave dcr_bus_if, // Memory - VX_mem_bus_if.master mem_bus_if, + VX_mem_bus_if.master icache_mem_bus_if, + VX_mem_bus_if.master dcache_mem_bus_if, `ifdef GBAR_ENABLE // Barrier @@ -76,47 +77,7 @@ module VX_socket import VX_gpu_pkg::*; #( assign mem_perf_tmp_if.mem = mem_perf_if.mem; `endif - VX_mem_bus_if #( - .DATA_SIZE (ICACHE_LINE_SIZE), - .TAG_WIDTH (ICACHE_MEM_TAG_WIDTH) - ) icache_mem_bus_if(); - - VX_mem_bus_if #( - .DATA_SIZE (DCACHE_LINE_SIZE), - .TAG_WIDTH (DCACHE_MEM_TAG_WIDTH) - ) dcache_mem_bus_if(); - - VX_mem_bus_if #( - .DATA_SIZE (`L1_LINE_SIZE), - .TAG_WIDTH (L1_MEM_TAG_WIDTH) - ) cache_mem_bus_if[2](); - - VX_mem_bus_if #( - .DATA_SIZE (`L1_LINE_SIZE), - .TAG_WIDTH (L1_MEM_ARB_TAG_WIDTH) - ) mem_bus_tmp_if[1](); - - `ASSIGN_VX_MEM_BUS_IF_X (cache_mem_bus_if[0], icache_mem_bus_if, L1_MEM_TAG_WIDTH, ICACHE_MEM_TAG_WIDTH); - `ASSIGN_VX_MEM_BUS_IF_X (cache_mem_bus_if[1], dcache_mem_bus_if, L1_MEM_TAG_WIDTH, DCACHE_MEM_TAG_WIDTH); - - `RESET_RELAY (mem_arb_reset, reset); - - VX_mem_arb #( - .NUM_INPUTS (2), - .DATA_SIZE (`L1_LINE_SIZE), - .TAG_WIDTH (L1_MEM_TAG_WIDTH), - .TAG_SEL_IDX (1), // Skip 0 for NC flag - .ARBITER ("R"), - .OUT_REG_REQ (2), - .OUT_REG_RSP (2) - ) mem_arb ( - .clk (clk), - .reset (mem_arb_reset), - .bus_in_if (cache_mem_bus_if), - .bus_out_if (mem_bus_tmp_if) - ); - - `ASSIGN_VX_MEM_BUS_IF (mem_bus_if, mem_bus_tmp_if[0]); + /////////////////////////////////////////////////////////////////////////// diff --git a/hw/rtl/VX_types.vh b/hw/rtl/VX_types.vh index 4fb03783..a5044ccf 100644 --- a/hw/rtl/VX_types.vh +++ b/hw/rtl/VX_types.vh @@ -78,33 +78,25 @@ `define VX_CSR_MPM_IBUF_ST_H 12'hB85 `define VX_CSR_MPM_SCRB_ST 12'hB06 `define VX_CSR_MPM_SCRB_ST_H 12'hB86 -`define VX_CSR_MPM_ALU_ST 12'hB07 -`define VX_CSR_MPM_ALU_ST_H 12'hB87 -`define VX_CSR_MPM_LSU_ST 12'hB08 -`define VX_CSR_MPM_LSU_ST_H 12'hB88 -`define VX_CSR_MPM_FPU_ST 12'hB09 -`define VX_CSR_MPM_FPU_ST_H 12'hB89 -`define VX_CSR_MPM_SFU_ST 12'hB0A -`define VX_CSR_MPM_SFU_ST_H 12'hB8A -`define VX_CSR_MPM_SCRB_ALU 12'hB0B -`define VX_CSR_MPM_SCRB_ALU_H 12'hB8B -`define VX_CSR_MPM_SCRB_FPU 12'hB0C -`define VX_CSR_MPM_SCRB_FPU_H 12'hB8C -`define VX_CSR_MPM_SCRB_LSU 12'hB0D -`define VX_CSR_MPM_SCRB_LSU_H 12'hB8D -`define VX_CSR_MPM_SCRB_SFU 12'hB0E -`define VX_CSR_MPM_SCRB_SFU_H 12'hB8E +`define VX_CSR_MPM_SCRB_ALU 12'hB07 +`define VX_CSR_MPM_SCRB_ALU_H 12'hB87 +`define VX_CSR_MPM_SCRB_FPU 12'hB08 +`define VX_CSR_MPM_SCRB_FPU_H 12'hB88 +`define VX_CSR_MPM_SCRB_LSU 12'hB09 +`define VX_CSR_MPM_SCRB_LSU_H 12'hB89 +`define VX_CSR_MPM_SCRB_SFU 12'hB0A +`define VX_CSR_MPM_SCRB_SFU_H 12'hB8A // PERF: memory -`define VX_CSR_MPM_IFETCHES 12'hB0F -`define VX_CSR_MPM_IFETCHES_H 12'hB8F -`define VX_CSR_MPM_LOADS 12'hB10 -`define VX_CSR_MPM_LOADS_H 12'hB90 -`define VX_CSR_MPM_STORES 12'hB11 -`define VX_CSR_MPM_STORES_H 12'hB91 -`define VX_CSR_MPM_IFETCH_LT 12'hB12 -`define VX_CSR_MPM_IFETCH_LT_H 12'hB92 -`define VX_CSR_MPM_LOAD_LT 12'hB13 -`define VX_CSR_MPM_LOAD_LT_H 12'hB93 +`define VX_CSR_MPM_IFETCHES 12'hB0B +`define VX_CSR_MPM_IFETCHES_H 12'hB8B +`define VX_CSR_MPM_LOADS 12'hB0C +`define VX_CSR_MPM_LOADS_H 12'hB8C +`define VX_CSR_MPM_STORES 12'hB0D +`define VX_CSR_MPM_STORES_H 12'hB8D +`define VX_CSR_MPM_IFETCH_LT 12'hB0E +`define VX_CSR_MPM_IFETCH_LT_H 12'hB8E +`define VX_CSR_MPM_LOAD_LT 12'hB0F +`define VX_CSR_MPM_LOAD_LT_H 12'hB8F // Machine Performance-monitoring memory counters // PERF: icache diff --git a/hw/rtl/core/VX_core.sv b/hw/rtl/core/VX_core.sv index 5aba3075..4d3ce297 100644 --- a/hw/rtl/core/VX_core.sv +++ b/hw/rtl/core/VX_core.sv @@ -273,23 +273,23 @@ module VX_core import VX_gpu_pkg::*; #( wire [1:0] perf_icache_pending_read_cycle; wire [`CLOG2(DCACHE_NUM_REQS+1)+1-1:0] perf_dcache_pending_read_cycle; - reg [`PERF_CTR_BITS-1:0] perf_icache_pending_reads; - reg [`PERF_CTR_BITS-1:0] perf_dcache_pending_reads; + reg [`PERF_CTR_BITS-1:0] perf_icache_pending_reads; + reg [`PERF_CTR_BITS-1:0] perf_dcache_pending_reads; - reg [`PERF_CTR_BITS-1:0] perf_ifetches; - reg [`PERF_CTR_BITS-1:0] perf_loads; - reg [`PERF_CTR_BITS-1:0] perf_stores; + reg [`PERF_CTR_BITS-1:0] perf_ifetches; + reg [`PERF_CTR_BITS-1:0] perf_loads; + reg [`PERF_CTR_BITS-1:0] perf_stores; - wire perf_icache_req_fire = icache_bus_if.req_valid & icache_bus_if.req_ready; - wire perf_icache_rsp_fire = icache_bus_if.rsp_valid & icache_bus_if.rsp_ready; + wire perf_icache_req_fire = icache_bus_if.req_valid && icache_bus_if.req_ready; + wire perf_icache_rsp_fire = icache_bus_if.rsp_valid && icache_bus_if.rsp_ready; wire [DCACHE_NUM_REQS-1:0] perf_dcache_rd_req_fire, perf_dcache_rd_req_fire_r; wire [DCACHE_NUM_REQS-1:0] perf_dcache_wr_req_fire, perf_dcache_wr_req_fire_r; wire [DCACHE_NUM_REQS-1:0] perf_dcache_rsp_fire; for (genvar i = 0; i < DCACHE_NUM_REQS; ++i) begin - assign perf_dcache_rd_req_fire[i] = dcache_bus_if[i].req_valid && ~dcache_bus_if[i].req_data.rw && dcache_bus_if[i].req_ready; - assign perf_dcache_wr_req_fire[i] = dcache_bus_if[i].req_valid && dcache_bus_if[i].req_data.rw && dcache_bus_if[i].req_ready; + assign perf_dcache_rd_req_fire[i] = dcache_bus_if[i].req_valid && dcache_bus_if[i].req_ready && ~dcache_bus_if[i].req_data.rw; + assign perf_dcache_wr_req_fire[i] = dcache_bus_if[i].req_valid && dcache_bus_if[i].req_ready && dcache_bus_if[i].req_data.rw; assign perf_dcache_rsp_fire[i] = dcache_bus_if[i].rsp_valid && dcache_bus_if[i].rsp_ready; end diff --git a/hw/rtl/core/VX_csr_data.sv b/hw/rtl/core/VX_csr_data.sv index 6d7c41f8..1b370260 100644 --- a/hw/rtl/core/VX_csr_data.sv +++ b/hw/rtl/core/VX_csr_data.sv @@ -195,19 +195,6 @@ import VX_fpu_pkg::*; `VX_CSR_MPM_IBUF_ST_H : read_data_ro_r = 32'(pipeline_perf_if.ibf_stalls[`PERF_CTR_BITS-1:32]); `VX_CSR_MPM_SCRB_ST : read_data_ro_r = pipeline_perf_if.scb_stalls[31:0]; `VX_CSR_MPM_SCRB_ST_H : read_data_ro_r = 32'(pipeline_perf_if.scb_stalls[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_ALU_ST : read_data_ro_r = pipeline_perf_if.dsp_stalls[`EX_ALU][31:0]; - `VX_CSR_MPM_ALU_ST_H : read_data_ro_r = 32'(pipeline_perf_if.dsp_stalls[`EX_ALU][`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_LSU_ST : read_data_ro_r = pipeline_perf_if.dsp_stalls[`EX_LSU][31:0]; - `VX_CSR_MPM_LSU_ST_H : read_data_ro_r = 32'(pipeline_perf_if.dsp_stalls[`EX_LSU][`PERF_CTR_BITS-1:32]); - `ifdef EXT_F_ENABLE - `VX_CSR_MPM_FPU_ST : read_data_ro_r = pipeline_perf_if.dsp_stalls[`EX_FPU][31:0]; - `VX_CSR_MPM_FPU_ST_H : read_data_ro_r = 32'(pipeline_perf_if.dsp_stalls[`EX_FPU][`PERF_CTR_BITS-1:32]); - `else - `VX_CSR_MPM_FPU_ST : read_data_ro_r = '0; - `VX_CSR_MPM_FPU_ST_H : read_data_ro_r = '0; - `endif - `VX_CSR_MPM_SFU_ST : read_data_ro_r = pipeline_perf_if.dsp_stalls[`EX_SFU][31:0]; - `VX_CSR_MPM_SFU_ST_H : read_data_ro_r = 32'(pipeline_perf_if.dsp_stalls[`EX_SFU][`PERF_CTR_BITS-1:32]); `VX_CSR_MPM_SCRB_ALU : read_data_ro_r = 32'(pipeline_perf_if.scb_uses[`EX_ALU][`PERF_CTR_BITS-1:32]); `VX_CSR_MPM_SCRB_ALU_H : read_data_ro_r = pipeline_perf_if.scb_uses[`EX_ALU][31:0]; `ifdef EXT_F_ENABLE @@ -220,7 +207,7 @@ import VX_fpu_pkg::*; `VX_CSR_MPM_SCRB_LSU : read_data_ro_r = 32'(pipeline_perf_if.scb_uses[`EX_LSU][`PERF_CTR_BITS-1:32]); `VX_CSR_MPM_SCRB_LSU_H : read_data_ro_r = pipeline_perf_if.scb_uses[`EX_LSU][31:0]; `VX_CSR_MPM_SCRB_SFU : read_data_ro_r = 32'(pipeline_perf_if.scb_uses[`EX_SFU][`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_SCRB_SFU_H : read_data_ro_r = pipeline_perf_if.scb_uses[`EX_SFU][31:0]; + `VX_CSR_MPM_SCRB_SFU_H : read_data_ro_r = pipeline_perf_if.scb_uses[`EX_SFU][31:0]; // PERF: memory `VX_CSR_MPM_IFETCHES : read_data_ro_r = pipeline_perf_if.ifetches[31:0]; `VX_CSR_MPM_IFETCHES_H : read_data_ro_r = 32'(pipeline_perf_if.ifetches[`PERF_CTR_BITS-1:32]); diff --git a/hw/rtl/core/VX_issue.sv b/hw/rtl/core/VX_issue.sv index 8d0eaff6..912abc97 100644 --- a/hw/rtl/core/VX_issue.sv +++ b/hw/rtl/core/VX_issue.sv @@ -84,7 +84,7 @@ module VX_issue #( .clk (clk), .reset (dispatch_reset), `ifdef PERF_ENABLE - .perf_stalls (perf_issue_if.dsp_stalls), + `UNUSED_PIN (perf_stalls), `endif .operands_if (operands_if), .alu_dispatch_if(alu_dispatch_if), diff --git a/hw/rtl/core/VX_lsu_unit.sv b/hw/rtl/core/VX_lsu_unit.sv index 1e0a09b8..5a57db4c 100644 --- a/hw/rtl/core/VX_lsu_unit.sv +++ b/hw/rtl/core/VX_lsu_unit.sv @@ -96,7 +96,7 @@ module VX_lsu_unit import VX_gpu_pkg::*; #( // detect duplicate addresses wire lsu_is_dup; -`ifdef LSU_DUP +`ifdef LSU_DUP_ENABLE if (NUM_LANES > 1) begin wire [NUM_LANES-2:0] addr_matches; for (genvar i = 0; i < (NUM_LANES-1); ++i) begin @@ -304,7 +304,7 @@ module VX_lsu_unit import VX_gpu_pkg::*; #( assign mem_req_tag = { execute_if[0].data.uuid, lsu_addr_type, execute_if[0].data.wid, execute_if[0].data.tmask, execute_if[0].data.PC, execute_if[0].data.rd, execute_if[0].data.op_type, req_align, execute_if[0].data.pid, pkt_waddr - `ifdef LSU_DUP + `ifdef LSU_DUP_ENABLE , lsu_is_dup `endif }; @@ -448,13 +448,13 @@ module VX_lsu_unit import VX_gpu_pkg::*; #( wire [PID_WIDTH-1:0] rsp_pid; wire rsp_is_dup; -`ifndef LSU_DUP +`ifndef LSU_DUP_ENABLE assign rsp_is_dup = 0; `endif assign { rsp_uuid, rsp_addr_type, rsp_wid, rsp_tmask_uq, rsp_pc, rsp_rd, rsp_op_type, rsp_align, rsp_pid, pkt_raddr - `ifdef LSU_DUP + `ifdef LSU_DUP_ENABLE , rsp_is_dup `endif } = mem_rsp_tag; diff --git a/hw/rtl/interfaces/VX_pipeline_perf_if.sv b/hw/rtl/interfaces/VX_pipeline_perf_if.sv index 66225336..2ae0f678 100644 --- a/hw/rtl/interfaces/VX_pipeline_perf_if.sv +++ b/hw/rtl/interfaces/VX_pipeline_perf_if.sv @@ -14,18 +14,17 @@ `include "VX_define.vh" interface VX_pipeline_perf_if (); - wire [`PERF_CTR_BITS-1:0] sched_idles; - wire [`PERF_CTR_BITS-1:0] sched_stalls; - wire [`PERF_CTR_BITS-1:0] ibf_stalls; - wire [`PERF_CTR_BITS-1:0] scb_stalls; - wire [`PERF_CTR_BITS-1:0] scb_uses [`NUM_EX_UNITS]; - wire [`PERF_CTR_BITS-1:0] dsp_stalls [`NUM_EX_UNITS]; + wire [`PERF_CTR_BITS-1:0] sched_idles; + wire [`PERF_CTR_BITS-1:0] sched_stalls; + wire [`PERF_CTR_BITS-1:0] ibf_stalls; + wire [`PERF_CTR_BITS-1:0] scb_stalls; + wire [`PERF_CTR_BITS-1:0] scb_uses [`NUM_EX_UNITS]; - wire [`PERF_CTR_BITS-1:0] ifetches; - wire [`PERF_CTR_BITS-1:0] loads; - wire [`PERF_CTR_BITS-1:0] stores; - wire [`PERF_CTR_BITS-1:0] ifetch_latency; - wire [`PERF_CTR_BITS-1:0] load_latency; + wire [`PERF_CTR_BITS-1:0] ifetches; + wire [`PERF_CTR_BITS-1:0] loads; + wire [`PERF_CTR_BITS-1:0] stores; + wire [`PERF_CTR_BITS-1:0] ifetch_latency; + wire [`PERF_CTR_BITS-1:0] load_latency; modport schedule ( output sched_idles, @@ -35,8 +34,7 @@ interface VX_pipeline_perf_if (); modport issue ( output ibf_stalls, output scb_stalls, - output scb_uses, - output dsp_stalls + output scb_uses ); modport slave ( @@ -45,7 +43,6 @@ interface VX_pipeline_perf_if (); input ibf_stalls, input scb_stalls, input scb_uses, - input dsp_stalls, input ifetches, input loads, input stores, diff --git a/runtime/common/utils.cpp b/runtime/common/utils.cpp index c0199a86..5f472c84 100644 --- a/runtime/common/utils.cpp +++ b/runtime/common/utils.cpp @@ -204,10 +204,6 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { uint64_t sched_stalls = 0; uint64_t ibuffer_stalls = 0; uint64_t scrb_stalls = 0; - uint64_t lsu_stalls = 0; - uint64_t fpu_stalls = 0; - uint64_t alu_stalls = 0; - uint64_t sfu_stalls = 0; uint64_t scrb_alu = 0; uint64_t scrb_fpu = 0; uint64_t scrb_lsu = 0; @@ -310,34 +306,10 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { calcAvgPercent(scrb_sfu_per_core, scrb_total)); scrb_stalls += scrb_stalls_per_core; } - // alu_stalls - { - uint64_t alu_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_ALU_ST); - if (num_cores > 1) fprintf(stream, "PERF: core%d: alu unit stalls=%ld\n", core_id, alu_stalls_per_core); - alu_stalls += alu_stalls_per_core; - } - // lsu_stalls - { - uint64_t lsu_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_LSU_ST); - if (num_cores > 1) fprintf(stream, "PERF: core%d: lsu unit stalls=%ld\n", core_id, lsu_stalls_per_core); - lsu_stalls += lsu_stalls_per_core; - } - // fpu_stalls - { - uint64_t fpu_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_FPU_ST); - if (num_cores > 1) fprintf(stream, "PERF: core%d: fpu unit stalls=%ld\n", core_id, fpu_stalls_per_core); - fpu_stalls += fpu_stalls_per_core; - } - // sfu_stalls - { - uint64_t sfu_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SFU_ST); - if (num_cores > 1) fprintf(stream, "PERF: core%d: sfu unit stalls=%ld\n", core_id, sfu_stalls_per_core); - sfu_stalls += sfu_stalls_per_core; - } // PERF: memory // ifetches { - uint64_t ifetches_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_LOADS); + uint64_t ifetches_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_IFETCHES); if (num_cores > 1) fprintf(stream, "PERF: core%d: ifetches=%ld\n", core_id, ifetches_per_core); ifetches += ifetches_per_core; @@ -464,10 +436,6 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { calcAvgPercent(scrb_fpu, scrb_total), calcAvgPercent(scrb_lsu, scrb_total), calcAvgPercent(scrb_sfu, scrb_total)); - fprintf(stream, "PERF: alu unit stalls=%ld\n", alu_stalls); - fprintf(stream, "PERF: lsu unit stalls=%ld\n", lsu_stalls); - fprintf(stream, "PERF: fpu unit stalls=%ld\n", fpu_stalls); - fprintf(stream, "PERF: sfu unit stalls=%ld\n", sfu_stalls); fprintf(stream, "PERF: ifetches=%ld\n", ifetches); fprintf(stream, "PERF: loads=%ld\n", loads); fprintf(stream, "PERF: stores=%ld\n", stores); diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 3b4cb171..b7b9cdcb 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -87,7 +87,7 @@ private: class vx_device { public: vx_device() - : arch_(NUM_THREADS, NUM_WARPS, NUM_CORES, NUM_CLUSTERS) + : arch_(NUM_THREADS, NUM_WARPS, NUM_CORES) , ram_(RAM_PAGE_SIZE) , processor_(arch_) , global_mem_( diff --git a/sim/simx/Makefile b/sim/simx/Makefile index 42823205..bb67dbb5 100644 --- a/sim/simx/Makefile +++ b/sim/simx/Makefile @@ -15,7 +15,7 @@ LDFLAGS += $(THIRD_PARTY_DIR)/softfloat/build/Linux-x86_64-GCC/softfloat.a LDFLAGS += -L$(THIRD_PARTY_DIR)/ramulator -lramulator SRCS = ../common/util.cpp ../common/mem.cpp ../common/rvfloats.cpp -SRCS += processor.cpp cluster.cpp core.cpp warp.cpp decode.cpp execute.cpp exe_unit.cpp cache_sim.cpp mem_sim.cpp shared_mem.cpp dcrs.cpp +SRCS += processor.cpp cluster.cpp socket.cpp core.cpp warp.cpp decode.cpp execute.cpp exe_unit.cpp cache_sim.cpp mem_sim.cpp shared_mem.cpp dcrs.cpp # Debugigng ifdef DEBUG diff --git a/sim/simx/arch.h b/sim/simx/arch.h index ab6ac4a3..099fbedd 100644 --- a/sim/simx/arch.h +++ b/sim/simx/arch.h @@ -28,6 +28,7 @@ private: uint16_t num_warps_; uint16_t num_cores_; uint16_t num_clusters_; + uint16_t socket_size_; uint16_t vsize_; uint16_t num_regs_; uint16_t num_csrs_; @@ -35,11 +36,12 @@ private: uint16_t ipdom_size_; public: - Arch(uint16_t num_threads, uint16_t num_warps, uint16_t num_cores, uint16_t num_clusters) + Arch(uint16_t num_threads, uint16_t num_warps, uint16_t num_cores) : num_threads_(num_threads) , num_warps_(num_warps) , num_cores_(num_cores) - , num_clusters_(num_clusters) + , num_clusters_(NUM_CLUSTERS) + , socket_size_(SOCKET_SIZE) , vsize_(16) , num_regs_(32) , num_csrs_(4096) @@ -82,6 +84,10 @@ public: uint16_t num_clusters() const { return num_clusters_; } + + uint16_t socket_size() const { + return socket_size_; + } }; } \ No newline at end of file diff --git a/sim/simx/cluster.cpp b/sim/simx/cluster.cpp index d7104915..7f690fb6 100644 --- a/sim/simx/cluster.cpp +++ b/sim/simx/cluster.cpp @@ -24,14 +24,38 @@ Cluster::Cluster(const SimContext& ctx, , mem_req_port(this) , mem_rsp_port(this) , cluster_id_(cluster_id) - , cores_(arch.num_cores()) + , sockets_(NUM_SOCKETS) , barriers_(arch.num_barriers(), 0) - , sharedmems_(arch.num_cores()) , processor_(processor) + , cores_per_socket_(arch.socket_size()) { - auto num_cores = arch.num_cores(); - char sname[100]; + + auto sockets_per_cluster = sockets_.size(); + + // create sockets + + snprintf(sname, 100, "cluster%d-icache-arb", cluster_id); + auto icache_switch = MemSwitch::Create(sname, ArbiterType::RoundRobin, sockets_per_cluster); + + snprintf(sname, 100, "cluster%d-dcache-arb", cluster_id); + auto dcache_switch = MemSwitch::Create(sname, ArbiterType::RoundRobin, sockets_per_cluster); + + for (uint32_t i = 0; i < sockets_per_cluster; ++i) { + uint32_t socket_id = cluster_id * sockets_per_cluster + i; + auto socket = Socket::Create(socket_id, this, arch, dcrs); + + socket->icache_mem_req_port.bind(&icache_switch->ReqIn.at(i)); + icache_switch->RspIn.at(i).bind(&socket->icache_mem_rsp_port); + + socket->dcache_mem_req_port.bind(&dcache_switch->ReqIn.at(i)); + dcache_switch->RspIn.at(i).bind(&socket->dcache_mem_rsp_port); + + sockets_.at(i) = socket; + } + + // Create l2cache + snprintf(sname, 100, "cluster%d-l2cache", cluster_id); l2cache_ = CacheSim::Create(sname, CacheSim::Config{ !L2_ENABLED, @@ -42,7 +66,7 @@ Cluster::Cluster(const SimContext& ctx, log2ceil(L2_NUM_BANKS), // B XLEN, // address bits 1, // number of ports - 5, // request size + 2, // request size true, // write-through false, // write response L2_MSHR_SIZE, // mshr @@ -52,87 +76,11 @@ Cluster::Cluster(const SimContext& ctx, l2cache_->MemReqPort.bind(&this->mem_req_port); this->mem_rsp_port.bind(&l2cache_->MemRspPort); - snprintf(sname, 100, "cluster%d-icaches", cluster_id); - icaches_ = CacheCluster::Create(sname, num_cores, NUM_ICACHES, 1, CacheSim::Config{ - !ICACHE_ENABLED, - log2ceil(ICACHE_SIZE), // C - log2ceil(L1_LINE_SIZE), // L - log2ceil(sizeof(uint32_t)), // W - log2ceil(ICACHE_NUM_WAYS),// A - 1, // B - XLEN, // address bits - 1, // number of ports - 1, // number of inputs - true, // write-through - false, // write response - (uint8_t)arch.num_warps(), // mshr - 2, // pipeline latency - }); + icache_switch->ReqOut.at(0).bind(&l2cache_->CoreReqPorts.at(0)); + l2cache_->CoreRspPorts.at(0).bind(&icache_switch->RspOut.at(0)); - icaches_->MemReqPort.bind(&l2cache_->CoreReqPorts.at(0)); - l2cache_->CoreRspPorts.at(0).bind(&icaches_->MemRspPort); - - snprintf(sname, 100, "cluster%d-dcaches", cluster_id); - dcaches_ = CacheCluster::Create(sname, num_cores, NUM_DCACHES, NUM_LSU_LANES, CacheSim::Config{ - !DCACHE_ENABLED, - log2ceil(DCACHE_SIZE), // C - log2ceil(L1_LINE_SIZE), // L - log2ceil(sizeof(Word)), // W - log2ceil(DCACHE_NUM_WAYS),// A - log2ceil(DCACHE_NUM_BANKS), // B - XLEN, // address bits - 1, // number of ports - DCACHE_NUM_BANKS, // number of inputs - true, // write-through - false, // write response - DCACHE_MSHR_SIZE, // mshr - 4, // pipeline latency - }); - - dcaches_->MemReqPort.bind(&l2cache_->CoreReqPorts.at(1)); - l2cache_->CoreRspPorts.at(1).bind(&dcaches_->MemRspPort); - - /////////////////////////////////////////////////////////////////////////// - - // create shared memory blocks - for (uint32_t i = 0; i < num_cores; ++i) { - snprintf(sname, 100, "cluster%d-shared_mem%d", cluster_id, i); - sharedmems_.at(i) = SharedMem::Create(sname, SharedMem::Config{ - (1 << SMEM_LOG_SIZE), - sizeof(Word), - NUM_LSU_LANES, - NUM_LSU_LANES, - false - }); - } - - // create cores - - for (uint32_t i = 0; i < num_cores; ++i) { - uint32_t core_id = cluster_id * num_cores + i; - cores_.at(i) = Core::Create(core_id, - this, - arch, - dcrs, - sharedmems_.at(i)); - - cores_.at(i)->icache_req_ports.at(0).bind(&icaches_->CoreReqPorts.at(i).at(0)); - icaches_->CoreRspPorts.at(i).at(0).bind(&cores_.at(i)->icache_rsp_ports.at(0)); - - for (uint32_t j = 0; j < NUM_LSU_LANES; ++j) { - snprintf(sname, 100, "cluster%d-smem_demux%d_%d", cluster_id, i, j); - auto smem_demux = SMemDemux::Create(sname); - - cores_.at(i)->dcache_req_ports.at(j).bind(&smem_demux->ReqIn); - smem_demux->RspIn.bind(&cores_.at(i)->dcache_rsp_ports.at(j)); - - smem_demux->ReqDC.bind(&dcaches_->CoreReqPorts.at(i).at(j)); - dcaches_->CoreRspPorts.at(i).at(j).bind(&smem_demux->RspDC); - - smem_demux->ReqSM.bind(&sharedmems_.at(i)->Inputs.at(j)); - sharedmems_.at(i)->Outputs.at(j).bind(&smem_demux->RspSM); - } - } + dcache_switch->ReqOut.at(0).bind(&l2cache_->CoreReqPorts.at(1)); + l2cache_->CoreRspPorts.at(1).bind(&dcache_switch->RspOut.at(0)); } Cluster::~Cluster() { @@ -150,14 +98,14 @@ void Cluster::tick() { } void Cluster::attach_ram(RAM* ram) { - for (auto core : cores_) { - core->attach_ram(ram); + for (auto& socket : sockets_) { + socket->attach_ram(ram); } } bool Cluster::running() const { - for (auto& core : cores_) { - if (core->running()) + for (auto& socket : sockets_) { + if (socket->running()) return true; } return false; @@ -166,9 +114,9 @@ bool Cluster::running() const { bool Cluster::check_exit(Word* exitcode, bool riscv_test) const { bool done = true; Word exitcode_ = 0; - for (auto& core : cores_) { + for (auto& socket : sockets_) { Word ec; - if (core->check_exit(&ec, riscv_test)) { + if (socket->check_exit(&ec, riscv_test)) { exitcode_ |= ec; } else { done = false; @@ -181,36 +129,32 @@ bool Cluster::check_exit(Word* exitcode, bool riscv_test) const { void Cluster::barrier(uint32_t bar_id, uint32_t count, uint32_t core_id) { auto& barrier = barriers_.at(bar_id); - uint32_t local_core_id = core_id % cores_.size(); + auto sockets_per_cluster = sockets_.size(); + auto cores_per_socket = cores_per_socket_; + + uint32_t cores_per_cluster = sockets_per_cluster * cores_per_socket; + uint32_t local_core_id = core_id % cores_per_cluster; barrier.set(local_core_id); DP(3, "*** Suspend core #" << core_id << " at barrier #" << bar_id); if (barrier.count() == (size_t)count) { // resume all suspended cores - for (uint32_t i = 0; i < cores_.size(); ++i) { - if (barrier.test(i)) { - DP(3, "*** Resume core #" << i << " at barrier #" << bar_id); - cores_.at(i)->resume(); + for (uint32_t s = 0; s < sockets_per_cluster; ++s) { + for (uint32_t c = 0; c < cores_per_socket; ++c) { + uint32_t i = s * cores_per_socket + c; + if (barrier.test(i)) { + DP(3, "*** Resume core #" << i << " at barrier #" << bar_id); + sockets_.at(s)->resume(c); + } } } barrier.reset(); } } -ProcessorImpl* Cluster::processor() const { - return processor_; -} - Cluster::PerfStats Cluster::perf_stats() const { Cluster::PerfStats perf; - perf.icache = icaches_->perf_stats(); - perf.dcache = dcaches_->perf_stats(); perf.l2cache = l2cache_->perf_stats(); - - for (auto sharedmem : sharedmems_) { - perf.sharedmem += sharedmem->perf_stats(); - } - return perf; } \ No newline at end of file diff --git a/sim/simx/cluster.h b/sim/simx/cluster.h index f91241e9..2547486d 100644 --- a/sim/simx/cluster.h +++ b/sim/simx/cluster.h @@ -17,8 +17,8 @@ #include "dcrs.h" #include "arch.h" #include "cache_cluster.h" -#include "shared_mem.h" #include "core.h" +#include "socket.h" #include "constants.h" namespace vortex { @@ -27,17 +27,11 @@ class ProcessorImpl; class Cluster : public SimObject { public: - struct PerfStats { - CacheSim::PerfStats icache; - CacheSim::PerfStats dcache; - SharedMem::PerfStats sharedmem; - CacheSim::PerfStats l2cache; + struct PerfStats { + CacheSim::PerfStats l2cache; PerfStats& operator+=(const PerfStats& rhs) { - this->icache += rhs.icache; - this->dcache += rhs.dcache; - this->sharedmem += rhs.sharedmem; - this->l2cache += rhs.l2cache; + this->l2cache += rhs.l2cache; return *this; } }; @@ -53,6 +47,14 @@ public: ~Cluster(); + uint32_t id() const { + return cluster_id_; + } + + ProcessorImpl* processor() const { + return processor_; + } + void reset(); void tick(); @@ -65,22 +67,15 @@ public: void barrier(uint32_t bar_id, uint32_t count, uint32_t core_id); - ProcessorImpl* processor() const; - Cluster::PerfStats perf_stats() const; private: - uint32_t cluster_id_; - std::vector cores_; - std::vector barriers_; - CacheSim::Ptr l2cache_; - CacheCluster::Ptr icaches_; - CacheCluster::Ptr dcaches_; - std::vector sharedmems_; - CacheCluster::Ptr tcaches_; - CacheCluster::Ptr ocaches_; - CacheCluster::Ptr rcaches_; - ProcessorImpl* processor_; + uint32_t cluster_id_; + std::vector sockets_; + std::vector barriers_; + CacheSim::Ptr l2cache_; + ProcessorImpl* processor_; + uint32_t cores_per_socket_; }; } // namespace vortex \ No newline at end of file diff --git a/sim/simx/core.cpp b/sim/simx/core.cpp index 49c2ec35..7a549ebd 100644 --- a/sim/simx/core.cpp +++ b/sim/simx/core.cpp @@ -21,18 +21,14 @@ #include "mem.h" #include "decode.h" #include "core.h" +#include "socket.h" #include "debug.h" #include "constants.h" #include "processor_impl.h" using namespace vortex; -Core::Core(const SimContext& ctx, - uint32_t core_id, - Cluster* cluster, - const Arch &arch, - const DCRS &dcrs, - SharedMem::Ptr sharedmem) +Core::Core(const SimContext& ctx, uint32_t core_id, Socket* socket, const Arch &arch, const DCRS &dcrs) : SimObject(ctx, "core") , icache_req_ports(1, this) , icache_rsp_ports(1, this) @@ -50,12 +46,12 @@ Core::Core(const SimContext& ctx, , operands_(ISSUE_WIDTH) , dispatchers_((uint32_t)ExeType::ExeTypeCount) , exe_units_((uint32_t)ExeType::ExeTypeCount) - , sharedmem_(sharedmem) + , smem_demuxs_(NUM_LSU_LANES) , fetch_latch_("fetch") , decode_latch_("decode") , pending_icache_(arch_.num_warps()) , csrs_(arch.num_warps()) - , cluster_(cluster) + , socket_(socket) , commit_arbs_(ISSUE_WIDTH) { char sname[100]; @@ -72,6 +68,27 @@ Core::Core(const SimContext& ctx, operands_.at(i) = SimPlatform::instance().create_object(); } + // initialize shared memory + shared_mem_ = SharedMem::Create(sname, SharedMem::Config{ + (1 << SMEM_LOG_SIZE), + sizeof(Word), + NUM_LSU_LANES, + NUM_LSU_LANES, + false + }); + for (uint32_t i = 0; i < NUM_LSU_LANES; ++i) { + snprintf(sname, 100, "smem_demux%d_%d", core_id, i); + auto smem_demux = SMemDemux::Create(sname); + + smem_demux->ReqDC.bind(&dcache_req_ports.at(i)); + dcache_rsp_ports.at(i).bind(&smem_demux->RspDC); + + smem_demux->ReqSM.bind(&shared_mem_->Inputs.at(i)); + shared_mem_->Outputs.at(i).bind(&smem_demux->RspSM); + + smem_demuxs_.at(i) = smem_demux; + } + // initialize dispatchers dispatchers_.at((int)ExeType::ALU) = SimPlatform::instance().create_object(arch, 2, NUM_ALU_BLOCKS, NUM_ALU_LANES); dispatchers_.at((int)ExeType::FPU) = SimPlatform::instance().create_object(arch, 2, NUM_FPU_BLOCKS, NUM_FPU_LANES); @@ -241,13 +258,6 @@ void Core::decode() { stalled_warps_.reset(trace->wid); } - // update perf counters - uint32_t active_threads = trace->tmask.count(); - if (trace->exe_type == ExeType::LSU && trace->lsu_type == LsuType::LOAD) - perf_stats_.loads += active_threads; - if (trace->exe_type == ExeType::LSU && trace->lsu_type == LsuType::STORE) - perf_stats_.stores += active_threads; - DT(3, "pipeline-decode: " << *trace); // insert to ibuffer @@ -394,7 +404,7 @@ void Core::barrier(uint32_t bar_id, uint32_t count, uint32_t warp_id) { if (is_global) { // global barrier handling if (barrier.count() == active_warps_.count()) { - cluster_->barrier(bar_idx, count, core_id_); + socket_->barrier(bar_idx, count, core_id_); barrier.reset(); } } else { @@ -431,7 +441,7 @@ AddrType Core::get_addr_type(uint64_t addr) { void Core::dcache_read(void *data, uint64_t addr, uint32_t size) { auto type = this->get_addr_type(addr); if (type == AddrType::Shared) { - sharedmem_->read(data, addr, size); + shared_mem_->read(data, addr, size); } else { mmu_.read(data, addr, size, 0); } @@ -446,7 +456,7 @@ void Core::dcache_write(const void* data, uint64_t addr, uint32_t size) { this->writeToStdOut(data, addr, size); } else { if (type == AddrType::Shared) { - sharedmem_->write(data, addr, size); + shared_mem_->write(data, addr, size); } else { mmu_.write(data, addr, size, 0); } @@ -554,16 +564,8 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { case VX_CSR_MPM_SCHED_ST_H:return perf_stats_.sched_stalls >> 32; case VX_CSR_MPM_IBUF_ST: return perf_stats_.ibuf_stalls & 0xffffffff; case VX_CSR_MPM_IBUF_ST_H: return perf_stats_.ibuf_stalls >> 32; - case VX_CSR_MPM_SCRB_ST: return perf_stats_.scrb_stalls & 0xffffffff; - case VX_CSR_MPM_SCRB_ST_H: return perf_stats_.scrb_stalls >> 32; - case VX_CSR_MPM_ALU_ST: return perf_stats_.alu_stalls & 0xffffffff; - case VX_CSR_MPM_ALU_ST_H: return perf_stats_.alu_stalls >> 32; - case VX_CSR_MPM_LSU_ST: return perf_stats_.lsu_stalls & 0xffffffff; - case VX_CSR_MPM_LSU_ST_H: return perf_stats_.lsu_stalls >> 32; - case VX_CSR_MPM_FPU_ST: return perf_stats_.fpu_stalls & 0xffffffff; - case VX_CSR_MPM_FPU_ST_H: return perf_stats_.fpu_stalls >> 32; - case VX_CSR_MPM_SFU_ST: return perf_stats_.sfu_stalls & 0xffffffff; - case VX_CSR_MPM_SFU_ST_H: return perf_stats_.sfu_stalls >> 32; + case VX_CSR_MPM_SCRB_ST: return perf_stats_.scrb_stalls & 0xffffffff; + case VX_CSR_MPM_SCRB_ST_H: return perf_stats_.scrb_stalls >> 32; case VX_CSR_MPM_SCRB_ALU: return perf_stats_.scrb_alu & 0xffffffff; case VX_CSR_MPM_SCRB_ALU_H:return perf_stats_.scrb_alu >> 32; case VX_CSR_MPM_SCRB_FPU: return perf_stats_.scrb_fpu & 0xffffffff; @@ -572,7 +574,6 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { case VX_CSR_MPM_SCRB_LSU_H:return perf_stats_.scrb_lsu >> 32; case VX_CSR_MPM_SCRB_SFU: return perf_stats_.scrb_sfu & 0xffffffff; case VX_CSR_MPM_SCRB_SFU_H:return perf_stats_.scrb_sfu >> 32; - case VX_CSR_MPM_IFETCHES: return perf_stats_.ifetches & 0xffffffff; case VX_CSR_MPM_IFETCHES_H: return perf_stats_.ifetches >> 32; case VX_CSR_MPM_LOADS: return perf_stats_.loads & 0xffffffff; @@ -586,27 +587,29 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { } } break; case VX_DCR_MPM_CLASS_MEM: { - auto proc_perf = cluster_->processor()->perf_stats(); + auto proc_perf = socket_->cluster()->processor()->perf_stats(); + auto socket_perf = socket_->perf_stats(); + auto smem_perf = shared_mem_->perf_stats(); switch (addr) { - case VX_CSR_MPM_ICACHE_READS: return proc_perf.clusters.icache.reads & 0xffffffff; - case VX_CSR_MPM_ICACHE_READS_H: return proc_perf.clusters.icache.reads >> 32; - case VX_CSR_MPM_ICACHE_MISS_R: return proc_perf.clusters.icache.read_misses & 0xffffffff; - case VX_CSR_MPM_ICACHE_MISS_R_H: return proc_perf.clusters.icache.read_misses >> 32; - case VX_CSR_MPM_ICACHE_MSHR_ST: return proc_perf.clusters.icache.mshr_stalls & 0xffffffff; - case VX_CSR_MPM_ICACHE_MSHR_ST_H: return proc_perf.clusters.icache.mshr_stalls >> 32; + case VX_CSR_MPM_ICACHE_READS: return socket_perf.icache.reads & 0xffffffff; + case VX_CSR_MPM_ICACHE_READS_H: return socket_perf.icache.reads >> 32; + case VX_CSR_MPM_ICACHE_MISS_R: return socket_perf.icache.read_misses & 0xffffffff; + case VX_CSR_MPM_ICACHE_MISS_R_H: return socket_perf.icache.read_misses >> 32; + case VX_CSR_MPM_ICACHE_MSHR_ST: return socket_perf.icache.mshr_stalls & 0xffffffff; + case VX_CSR_MPM_ICACHE_MSHR_ST_H: return socket_perf.icache.mshr_stalls >> 32; - case VX_CSR_MPM_DCACHE_READS: return proc_perf.clusters.dcache.reads & 0xffffffff; - case VX_CSR_MPM_DCACHE_READS_H: return proc_perf.clusters.dcache.reads >> 32; - case VX_CSR_MPM_DCACHE_WRITES: return proc_perf.clusters.dcache.writes & 0xffffffff; - case VX_CSR_MPM_DCACHE_WRITES_H: return proc_perf.clusters.dcache.writes >> 32; - case VX_CSR_MPM_DCACHE_MISS_R: return proc_perf.clusters.dcache.read_misses & 0xffffffff; - case VX_CSR_MPM_DCACHE_MISS_R_H: return proc_perf.clusters.dcache.read_misses >> 32; - case VX_CSR_MPM_DCACHE_MISS_W: return proc_perf.clusters.dcache.write_misses & 0xffffffff; - case VX_CSR_MPM_DCACHE_MISS_W_H: return proc_perf.clusters.dcache.write_misses >> 32; - case VX_CSR_MPM_DCACHE_BANK_ST: return proc_perf.clusters.dcache.bank_stalls & 0xffffffff; - case VX_CSR_MPM_DCACHE_BANK_ST_H: return proc_perf.clusters.dcache.bank_stalls >> 32; - case VX_CSR_MPM_DCACHE_MSHR_ST: return proc_perf.clusters.dcache.mshr_stalls & 0xffffffff; - case VX_CSR_MPM_DCACHE_MSHR_ST_H: return proc_perf.clusters.dcache.mshr_stalls >> 32; + case VX_CSR_MPM_DCACHE_READS: return socket_perf.dcache.reads & 0xffffffff; + case VX_CSR_MPM_DCACHE_READS_H: return socket_perf.dcache.reads >> 32; + case VX_CSR_MPM_DCACHE_WRITES: return socket_perf.dcache.writes & 0xffffffff; + case VX_CSR_MPM_DCACHE_WRITES_H: return socket_perf.dcache.writes >> 32; + case VX_CSR_MPM_DCACHE_MISS_R: return socket_perf.dcache.read_misses & 0xffffffff; + case VX_CSR_MPM_DCACHE_MISS_R_H: return socket_perf.dcache.read_misses >> 32; + case VX_CSR_MPM_DCACHE_MISS_W: return socket_perf.dcache.write_misses & 0xffffffff; + case VX_CSR_MPM_DCACHE_MISS_W_H: return socket_perf.dcache.write_misses >> 32; + case VX_CSR_MPM_DCACHE_BANK_ST: return socket_perf.dcache.bank_stalls & 0xffffffff; + case VX_CSR_MPM_DCACHE_BANK_ST_H: return socket_perf.dcache.bank_stalls >> 32; + case VX_CSR_MPM_DCACHE_MSHR_ST: return socket_perf.dcache.mshr_stalls & 0xffffffff; + case VX_CSR_MPM_DCACHE_MSHR_ST_H: return socket_perf.dcache.mshr_stalls >> 32; case VX_CSR_MPM_L2CACHE_READS: return proc_perf.clusters.l2cache.reads & 0xffffffff; case VX_CSR_MPM_L2CACHE_READS_H: return proc_perf.clusters.l2cache.reads >> 32; @@ -641,12 +644,12 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { case VX_CSR_MPM_MEM_LT: return proc_perf.mem_latency & 0xffffffff; case VX_CSR_MPM_MEM_LT_H : return proc_perf.mem_latency >> 32; - case VX_CSR_MPM_SMEM_READS: return proc_perf.clusters.sharedmem.reads & 0xffffffff; - case VX_CSR_MPM_SMEM_READS_H: return proc_perf.clusters.sharedmem.reads >> 32; - case VX_CSR_MPM_SMEM_WRITES: return proc_perf.clusters.sharedmem.writes & 0xffffffff; - case VX_CSR_MPM_SMEM_WRITES_H: return proc_perf.clusters.sharedmem.writes >> 32; - case VX_CSR_MPM_SMEM_BANK_ST: return proc_perf.clusters.sharedmem.bank_stalls & 0xffffffff; - case VX_CSR_MPM_SMEM_BANK_ST_H: return proc_perf.clusters.sharedmem.bank_stalls >> 32; + case VX_CSR_MPM_SMEM_READS: return smem_perf.reads & 0xffffffff; + case VX_CSR_MPM_SMEM_READS_H: return smem_perf.reads >> 32; + case VX_CSR_MPM_SMEM_WRITES: return smem_perf.writes & 0xffffffff; + case VX_CSR_MPM_SMEM_WRITES_H: return smem_perf.writes >> 32; + case VX_CSR_MPM_SMEM_BANK_ST: return smem_perf.bank_stalls & 0xffffffff; + case VX_CSR_MPM_SMEM_BANK_ST_H: return smem_perf.bank_stalls >> 32; } } break; } diff --git a/sim/simx/core.h b/sim/simx/core.h index cef60e81..343fdb31 100644 --- a/sim/simx/core.h +++ b/sim/simx/core.h @@ -40,7 +40,7 @@ namespace vortex { -class Cluster; +class Socket; using TraceSwitch = Mux; @@ -53,10 +53,6 @@ public: uint64_t sched_stalls; uint64_t ibuf_stalls; uint64_t scrb_stalls; - uint64_t alu_stalls; - uint64_t lsu_stalls; - uint64_t fpu_stalls; - uint64_t sfu_stalls; uint64_t scrb_alu; uint64_t scrb_fpu; uint64_t scrb_lsu; @@ -74,10 +70,6 @@ public: , sched_stalls(0) , ibuf_stalls(0) , scrb_stalls(0) - , alu_stalls(0) - , lsu_stalls(0) - , fpu_stalls(0) - , sfu_stalls(0) , scrb_alu(0) , scrb_fpu(0) , scrb_lsu(0) @@ -96,12 +88,7 @@ public: std::vector> dcache_req_ports; std::vector> dcache_rsp_ports; - Core(const SimContext& ctx, - uint32_t core_id, - Cluster* cluster, - const Arch &arch, - const DCRS &dcrs, - SharedMem::Ptr sharedmem); + Core(const SimContext& ctx, uint32_t core_id, Socket* socket, const Arch &arch, const DCRS &dcrs); ~Core(); @@ -119,6 +106,10 @@ public: return core_id_; } + Socket* socket() const { + return socket_; + } + const Arch& arch() const { return arch_; } @@ -181,7 +172,8 @@ private: std::vector operands_; std::vector dispatchers_; std::vector exe_units_; - SharedMem::Ptr sharedmem_; + SharedMem::Ptr shared_mem_; + std::vector smem_demuxs_; PipelineLatch fetch_latch_; PipelineLatch decode_latch_; @@ -201,7 +193,7 @@ private: PerfStats perf_stats_; - Cluster* cluster_; + Socket* socket_; std::vector commit_arbs_; diff --git a/sim/simx/exe_unit.cpp b/sim/simx/exe_unit.cpp index 2f3e79e3..4b5cb356 100644 --- a/sim/simx/exe_unit.cpp +++ b/sim/simx/exe_unit.cpp @@ -51,8 +51,7 @@ void AluUnit::tick() { assert(core_->stalled_warps_.test(trace->wid)); core_->stalled_warps_.reset(trace->wid); } - auto time = input.pop(); - core_->perf_stats_.alu_stalls += (SimPlatform::instance().cycles() - time); + input.pop(); } } @@ -87,8 +86,7 @@ void FpuUnit::tick() { std::abort(); } DT(3, "pipeline-execute: op=" << trace->fpu_type << ", " << *trace); - auto time = input.pop(); - core_->perf_stats_.fpu_stalls += (SimPlatform::instance().cycles() - time); + input.pop(); } } @@ -114,7 +112,7 @@ void LsuUnit::tick() { // handle dcache response for (uint32_t t = 0; t < num_lanes_; ++t) { - auto& dcache_rsp_port = core_->dcache_rsp_ports.at(t); + auto& dcache_rsp_port = core_->smem_demuxs_.at(t)->RspIn; if (dcache_rsp_port.empty()) continue; auto& mem_rsp = dcache_rsp_port.front(); @@ -136,7 +134,7 @@ void LsuUnit::tick() { // handle shared memory response for (uint32_t t = 0; t < num_lanes_; ++t) { - auto& smem_rsp_port = core_->sharedmem_->Outputs.at(t); + auto& smem_rsp_port = core_->shared_mem_->Outputs.at(t); if (smem_rsp_port.empty()) continue; auto& mem_rsp = smem_rsp_port.front(); @@ -184,8 +182,7 @@ void LsuUnit::tick() { fence_lock_ = true; DT(3, "fence-lock: " << *trace); // remove input - auto time = input.pop(); - core_->perf_stats_.lsu_stalls += (SimPlatform::instance().cycles() - time); + input.pop(); break; } @@ -213,7 +210,9 @@ void LsuUnit::tick() { auto mem_addr = trace_data->mem_addrs.at(t).addr & ~addr_mask; matches += (addr0 == mem_addr); } + #ifdef LSU_DUP_ENABLE is_dup = (matches == trace->tmask.count()); + #endif } uint32_t addr_count; @@ -229,7 +228,7 @@ void LsuUnit::tick() { if (!trace->tmask.test(t0 + t)) continue; - auto& dcache_req_port = core_->dcache_req_ports.at(t); + auto& dcache_req_port = core_->smem_demuxs_.at(t)->ReqIn; auto mem_addr = trace_data->mem_addrs.at(t); auto type = core_->get_addr_type(mem_addr.addr); @@ -241,12 +240,16 @@ void LsuUnit::tick() { mem_req.cid = trace->cid; mem_req.uuid = trace->uuid; - dcache_req_port.send(mem_req, 2); + dcache_req_port.send(mem_req, 1); DT(3, "dcache-req: addr=0x" << std::hex << mem_req.addr << ", tag=" << tag << ", lsu_type=" << trace->lsu_type << ", tid=" << t << ", addr_type=" << mem_req.type << ", " << *trace); - ++pending_loads_; - ++core_->perf_stats_.loads; + if (is_write) { + ++core_->perf_stats_.stores; + } else { + ++core_->perf_stats_.loads; + ++pending_loads_; + } if (is_dup) break; } @@ -254,13 +257,11 @@ void LsuUnit::tick() { // do not wait on writes if (is_write) { pending_rd_reqs_.release(tag); - output.send(trace, 1); - ++core_->perf_stats_.stores; + output.send(trace, 1); } // remove input - auto time = input.pop(); - core_->perf_stats_.lsu_stalls += (SimPlatform::instance().cycles() - time); + input.pop(); break; // single block } @@ -318,10 +319,7 @@ void SfuUnit::tick() { core_->stalled_warps_.reset(trace->wid); } - auto time = input.pop(); - auto stalls = (SimPlatform::instance().cycles() - time); - - core_->perf_stats_.sfu_stalls += stalls; + input.pop(); break; // single block } diff --git a/sim/simx/main.cpp b/sim/simx/main.cpp index 22d9c880..64031bb8 100644 --- a/sim/simx/main.cpp +++ b/sim/simx/main.cpp @@ -34,14 +34,13 @@ static void show_usage() { uint32_t num_threads = NUM_THREADS; uint32_t num_warps = NUM_WARPS; uint32_t num_cores = NUM_CORES; -uint32_t num_clusters = NUM_CLUSTERS; bool showStats = false;; bool riscv_test = false; const char* program = nullptr; static void parse_args(int argc, char **argv) { int c; - while ((c = getopt(argc, argv, "t:w:c:g:rsh?")) != -1) { + while ((c = getopt(argc, argv, "t:w:c:rsh?")) != -1) { switch (c) { case 't': num_threads = atoi(optarg); @@ -51,9 +50,6 @@ static void parse_args(int argc, char **argv) { break; case 'c': num_cores = atoi(optarg); - break; - case 'g': - num_clusters = atoi(optarg); break; case 'r': riscv_test = true; @@ -88,7 +84,7 @@ int main(int argc, char **argv) { { // create processor configuation - Arch arch(num_threads, num_warps, num_cores, num_clusters); + Arch arch(num_threads, num_warps, num_cores); // create memory module RAM ram(RAM_PAGE_SIZE); diff --git a/sim/simx/socket.cpp b/sim/simx/socket.cpp new file mode 100644 index 00000000..fb620d62 --- /dev/null +++ b/sim/simx/socket.cpp @@ -0,0 +1,146 @@ +// Copyright © 2019-2023 +// +// Licensed 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. + +#include "socket.h" +#include "cluster.h" + +using namespace vortex; + +Socket::Socket(const SimContext& ctx, + uint32_t socket_id, + Cluster* cluster, + const Arch &arch, const + DCRS &dcrs) + : SimObject(ctx, "socket") + , icache_mem_req_port(this) + , icache_mem_rsp_port(this) + , dcache_mem_req_port(this) + , dcache_mem_rsp_port(this) + , socket_id_(socket_id) + , cores_(arch.socket_size()) + , cluster_(cluster) +{ + auto cores_per_socket = cores_.size(); + + char sname[100]; + snprintf(sname, 100, "socket%d-icaches", socket_id); + icaches_ = CacheCluster::Create(sname, cores_per_socket, NUM_ICACHES, 1, CacheSim::Config{ + !ICACHE_ENABLED, + log2ceil(ICACHE_SIZE), // C + log2ceil(L1_LINE_SIZE), // L + log2ceil(sizeof(uint32_t)), // W + log2ceil(ICACHE_NUM_WAYS),// A + 1, // B + XLEN, // address bits + 1, // number of ports + 1, // number of inputs + true, // write-through + false, // write response + (uint8_t)arch.num_warps(), // mshr + 2, // pipeline latency + }); + + icaches_->MemReqPort.bind(&icache_mem_req_port); + icache_mem_rsp_port.bind(&icaches_->MemRspPort); + + snprintf(sname, 100, "socket%d-dcaches", socket_id); + dcaches_ = CacheCluster::Create(sname, cores_per_socket, NUM_DCACHES, NUM_LSU_LANES, CacheSim::Config{ + !DCACHE_ENABLED, + log2ceil(DCACHE_SIZE), // C + log2ceil(L1_LINE_SIZE), // L + log2ceil(sizeof(Word)), // W + log2ceil(DCACHE_NUM_WAYS),// A + log2ceil(DCACHE_NUM_BANKS), // B + XLEN, // address bits + 1, // number of ports + DCACHE_NUM_BANKS, // number of inputs + true, // write-through + false, // write response + DCACHE_MSHR_SIZE, // mshr + 2, // pipeline latency + }); + + dcaches_->MemReqPort.bind(&dcache_mem_req_port); + dcache_mem_rsp_port.bind(&dcaches_->MemRspPort); + + // create cores + + for (uint32_t i = 0; i < cores_per_socket; ++i) { + uint32_t core_id = socket_id * cores_per_socket + i; + cores_.at(i) = Core::Create(core_id, this, arch, dcrs); + + cores_.at(i)->icache_req_ports.at(0).bind(&icaches_->CoreReqPorts.at(i).at(0)); + icaches_->CoreRspPorts.at(i).at(0).bind(&cores_.at(i)->icache_rsp_ports.at(0)); + + for (uint32_t j = 0; j < NUM_LSU_LANES; ++j) { + cores_.at(i)->dcache_req_ports.at(j).bind(&dcaches_->CoreReqPorts.at(i).at(j)); + dcaches_->CoreRspPorts.at(i).at(j).bind(&cores_.at(i)->dcache_rsp_ports.at(j)); + } + } +} + +Socket::~Socket() { + //-- +} + +void Socket::reset() { + //-- +} + +void Socket::tick() { + //-- +} + +void Socket::attach_ram(RAM* ram) { + for (auto core : cores_) { + core->attach_ram(ram); + } +} + +bool Socket::running() const { + for (auto& core : cores_) { + if (core->running()) + return true; + } + return false; +} + +bool Socket::check_exit(Word* exitcode, bool riscv_test) const { + bool done = true; + Word exitcode_ = 0; + for (auto& core : cores_) { + Word ec; + if (core->check_exit(&ec, riscv_test)) { + exitcode_ |= ec; + } else { + done = false; + } + } + *exitcode = exitcode_; + return done; +} + +void Socket::barrier(uint32_t bar_id, uint32_t count, uint32_t core_id) { + cluster_->barrier(bar_id, count, socket_id_ * cores_.size() + core_id); +} + +void Socket::resume(uint32_t core_index) { + cores_.at(core_index)->resume(); +} + +Socket::PerfStats Socket::perf_stats() const { + Socket::PerfStats perf; + perf.icache = icaches_->perf_stats(); + perf.dcache = dcaches_->perf_stats(); + return perf; +} \ No newline at end of file diff --git a/sim/simx/socket.h b/sim/simx/socket.h new file mode 100644 index 00000000..5c94c31f --- /dev/null +++ b/sim/simx/socket.h @@ -0,0 +1,87 @@ +// Copyright © 2019-2023 +// +// Licensed 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. + +#pragma once + +#include +#include "dcrs.h" +#include "arch.h" +#include "cache_cluster.h" +#include "shared_mem.h" +#include "core.h" +#include "constants.h" + +namespace vortex { + +class Cluster; + +class Socket : public SimObject { +public: + struct PerfStats { + CacheSim::PerfStats icache; + CacheSim::PerfStats dcache; + + PerfStats& operator+=(const PerfStats& rhs) { + this->icache += rhs.icache; + this->dcache += rhs.dcache; + return *this; + } + }; + + SimPort icache_mem_req_port; + SimPort icache_mem_rsp_port; + + SimPort dcache_mem_req_port; + SimPort dcache_mem_rsp_port; + + Socket(const SimContext& ctx, + uint32_t socket_id, + Cluster* cluster, + const Arch &arch, + const DCRS &dcrs); + + ~Socket(); + + uint32_t id() const { + return socket_id_; + } + + Cluster* cluster() const { + return cluster_; + } + + void reset(); + + void tick(); + + void attach_ram(RAM* ram); + + bool running() const; + + bool check_exit(Word* exitcode, bool riscv_test) const; + + void barrier(uint32_t bar_id, uint32_t count, uint32_t core_id); + + void resume(uint32_t core_id); + + Socket::PerfStats perf_stats() const; + +private: + uint32_t socket_id_; + std::vector cores_; + CacheCluster::Ptr icaches_; + CacheCluster::Ptr dcaches_; + Cluster* cluster_; +}; + +} // namespace vortex \ No newline at end of file diff --git a/sim/simx/types.h b/sim/simx/types.h index 6bba7f9c..d3fcfa1a 100644 --- a/sim/simx/types.h +++ b/sim/simx/types.h @@ -70,6 +70,7 @@ inline std::ostream &operator<<(std::ostream &os, const RegType& type) { case RegType::Integer: os << "x"; break; case RegType::Float: os << "f"; break; case RegType::Vector: os << "v"; break; + default: assert(false); } return os; } @@ -112,6 +113,7 @@ inline std::ostream &operator<<(std::ostream &os, const AluType& type) { case AluType::SYSCALL: os << "SYSCALL"; break; case AluType::IMUL: os << "IMUL"; break; case AluType::IDIV: os << "IDIV"; break; + default: assert(false); } return os; } @@ -129,6 +131,7 @@ inline std::ostream &operator<<(std::ostream &os, const LsuType& type) { case LsuType::LOAD: os << "LOAD"; break; case LsuType::STORE: os << "STORE"; break; case LsuType::FENCE: os << "FENCE"; break; + default: assert(false); } return os; } @@ -146,6 +149,7 @@ inline std::ostream &operator<<(std::ostream &os, const AddrType& type) { case AddrType::Global: os << "Global"; break; case AddrType::Shared: os << "Shared"; break; case AddrType::IO: os << "IO"; break; + default: assert(false); } return os; } @@ -174,6 +178,7 @@ inline std::ostream &operator<<(std::ostream &os, const FpuType& type) { case FpuType::FDIV: os << "FDIV"; break; case FpuType::FSQRT: os << "FSQRT"; break; case FpuType::FCVT: os << "FCVT"; break; + default: assert(false); } return os; } @@ -205,6 +210,7 @@ inline std::ostream &operator<<(std::ostream &os, const SfuType& type) { case SfuType::CSRRS: os << "CSRRS"; break; case SfuType::CSRRC: os << "CSRRC"; break; case SfuType::CMOV: os << "CMOV"; break; + default: assert(false); } return os; } @@ -220,6 +226,7 @@ inline std::ostream &operator<<(std::ostream &os, const ArbiterType& type) { switch (type) { case ArbiterType::Priority: os << "Priority"; break; case ArbiterType::RoundRobin: os << "RoundRobin"; break; + default: assert(false); } return os; } From e217bc2c23c673abc9d4ae67e7d5bed399396561 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Thu, 28 Dec 2023 12:12:11 -0800 Subject: [PATCH 33/57] adding tracking for SFU stalls --- hw/rtl/VX_cluster.sv | 145 ++-- hw/rtl/VX_define.vh | 869 ++++++++++++----------- hw/rtl/VX_gpu_pkg.sv | 5 +- hw/rtl/VX_socket.sv | 15 +- hw/rtl/VX_types.vh | 5 + hw/rtl/Vortex.sv | 24 +- hw/rtl/cache/VX_cache_cluster.sv | 5 +- hw/rtl/cache/VX_cache_define.vh | 12 + hw/rtl/core/VX_core.sv | 682 +++++++++--------- hw/rtl/core/VX_core_top.sv | 6 +- hw/rtl/core/VX_csr_data.sv | 171 ++--- hw/rtl/core/VX_csr_unit.sv | 2 - hw/rtl/core/VX_issue.sv | 3 +- hw/rtl/core/VX_scoreboard.sv | 136 ++-- hw/rtl/core/VX_sfu_unit.sv | 35 +- hw/rtl/interfaces/VX_pipeline_perf_if.sv | 9 +- runtime/common/utils.cpp | 81 ++- sim/simx/cluster.cpp | 21 +- sim/simx/cluster.h | 22 +- sim/simx/core.cpp | 95 ++- sim/simx/core.h | 18 +- sim/simx/processor.cpp | 4 +- sim/simx/processor_impl.h | 13 +- sim/simx/scoreboard.h | 7 +- sim/simx/socket.cpp | 19 +- sim/simx/socket.h | 12 +- tests/opencl/Makefile | 16 +- 27 files changed, 1266 insertions(+), 1166 deletions(-) diff --git a/hw/rtl/VX_cluster.sv b/hw/rtl/VX_cluster.sv index 6de47c5f..2d220c24 100644 --- a/hw/rtl/VX_cluster.sv +++ b/hw/rtl/VX_cluster.sv @@ -43,7 +43,16 @@ module VX_cluster import VX_gpu_pkg::*; #( `ifdef SCOPE localparam scope_socket = 0; `SCOPE_IO_SWITCH (scope_socket + `NUM_SOCKETS); -`endif +`endif + +`ifdef PERF_ENABLE + VX_mem_perf_if mem_perf_tmp_if(); + assign mem_perf_tmp_if.icache = 'x; + assign mem_perf_tmp_if.dcache = 'x; + assign mem_perf_tmp_if.l3cache = mem_perf_if.l3cache; + assign mem_perf_tmp_if.smem = 'x; + assign mem_perf_tmp_if.mem = mem_perf_if.mem; +`endif `ifdef GBAR_ENABLE @@ -69,24 +78,68 @@ module VX_cluster import VX_gpu_pkg::*; #( .reset (gbar_reset), .gbar_bus_if (gbar_bus_if) ); -`endif -`ifdef PERF_ENABLE - VX_mem_perf_if mem_perf_tmp_if(); - cache_perf_t perf_l2cache; - - assign mem_perf_tmp_if.icache = 'x; - assign mem_perf_tmp_if.dcache = 'x; - assign mem_perf_tmp_if.l2cache = perf_l2cache; - assign mem_perf_tmp_if.l3cache = mem_perf_if.l3cache; - assign mem_perf_tmp_if.smem = 'x; - assign mem_perf_tmp_if.mem = mem_perf_if.mem; `endif VX_mem_bus_if #( - .DATA_SIZE (`L1_LINE_SIZE), - .TAG_WIDTH (L1_MEM_TAG_WIDTH) - ) l1_mem_bus_if[2](); + .DATA_SIZE (L2_WORD_SIZE), + .TAG_WIDTH (L2_TAG_WIDTH) + ) l2_mem_bus_if[L2_NUM_REQS](); + + VX_mem_bus_if #( + .DATA_SIZE (ICACHE_LINE_SIZE), + .TAG_WIDTH (ICACHE_MEM_TAG_WIDTH) + ) per_socket_icache_mem_bus_if[`NUM_SOCKETS](); + + VX_mem_bus_if #( + .DATA_SIZE (DCACHE_LINE_SIZE), + .TAG_WIDTH (DCACHE_MEM_TAG_WIDTH) + ) per_socket_dcache_mem_bus_if[`NUM_SOCKETS](); + + VX_mem_bus_if #( + .DATA_SIZE (ICACHE_LINE_SIZE), + .TAG_WIDTH (ICACHE_MEM_ARB_TAG_WIDTH) + ) icache_mem_bus_if[1](); + + VX_mem_bus_if #( + .DATA_SIZE (DCACHE_LINE_SIZE), + .TAG_WIDTH (DCACHE_MEM_ARB_TAG_WIDTH) + ) dcache_mem_bus_if[1](); + + `RESET_RELAY (l1_mem_arb_reset, reset); + + VX_mem_arb #( + .NUM_INPUTS (`NUM_SOCKETS), + .DATA_SIZE (ICACHE_LINE_SIZE), + .TAG_WIDTH (ICACHE_MEM_TAG_WIDTH), + .TAG_SEL_IDX (1), // Skip 0 for NC flag + .ARBITER ("R"), + .OUT_REG_REQ (2), + .OUT_REG_RSP (2) + ) icache_mem_arb ( + .clk (clk), + .reset (l1_mem_arb_reset), + .bus_in_if (per_socket_icache_mem_bus_if), + .bus_out_if (icache_mem_bus_if) + ); + + VX_mem_arb #( + .NUM_INPUTS (`NUM_SOCKETS), + .DATA_SIZE (DCACHE_LINE_SIZE), + .TAG_WIDTH (DCACHE_MEM_TAG_WIDTH), + .TAG_SEL_IDX (1), // Skip 0 for NC flag + .ARBITER ("R"), + .OUT_REG_REQ (2), + .OUT_REG_RSP (2) + ) dcache_mem_arb ( + .clk (clk), + .reset (l1_mem_arb_reset), + .bus_in_if (per_socket_dcache_mem_bus_if), + .bus_out_if (dcache_mem_bus_if) + ); + + `ASSIGN_VX_MEM_BUS_IF_X (l2_mem_bus_if[ICACHE_MEM_ARB_IDX], icache_mem_bus_if[0], L1_MEM_TAG_WIDTH, ICACHE_MEM_ARB_TAG_WIDTH); + `ASSIGN_VX_MEM_BUS_IF_X (l2_mem_bus_if[DCACHE_MEM_ARB_IDX], dcache_mem_bus_if[0], L1_MEM_TAG_WIDTH, DCACHE_MEM_ARB_TAG_WIDTH); `RESET_RELAY (l2_reset, reset); @@ -113,67 +166,12 @@ module VX_cluster import VX_gpu_pkg::*; #( .clk (clk), .reset (l2_reset), `ifdef PERF_ENABLE - .cache_perf (perf_l2cache), + .cache_perf (mem_perf_tmp_if.l2cache), `endif - .core_bus_if (l1_mem_bus_if), + .core_bus_if (l2_mem_bus_if), .mem_bus_if (mem_bus_if) ); - VX_mem_bus_if #( - .DATA_SIZE (`L1_LINE_SIZE), - .TAG_WIDTH (ICACHE_MEM_TAG_WIDTH) - ) per_socket_icache_mem_bus_if[`NUM_SOCKETS](); - - VX_mem_bus_if #( - .DATA_SIZE (`L1_LINE_SIZE), - .TAG_WIDTH (DCACHE_MEM_TAG_WIDTH) - ) per_socket_dcache_mem_bus_if[`NUM_SOCKETS](); - - VX_mem_bus_if #( - .DATA_SIZE (ICACHE_LINE_SIZE), - .TAG_WIDTH (ICACHE_MEM_ARB_TAG_WIDTH) - ) icache_mem_bus_if[1](); - - VX_mem_bus_if #( - .DATA_SIZE (DCACHE_LINE_SIZE), - .TAG_WIDTH (DCACHE_MEM_ARB_TAG_WIDTH) - ) dcache_mem_bus_if[1](); - - `RESET_RELAY (l1_mem_arb_reset, reset); - - VX_mem_arb #( - .NUM_INPUTS (`NUM_SOCKETS), - .DATA_SIZE (`L1_LINE_SIZE), - .TAG_WIDTH (ICACHE_MEM_TAG_WIDTH), - .TAG_SEL_IDX (1), // Skip 0 for NC flag - .ARBITER ("R"), - .OUT_REG_REQ (2), - .OUT_REG_RSP (2) - ) icache_mem_arb ( - .clk (clk), - .reset (l1_mem_arb_reset), - .bus_in_if (per_socket_icache_mem_bus_if), - .bus_out_if (icache_mem_bus_if) - ); - - VX_mem_arb #( - .NUM_INPUTS (`NUM_SOCKETS), - .DATA_SIZE (`L1_LINE_SIZE), - .TAG_WIDTH (DCACHE_MEM_TAG_WIDTH), - .TAG_SEL_IDX (1), // Skip 0 for NC flag - .ARBITER ("R"), - .OUT_REG_REQ (2), - .OUT_REG_RSP (2) - ) dcache_mem_arb ( - .clk (clk), - .reset (l1_mem_arb_reset), - .bus_in_if (per_socket_dcache_mem_bus_if), - .bus_out_if (dcache_mem_bus_if) - ); - - `ASSIGN_VX_MEM_BUS_IF_X (l1_mem_bus_if[0], icache_mem_bus_if[0], L1_MEM_TAG_WIDTH, ICACHE_MEM_ARB_TAG_WIDTH); - `ASSIGN_VX_MEM_BUS_IF_X (l1_mem_bus_if[1], dcache_mem_bus_if[0], L1_MEM_TAG_WIDTH, DCACHE_MEM_ARB_TAG_WIDTH); - /////////////////////////////////////////////////////////////////////////// wire [`NUM_SOCKETS-1:0] per_socket_sim_ebreak; @@ -201,6 +199,7 @@ module VX_cluster import VX_gpu_pkg::*; #( .SOCKET_ID ((CLUSTER_ID * `NUM_SOCKETS) + i) ) socket ( `SCOPE_IO_BIND (scope_socket+i) + .clk (clk), .reset (socket_reset), @@ -212,7 +211,7 @@ module VX_cluster import VX_gpu_pkg::*; #( .icache_mem_bus_if (per_socket_icache_mem_bus_if[i]), .dcache_mem_bus_if (per_socket_dcache_mem_bus_if[i]), - + `ifdef GBAR_ENABLE .gbar_bus_if (per_socket_gbar_bus_if[i]), `endif diff --git a/hw/rtl/VX_define.vh b/hw/rtl/VX_define.vh index f39e7fea..63f2d42d 100644 --- a/hw/rtl/VX_define.vh +++ b/hw/rtl/VX_define.vh @@ -1,432 +1,437 @@ -// Copyright © 2019-2023 -// -// Licensed 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. - -`ifndef VX_DEFINE_VH -`define VX_DEFINE_VH - -`include "VX_platform.vh" -`include "VX_config.vh" -`include "VX_types.vh" - -/////////////////////////////////////////////////////////////////////////////// - -`define NW_BITS `CLOG2(`NUM_WARPS) -`define NC_WIDTH `UP(`NC_BITS) - -`define NT_BITS `CLOG2(`NUM_THREADS) -`define NW_WIDTH `UP(`NW_BITS) - -`define NC_BITS `CLOG2(`NUM_CORES) -`define NT_WIDTH `UP(`NT_BITS) - -`define NB_BITS `CLOG2(`NUM_BARRIERS) -`define NB_WIDTH `UP(`NB_BITS) - -`define NUM_IREGS 32 - -`define NRI_BITS `CLOG2(`NUM_IREGS) - -`ifdef EXT_F_ENABLE -`define NUM_REGS (2 * `NUM_IREGS) -`else -`define NUM_REGS `NUM_IREGS -`endif - -`define NR_BITS `CLOG2(`NUM_REGS) - -`define PERF_CTR_BITS 44 - -`ifndef NDEBUG -`define UUID_WIDTH 44 -`else -`define UUID_WIDTH 1 -`endif - -/////////////////////////////////////////////////////////////////////////////// - -`define EX_ALU 0 -`define EX_LSU 1 -`define EX_SFU 2 -`define EX_FPU 3 - -`define NUM_EX_UNITS (3 + `EXT_F_ENABLED) -`define EX_BITS `CLOG2(`NUM_EX_UNITS) - -/////////////////////////////////////////////////////////////////////////////// - -`define INST_LUI 7'b0110111 -`define INST_AUIPC 7'b0010111 -`define INST_JAL 7'b1101111 -`define INST_JALR 7'b1100111 -`define INST_B 7'b1100011 // branch instructions -`define INST_L 7'b0000011 // load instructions -`define INST_S 7'b0100011 // store instructions -`define INST_I 7'b0010011 // immediate instructions -`define INST_R 7'b0110011 // register instructions -`define INST_FENCE 7'b0001111 // Fence instructions -`define INST_SYS 7'b1110011 // system instructions - -// RV64I instruction specific opcodes (for any W instruction) -`define INST_I_W 7'b0011011 // W type immediate instructions -`define INST_R_W 7'b0111011 // W type register instructions - -`define INST_FL 7'b0000111 // float load instruction -`define INST_FS 7'b0100111 // float store instruction -`define INST_FMADD 7'b1000011 -`define INST_FMSUB 7'b1000111 -`define INST_FNMSUB 7'b1001011 -`define INST_FNMADD 7'b1001111 -`define INST_FCI 7'b1010011 // float common instructions - -// Custom extension opcodes -`define INST_EXT1 7'b0001011 // 0x0B -`define INST_EXT2 7'b0101011 // 0x2B -`define INST_EXT3 7'b1011011 // 0x5B -`define INST_EXT4 7'b1111011 // 0x7B - -/////////////////////////////////////////////////////////////////////////////// - -`define INST_FRM_RNE 3'b000 // round to nearest even -`define INST_FRM_RTZ 3'b001 // round to zero -`define INST_FRM_RDN 3'b010 // round to -inf -`define INST_FRM_RUP 3'b011 // round to +inf -`define INST_FRM_RMM 3'b100 // round to nearest max magnitude -`define INST_FRM_DYN 3'b111 // dynamic mode -`define INST_FRM_BITS 3 - -/////////////////////////////////////////////////////////////////////////////// - -`define INST_OP_BITS 4 -`define INST_MOD_BITS 3 -`define INST_FMT_BITS 2 - -/////////////////////////////////////////////////////////////////////////////// - -`define INST_ALU_ADD 4'b0000 -`define INST_ALU_LUI 4'b0010 -`define INST_ALU_AUIPC 4'b0011 -`define INST_ALU_SLTU 4'b0100 -`define INST_ALU_SLT 4'b0101 -`define INST_ALU_SUB 4'b0111 -`define INST_ALU_SRL 4'b1000 -`define INST_ALU_SRA 4'b1001 -`define INST_ALU_AND 4'b1100 -`define INST_ALU_OR 4'b1101 -`define INST_ALU_XOR 4'b1110 -`define INST_ALU_SLL 4'b1111 -`define INST_ALU_OTHER 4'b0111 -`define INST_ALU_BITS 4 -`define INST_ALU_CLASS(op) op[3:2] -`define INST_ALU_SIGNED(op) op[0] -`define INST_ALU_IS_SUB(op) op[1] -`define INST_ALU_IS_BR(mod) mod[0] -`define INST_ALU_IS_M(mod) mod[1] -`define INST_ALU_IS_W(mod) mod[2] - -`define INST_BR_EQ 4'b0000 -`define INST_BR_NE 4'b0010 -`define INST_BR_LTU 4'b0100 -`define INST_BR_GEU 4'b0110 -`define INST_BR_LT 4'b0101 -`define INST_BR_GE 4'b0111 -`define INST_BR_JAL 4'b1000 -`define INST_BR_JALR 4'b1001 -`define INST_BR_ECALL 4'b1010 -`define INST_BR_EBREAK 4'b1011 -`define INST_BR_URET 4'b1100 -`define INST_BR_SRET 4'b1101 -`define INST_BR_MRET 4'b1110 -`define INST_BR_OTHER 4'b1111 -`define INST_BR_BITS 4 -`define INST_BR_CLASS(op) {1'b0, ~op[3]} -`define INST_BR_IS_NEG(op) op[1] -`define INST_BR_IS_LESS(op) op[2] -`define INST_BR_IS_STATIC(op) op[3] - -`define INST_M_MUL 3'b000 -`define INST_M_MULHU 3'b001 -`define INST_M_MULH 3'b010 -`define INST_M_MULHSU 3'b011 -`define INST_M_DIV 3'b100 -`define INST_M_DIVU 3'b101 -`define INST_M_REM 3'b110 -`define INST_M_REMU 3'b111 -`define INST_M_BITS 3 -`define INST_M_SIGNED(op) (~op[0]) -`define INST_M_IS_MULX(op) (~op[2]) -`define INST_M_IS_MULH(op) (op[1:0] != 0) -`define INST_M_SIGNED_A(op) (op[1:0] != 1) -`define INST_M_IS_REM(op) op[1] - -`define INST_FMT_B 3'b000 -`define INST_FMT_H 3'b001 -`define INST_FMT_W 3'b010 -`define INST_FMT_D 3'b011 -`define INST_FMT_BU 3'b100 -`define INST_FMT_HU 3'b101 -`define INST_FMT_WU 3'b110 - -`define INST_LSU_LB 4'b0000 -`define INST_LSU_LH 4'b0001 -`define INST_LSU_LW 4'b0010 -`define INST_LSU_LD 4'b0011 // new for RV64I LD -`define INST_LSU_LBU 4'b0100 -`define INST_LSU_LHU 4'b0101 -`define INST_LSU_LWU 4'b0110 // new for RV64I LWU -`define INST_LSU_SB 4'b1000 -`define INST_LSU_SH 4'b1001 -`define INST_LSU_SW 4'b1010 -`define INST_LSU_SD 4'b1011 // new for RV64I SD -`define INST_LSU_FENCE 4'b1111 -`define INST_LSU_BITS 4 -`define INST_LSU_FMT(op) op[2:0] -`define INST_LSU_WSIZE(op) op[1:0] -`define INST_LSU_IS_FENCE(op) (op[3:2] == 3) - -`define INST_FENCE_BITS 1 -`define INST_FENCE_D 1'h0 -`define INST_FENCE_I 1'h1 - -`define INST_FPU_ADD 4'b0000 -`define INST_FPU_SUB 4'b0001 -`define INST_FPU_MUL 4'b0010 -`define INST_FPU_DIV 4'b0011 -`define INST_FPU_SQRT 4'b0100 -`define INST_FPU_CMP 4'b0101 // mod: LE=0, LT=1, EQ=2 -`define INST_FPU_F2F 4'b0110 -`define INST_FPU_MISC 4'b0111 // mod: SGNJ=0, SGNJN=1, SGNJX=2, CLASS=3, MVXW=4, MVWX=5, FMIN=6, FMAX=7 -`define INST_FPU_F2I 4'b1000 -`define INST_FPU_F2U 4'b1001 -`define INST_FPU_I2F 4'b1010 -`define INST_FPU_U2F 4'b1011 -`define INST_FPU_MADD 4'b1100 -`define INST_FPU_MSUB 4'b1101 -`define INST_FPU_NMSUB 4'b1110 -`define INST_FPU_NMADD 4'b1111 -`define INST_FPU_BITS 4 -`define INST_FPU_IS_W(mod) (mod[4]) -`define INST_FPU_IS_CLASS(op, mod) (op == `INST_FPU_MISC && mod == 3) -`define INST_FPU_IS_MVXW(op, mod) (op == `INST_FPU_MISC && mod == 4) - -`define INST_SFU_TMC 4'h0 -`define INST_SFU_WSPAWN 4'h1 -`define INST_SFU_SPLIT 4'h2 -`define INST_SFU_JOIN 4'h3 -`define INST_SFU_BAR 4'h4 -`define INST_SFU_PRED 4'h5 -`define INST_SFU_CSRRW 4'h6 -`define INST_SFU_CSRRS 4'h7 -`define INST_SFU_CSRRC 4'h8 -`define INST_SFU_CMOV 4'h9 -`define INST_SFU_BITS 4 -`define INST_SFU_CSR(f3) (4'h6 + 4'(f3) - 4'h1) -`define INST_SFU_IS_WCTL(op) (op <= 5) -`define INST_SFU_IS_CSR(op) (op >= 6 && op <= 8) - -/////////////////////////////////////////////////////////////////////////////// - -// non-cacheable tag bits -`define NC_TAG_BITS 1 - -// cache address type bits -`ifdef SM_ENABLE -`define CACHE_ADDR_TYPE_BITS (`NC_TAG_BITS + 1) -`else -`define CACHE_ADDR_TYPE_BITS `NC_TAG_BITS -`endif - -`define ARB_SEL_BITS(I, O) ((I > O) ? `CLOG2((I + O - 1) / O) : 0) - -/////////////////////////////////////////////////////////////////////////////// - -`define CACHE_MEM_TAG_WIDTH(mshr_size, num_banks) \ - (`CLOG2(mshr_size) + `CLOG2(num_banks) + `NC_TAG_BITS) - -`define CACHE_NC_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, tag_width) \ - (`CLOG2(num_reqs) + `CLOG2(line_size / word_size) + tag_width) - -`define CACHE_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, tag_width) \ - (`CACHE_NC_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, tag_width) + `NC_TAG_BITS) - -`define CACHE_NC_MEM_TAG_WIDTH(mshr_size, num_banks, num_reqs, line_size, word_size, tag_width) \ - `MAX(`CACHE_MEM_TAG_WIDTH(mshr_size, num_banks), `CACHE_NC_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, tag_width)) - -/////////////////////////////////////////////////////////////////////////////// - -`define CACHE_CLUSTER_CORE_ARB_TAG(tag_width, num_inputs, num_caches) \ - (tag_width + `ARB_SEL_BITS(num_inputs, `UP(num_caches))) - -`define CACHE_CLUSTER_MEM_ARB_TAG(tag_width, num_caches) \ - (tag_width + `ARB_SEL_BITS(`UP(num_caches), 1)) - -`define CACHE_CLUSTER_MEM_TAG_WIDTH(mshr_size, num_banks, num_caches) \ - `CACHE_CLUSTER_MEM_ARB_TAG(`CACHE_MEM_TAG_WIDTH(mshr_size, num_banks), num_caches) - -`define CACHE_CLUSTER_NC_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, tag_width, num_inputs, num_caches) \ - `CACHE_CLUSTER_MEM_ARB_TAG((`CLOG2(num_reqs) + `CLOG2(line_size / word_size) + `CACHE_CLUSTER_CORE_ARB_TAG(tag_width, num_inputs, num_caches)), num_caches) - -`define CACHE_CLUSTER_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, tag_width, num_inputs, num_caches) \ - `CACHE_CLUSTER_MEM_ARB_TAG((`CACHE_NC_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, `CACHE_CLUSTER_CORE_ARB_TAG(tag_width, num_inputs, num_caches)) + `NC_TAG_BITS), num_caches) - -`define CACHE_CLUSTER_NC_MEM_TAG_WIDTH(mshr_size, num_banks, num_reqs, line_size, word_size, tag_width, num_inputs, num_caches) \ - `CACHE_CLUSTER_MEM_ARB_TAG(`MAX(`CACHE_MEM_TAG_WIDTH(mshr_size, num_banks), `CACHE_NC_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, `CACHE_CLUSTER_CORE_ARB_TAG(tag_width, num_inputs, num_caches))), num_caches) - -/////////////////////////////////////////////////////////////////////////////// - -`ifdef L2_ENABLE -`define L2_LINE_SIZE `MEM_BLOCK_SIZE -`else -`define L2_LINE_SIZE `L1_LINE_SIZE -`endif - -`ifdef L3_ENABLE -`define L3_LINE_SIZE `MEM_BLOCK_SIZE -`else -`define L3_LINE_SIZE `L2_LINE_SIZE -`endif - -`define VX_MEM_BYTEEN_WIDTH `L3_LINE_SIZE -`define VX_MEM_ADDR_WIDTH (`MEM_ADDR_WIDTH - `CLOG2(`L3_LINE_SIZE)) -`define VX_MEM_DATA_WIDTH (`L3_LINE_SIZE * 8) -`define VX_MEM_TAG_WIDTH L3_MEM_TAG_WIDTH - -`define VX_DCR_ADDR_WIDTH `VX_DCR_ADDR_BITS -`define VX_DCR_DATA_WIDTH 32 - -`define TO_FULL_ADDR(x) {x, (`MEM_ADDR_WIDTH-$bits(x))'(0)} - -/////////////////////////////////////////////////////////////////////////////// - -`define BUFFER_EX(dst, src, ena, latency) \ - VX_pipe_register #( \ - .DATAW ($bits(dst)), \ - .RESETW ($bits(dst)), \ - .DEPTH (latency) \ - ) __``dst ( \ - .clk (clk), \ - .reset (reset), \ - .enable (ena), \ - .data_in (src), \ - .data_out (dst) \ - ) - -`define BUFFER(dst, src) `BUFFER_EX(dst, src, 1'b1, 1) - -`define POP_COUNT_EX(out, in, model) \ - VX_popcount #( \ - .N ($bits(in)), \ - .MODEL (model) \ - ) __``out ( \ - .data_in (in), \ - .data_out (out) \ - ) - -`define POP_COUNT(out, in) `POP_COUNT_EX(out, in, 1) - -`define ASSIGN_VX_MEM_BUS_IF(dst, src) \ - assign dst.req_valid = src.req_valid; \ - assign dst.req_data = src.req_data; \ - assign src.req_ready = dst.req_ready; \ - assign src.rsp_valid = dst.rsp_valid; \ - assign src.rsp_data = dst.rsp_data; \ - assign dst.rsp_ready = src.rsp_ready - -`define ASSIGN_VX_MEM_BUS_IF_X(dst, src, TD, TS) \ - assign dst.req_valid = src.req_valid; \ - assign dst.req_data.rw = src.req_data.rw; \ - assign dst.req_data.byteen = src.req_data.byteen; \ - assign dst.req_data.addr = src.req_data.addr; \ - assign dst.req_data.data = src.req_data.data; \ - if (TD != TS) \ - assign dst.req_data.tag = {src.req_data.tag, {(TD-TS){1'b0}}}; \ - else \ - assign dst.req_data.tag = src.req_data.tag; \ - assign src.req_ready = dst.req_ready; \ - assign src.rsp_valid = dst.rsp_valid; \ - assign src.rsp_data.data = dst.rsp_data.data; \ - assign src.rsp_data.tag = dst.rsp_data.tag[TD-1 -: TS]; \ - assign dst.rsp_ready = src.rsp_ready - -`define BUFFER_DCR_BUS_IF(dst, src, enable) \ - logic [(1 + `VX_DCR_ADDR_WIDTH + `VX_DCR_DATA_WIDTH)-1:0] __``dst; \ - if (enable) begin \ - always @(posedge clk) begin \ - __``dst <= {src.write_valid, src.write_addr, src.write_data}; \ - end \ - end else begin \ - assign __``dst = {src.write_valid, src.write_addr, src.write_data}; \ - end \ - VX_dcr_bus_if dst(); \ - assign {dst.write_valid, dst.write_addr, dst.write_data} = __``dst - -`define PERF_REDUCE(dst, src, field, width, count) \ - wire [count-1:0][width-1:0] __reduce_add_i_``src``field; \ - wire [width-1:0] __reduce_add_o_``dst``field; \ - reg [width-1:0] __reduce_add_r_``dst``field; \ - for (genvar __i = 0; __i < count; ++__i) begin \ - assign __reduce_add_i_``src``field[__i] = ``src[__i].``field; \ - end \ - VX_reduce #(.DATAW_IN(width), .N(count), .OP("+")) __reduce_add_``dst``field ( \ - __reduce_add_i_``src``field, \ - __reduce_add_o_``dst``field \ - ); \ - always @(posedge clk) begin \ - if (reset) begin \ - __reduce_add_r_``dst``field <= '0; \ - end else begin \ - __reduce_add_r_``dst``field <= __reduce_add_o_``dst``field; \ - end \ - end \ - assign ``dst.``field = __reduce_add_r_``dst``field - -`define PERF_CACHE_REDUCE(dst, src, count) \ - `PERF_REDUCE (dst, src, reads, `PERF_CTR_BITS, count); \ - `PERF_REDUCE (dst, src, writes, `PERF_CTR_BITS, count); \ - `PERF_REDUCE (dst, src, read_misses, `PERF_CTR_BITS, count); \ - `PERF_REDUCE (dst, src, write_misses, `PERF_CTR_BITS, count); \ - `PERF_REDUCE (dst, src, bank_stalls, `PERF_CTR_BITS, count); \ - `PERF_REDUCE (dst, src, mshr_stalls, `PERF_CTR_BITS, count); \ - `PERF_REDUCE (dst, src, mem_stalls, `PERF_CTR_BITS, count); \ - `PERF_REDUCE (dst, src, crsp_stalls, `PERF_CTR_BITS, count) - -`define ASSIGN_BLOCKED_WID(dst, src, block_idx, block_size) \ - if (block_size != 1) begin \ - if (block_size != `NUM_WARPS) begin \ - assign dst = {src[`NW_WIDTH-1:`CLOG2(block_size)], `CLOG2(block_size)'(block_idx)}; \ - end else begin \ - assign dst = `NW_WIDTH'(block_idx); \ - end \ - end else begin \ - assign dst = src; \ - end - -`define TO_DISPATCH_DATA(data, tid) { \ - data.uuid, \ - data.wis, \ - data.tmask, \ - data.op_type, \ - data.op_mod, \ - data.wb, \ - data.use_PC, \ - data.use_imm, \ - data.PC, \ - data.imm, \ - data.rd, \ - tid, \ - data.rs1_data, \ - data.rs2_data, \ - data.rs3_data} - -/////////////////////////////////////////////////////////////////////////////// - -`endif // VX_DEFINE_VH +// Copyright © 2019-2023 +// +// Licensed 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. + +`ifndef VX_DEFINE_VH +`define VX_DEFINE_VH + +`include "VX_platform.vh" +`include "VX_config.vh" +`include "VX_types.vh" + +/////////////////////////////////////////////////////////////////////////////// + +`define NW_BITS `CLOG2(`NUM_WARPS) +`define NC_WIDTH `UP(`NC_BITS) + +`define NT_BITS `CLOG2(`NUM_THREADS) +`define NW_WIDTH `UP(`NW_BITS) + +`define NC_BITS `CLOG2(`NUM_CORES) +`define NT_WIDTH `UP(`NT_BITS) + +`define NB_BITS `CLOG2(`NUM_BARRIERS) +`define NB_WIDTH `UP(`NB_BITS) + +`define NUM_IREGS 32 + +`define NRI_BITS `CLOG2(`NUM_IREGS) + +`ifdef EXT_F_ENABLE +`define NUM_REGS (2 * `NUM_IREGS) +`else +`define NUM_REGS `NUM_IREGS +`endif + +`define NR_BITS `CLOG2(`NUM_REGS) + +`define PERF_CTR_BITS 44 + +`ifndef NDEBUG +`define UUID_WIDTH 44 +`else +`define UUID_WIDTH 1 +`endif + +/////////////////////////////////////////////////////////////////////////////// + +`define EX_ALU 0 +`define EX_LSU 1 +`define EX_SFU 2 +`define EX_FPU (`EX_SFU + `EXT_F_ENABLED) + +`define NUM_EX_UNITS (3 + `EXT_F_ENABLED) +`define EX_BITS `CLOG2(`NUM_EX_UNITS) +`define EX_WIDTH `UP(`EX_BITS) + +`define SFU_CSRS 0 +`define SFU_WCTL 1 + +`define NUM_SFU_UNITS (2) +`define SFU_BITS `CLOG2(`NUM_SFU_UNITS) +`define SFU_WIDTH `UP(`SFU_BITS) + +/////////////////////////////////////////////////////////////////////////////// + +`define INST_LUI 7'b0110111 +`define INST_AUIPC 7'b0010111 +`define INST_JAL 7'b1101111 +`define INST_JALR 7'b1100111 +`define INST_B 7'b1100011 // branch instructions +`define INST_L 7'b0000011 // load instructions +`define INST_S 7'b0100011 // store instructions +`define INST_I 7'b0010011 // immediate instructions +`define INST_R 7'b0110011 // register instructions +`define INST_FENCE 7'b0001111 // Fence instructions +`define INST_SYS 7'b1110011 // system instructions + +// RV64I instruction specific opcodes (for any W instruction) +`define INST_I_W 7'b0011011 // W type immediate instructions +`define INST_R_W 7'b0111011 // W type register instructions + +`define INST_FL 7'b0000111 // float load instruction +`define INST_FS 7'b0100111 // float store instruction +`define INST_FMADD 7'b1000011 +`define INST_FMSUB 7'b1000111 +`define INST_FNMSUB 7'b1001011 +`define INST_FNMADD 7'b1001111 +`define INST_FCI 7'b1010011 // float common instructions + +// Custom extension opcodes +`define INST_EXT1 7'b0001011 // 0x0B +`define INST_EXT2 7'b0101011 // 0x2B +`define INST_EXT3 7'b1011011 // 0x5B +`define INST_EXT4 7'b1111011 // 0x7B + +/////////////////////////////////////////////////////////////////////////////// + +`define INST_FRM_RNE 3'b000 // round to nearest even +`define INST_FRM_RTZ 3'b001 // round to zero +`define INST_FRM_RDN 3'b010 // round to -inf +`define INST_FRM_RUP 3'b011 // round to +inf +`define INST_FRM_RMM 3'b100 // round to nearest max magnitude +`define INST_FRM_DYN 3'b111 // dynamic mode +`define INST_FRM_BITS 3 + +/////////////////////////////////////////////////////////////////////////////// + +`define INST_OP_BITS 4 +`define INST_MOD_BITS 3 +`define INST_FMT_BITS 2 + +/////////////////////////////////////////////////////////////////////////////// + +`define INST_ALU_ADD 4'b0000 +`define INST_ALU_LUI 4'b0010 +`define INST_ALU_AUIPC 4'b0011 +`define INST_ALU_SLTU 4'b0100 +`define INST_ALU_SLT 4'b0101 +`define INST_ALU_SUB 4'b0111 +`define INST_ALU_SRL 4'b1000 +`define INST_ALU_SRA 4'b1001 +`define INST_ALU_AND 4'b1100 +`define INST_ALU_OR 4'b1101 +`define INST_ALU_XOR 4'b1110 +`define INST_ALU_SLL 4'b1111 +`define INST_ALU_OTHER 4'b0111 +`define INST_ALU_BITS 4 +`define INST_ALU_CLASS(op) op[3:2] +`define INST_ALU_SIGNED(op) op[0] +`define INST_ALU_IS_SUB(op) op[1] +`define INST_ALU_IS_BR(mod) mod[0] +`define INST_ALU_IS_M(mod) mod[1] +`define INST_ALU_IS_W(mod) mod[2] + +`define INST_BR_EQ 4'b0000 +`define INST_BR_NE 4'b0010 +`define INST_BR_LTU 4'b0100 +`define INST_BR_GEU 4'b0110 +`define INST_BR_LT 4'b0101 +`define INST_BR_GE 4'b0111 +`define INST_BR_JAL 4'b1000 +`define INST_BR_JALR 4'b1001 +`define INST_BR_ECALL 4'b1010 +`define INST_BR_EBREAK 4'b1011 +`define INST_BR_URET 4'b1100 +`define INST_BR_SRET 4'b1101 +`define INST_BR_MRET 4'b1110 +`define INST_BR_OTHER 4'b1111 +`define INST_BR_BITS 4 +`define INST_BR_CLASS(op) {1'b0, ~op[3]} +`define INST_BR_IS_NEG(op) op[1] +`define INST_BR_IS_LESS(op) op[2] +`define INST_BR_IS_STATIC(op) op[3] + +`define INST_M_MUL 3'b000 +`define INST_M_MULHU 3'b001 +`define INST_M_MULH 3'b010 +`define INST_M_MULHSU 3'b011 +`define INST_M_DIV 3'b100 +`define INST_M_DIVU 3'b101 +`define INST_M_REM 3'b110 +`define INST_M_REMU 3'b111 +`define INST_M_BITS 3 +`define INST_M_SIGNED(op) (~op[0]) +`define INST_M_IS_MULX(op) (~op[2]) +`define INST_M_IS_MULH(op) (op[1:0] != 0) +`define INST_M_SIGNED_A(op) (op[1:0] != 1) +`define INST_M_IS_REM(op) op[1] + +`define INST_FMT_B 3'b000 +`define INST_FMT_H 3'b001 +`define INST_FMT_W 3'b010 +`define INST_FMT_D 3'b011 +`define INST_FMT_BU 3'b100 +`define INST_FMT_HU 3'b101 +`define INST_FMT_WU 3'b110 + +`define INST_LSU_LB 4'b0000 +`define INST_LSU_LH 4'b0001 +`define INST_LSU_LW 4'b0010 +`define INST_LSU_LD 4'b0011 // new for RV64I LD +`define INST_LSU_LBU 4'b0100 +`define INST_LSU_LHU 4'b0101 +`define INST_LSU_LWU 4'b0110 // new for RV64I LWU +`define INST_LSU_SB 4'b1000 +`define INST_LSU_SH 4'b1001 +`define INST_LSU_SW 4'b1010 +`define INST_LSU_SD 4'b1011 // new for RV64I SD +`define INST_LSU_FENCE 4'b1111 +`define INST_LSU_BITS 4 +`define INST_LSU_FMT(op) op[2:0] +`define INST_LSU_WSIZE(op) op[1:0] +`define INST_LSU_IS_FENCE(op) (op[3:2] == 3) + +`define INST_FENCE_BITS 1 +`define INST_FENCE_D 1'h0 +`define INST_FENCE_I 1'h1 + +`define INST_FPU_ADD 4'b0000 +`define INST_FPU_SUB 4'b0001 +`define INST_FPU_MUL 4'b0010 +`define INST_FPU_DIV 4'b0011 +`define INST_FPU_SQRT 4'b0100 +`define INST_FPU_CMP 4'b0101 // mod: LE=0, LT=1, EQ=2 +`define INST_FPU_F2F 4'b0110 +`define INST_FPU_MISC 4'b0111 // mod: SGNJ=0, SGNJN=1, SGNJX=2, CLASS=3, MVXW=4, MVWX=5, FMIN=6, FMAX=7 +`define INST_FPU_F2I 4'b1000 +`define INST_FPU_F2U 4'b1001 +`define INST_FPU_I2F 4'b1010 +`define INST_FPU_U2F 4'b1011 +`define INST_FPU_MADD 4'b1100 +`define INST_FPU_MSUB 4'b1101 +`define INST_FPU_NMSUB 4'b1110 +`define INST_FPU_NMADD 4'b1111 +`define INST_FPU_BITS 4 +`define INST_FPU_IS_W(mod) (mod[4]) +`define INST_FPU_IS_CLASS(op, mod) (op == `INST_FPU_MISC && mod == 3) +`define INST_FPU_IS_MVXW(op, mod) (op == `INST_FPU_MISC && mod == 4) + +`define INST_SFU_TMC 4'h0 +`define INST_SFU_WSPAWN 4'h1 +`define INST_SFU_SPLIT 4'h2 +`define INST_SFU_JOIN 4'h3 +`define INST_SFU_BAR 4'h4 +`define INST_SFU_PRED 4'h5 +`define INST_SFU_CSRRW 4'h6 +`define INST_SFU_CSRRS 4'h7 +`define INST_SFU_CSRRC 4'h8 +`define INST_SFU_CMOV 4'h9 +`define INST_SFU_BITS 4 +`define INST_SFU_CSR(f3) (4'h6 + 4'(f3) - 4'h1) +`define INST_SFU_IS_WCTL(op) (op <= 5) +`define INST_SFU_IS_CSR(op) (op >= 6 && op <= 8) + +/////////////////////////////////////////////////////////////////////////////// + +// non-cacheable tag bits +`define NC_TAG_BITS 1 + +// cache address type bits +`ifdef SM_ENABLE +`define CACHE_ADDR_TYPE_BITS (`NC_TAG_BITS + 1) +`else +`define CACHE_ADDR_TYPE_BITS `NC_TAG_BITS +`endif + +`define ARB_SEL_BITS(I, O) ((I > O) ? `CLOG2((I + O - 1) / O) : 0) + +/////////////////////////////////////////////////////////////////////////////// + +`define CACHE_MEM_TAG_WIDTH(mshr_size, num_banks) \ + (`CLOG2(mshr_size) + `CLOG2(num_banks) + `NC_TAG_BITS) + +`define CACHE_NC_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, tag_width) \ + (`CLOG2(num_reqs) + `CLOG2(line_size / word_size) + tag_width) + +`define CACHE_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, tag_width) \ + (`CACHE_NC_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, tag_width) + `NC_TAG_BITS) + +`define CACHE_NC_MEM_TAG_WIDTH(mshr_size, num_banks, num_reqs, line_size, word_size, tag_width) \ + `MAX(`CACHE_MEM_TAG_WIDTH(mshr_size, num_banks), `CACHE_NC_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, tag_width)) + +/////////////////////////////////////////////////////////////////////////////// + +`define CACHE_CLUSTER_CORE_ARB_TAG(tag_width, num_inputs, num_caches) \ + (tag_width + `ARB_SEL_BITS(num_inputs, `UP(num_caches))) + +`define CACHE_CLUSTER_MEM_ARB_TAG(tag_width, num_caches) \ + (tag_width + `ARB_SEL_BITS(`UP(num_caches), 1)) + +`define CACHE_CLUSTER_MEM_TAG_WIDTH(mshr_size, num_banks, num_caches) \ + `CACHE_CLUSTER_MEM_ARB_TAG(`CACHE_MEM_TAG_WIDTH(mshr_size, num_banks), num_caches) + +`define CACHE_CLUSTER_NC_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, tag_width, num_inputs, num_caches) \ + `CACHE_CLUSTER_MEM_ARB_TAG((`CLOG2(num_reqs) + `CLOG2(line_size / word_size) + `CACHE_CLUSTER_CORE_ARB_TAG(tag_width, num_inputs, num_caches)), num_caches) + +`define CACHE_CLUSTER_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, tag_width, num_inputs, num_caches) \ + `CACHE_CLUSTER_MEM_ARB_TAG((`CACHE_NC_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, `CACHE_CLUSTER_CORE_ARB_TAG(tag_width, num_inputs, num_caches)) + `NC_TAG_BITS), num_caches) + +`define CACHE_CLUSTER_NC_MEM_TAG_WIDTH(mshr_size, num_banks, num_reqs, line_size, word_size, tag_width, num_inputs, num_caches) \ + `CACHE_CLUSTER_MEM_ARB_TAG(`MAX(`CACHE_MEM_TAG_WIDTH(mshr_size, num_banks), `CACHE_NC_BYPASS_TAG_WIDTH(num_reqs, line_size, word_size, `CACHE_CLUSTER_CORE_ARB_TAG(tag_width, num_inputs, num_caches))), num_caches) + +/////////////////////////////////////////////////////////////////////////////// + +`ifdef L2_ENABLE +`define L2_LINE_SIZE `MEM_BLOCK_SIZE +`else +`define L2_LINE_SIZE `L1_LINE_SIZE +`endif + +`ifdef L3_ENABLE +`define L3_LINE_SIZE `MEM_BLOCK_SIZE +`else +`define L3_LINE_SIZE `L2_LINE_SIZE +`endif + +`define VX_MEM_BYTEEN_WIDTH `L3_LINE_SIZE +`define VX_MEM_ADDR_WIDTH (`MEM_ADDR_WIDTH - `CLOG2(`L3_LINE_SIZE)) +`define VX_MEM_DATA_WIDTH (`L3_LINE_SIZE * 8) +`define VX_MEM_TAG_WIDTH L3_MEM_TAG_WIDTH + +`define VX_DCR_ADDR_WIDTH `VX_DCR_ADDR_BITS +`define VX_DCR_DATA_WIDTH 32 + +`define TO_FULL_ADDR(x) {x, (`MEM_ADDR_WIDTH-$bits(x))'(0)} + +/////////////////////////////////////////////////////////////////////////////// + +`define BUFFER_EX(dst, src, ena, latency) \ + VX_pipe_register #( \ + .DATAW ($bits(dst)), \ + .RESETW ($bits(dst)), \ + .DEPTH (latency) \ + ) __``dst ( \ + .clk (clk), \ + .reset (reset), \ + .enable (ena), \ + .data_in (src), \ + .data_out (dst) \ + ) + +`define BUFFER(dst, src) `BUFFER_EX(dst, src, 1'b1, 1) + +`define POP_COUNT_EX(out, in, model) \ + VX_popcount #( \ + .N ($bits(in)), \ + .MODEL (model) \ + ) __``out ( \ + .data_in (in), \ + .data_out (out) \ + ) + +`define POP_COUNT(out, in) `POP_COUNT_EX(out, in, 1) + +`define ASSIGN_VX_MEM_BUS_IF(dst, src) \ + assign dst.req_valid = src.req_valid; \ + assign dst.req_data = src.req_data; \ + assign src.req_ready = dst.req_ready; \ + assign src.rsp_valid = dst.rsp_valid; \ + assign src.rsp_data = dst.rsp_data; \ + assign dst.rsp_ready = src.rsp_ready + +`define ASSIGN_VX_MEM_BUS_IF_X(dst, src, TD, TS) \ + assign dst.req_valid = src.req_valid; \ + assign dst.req_data.rw = src.req_data.rw; \ + assign dst.req_data.byteen = src.req_data.byteen; \ + assign dst.req_data.addr = src.req_data.addr; \ + assign dst.req_data.data = src.req_data.data; \ + if (TD != TS) \ + assign dst.req_data.tag = {src.req_data.tag, {(TD-TS){1'b0}}}; \ + else \ + assign dst.req_data.tag = src.req_data.tag; \ + assign src.req_ready = dst.req_ready; \ + assign src.rsp_valid = dst.rsp_valid; \ + assign src.rsp_data.data = dst.rsp_data.data; \ + assign src.rsp_data.tag = dst.rsp_data.tag[TD-1 -: TS]; \ + assign dst.rsp_ready = src.rsp_ready + +`define BUFFER_DCR_BUS_IF(dst, src, enable) \ + logic [(1 + `VX_DCR_ADDR_WIDTH + `VX_DCR_DATA_WIDTH)-1:0] __``dst; \ + if (enable) begin \ + always @(posedge clk) begin \ + __``dst <= {src.write_valid, src.write_addr, src.write_data}; \ + end \ + end else begin \ + assign __``dst = {src.write_valid, src.write_addr, src.write_data}; \ + end \ + VX_dcr_bus_if dst(); \ + assign {dst.write_valid, dst.write_addr, dst.write_data} = __``dst + +`define PERF_COUNTER_ADD(dst, src, field, width, dst_count, src_count, reg_enable) \ + for (genvar __d = 0; __d < dst_count; ++__d) begin \ + localparam __count = ((src_count > dst_count) ? ((src_count + dst_count - 1) / dst_count) : 1); \ + wire [__count-1:0][width-1:0] __reduce_add_i_``src``field; \ + wire [width-1:0] __reduce_add_o_``dst``field; \ + for (genvar __i = 0; __i < __count; ++__i) begin \ + assign __reduce_add_i_``src``field[__i] = ``src[__d * __count + __i].``field; \ + end \ + VX_reduce #(.DATAW_IN(width), .N(__count), .OP("+")) __reduce_add_``dst``field ( \ + __reduce_add_i_``src``field, \ + __reduce_add_o_``dst``field \ + ); \ + if (reg_enable) begin \ + reg [width-1:0] __reduce_add_r_``dst``field; \ + always @(posedge clk) begin \ + if (reset) begin \ + __reduce_add_r_``dst``field <= '0; \ + end else begin \ + __reduce_add_r_``dst``field <= __reduce_add_o_``dst``field; \ + end \ + end \ + assign ``dst[__d].``field = __reduce_add_r_``dst``field; \ + end else begin \ + assign ``dst[__d].``field = __reduce_add_o_``dst``field; \ + end \ + end + +`define ASSIGN_BLOCKED_WID(dst, src, block_idx, block_size) \ + if (block_size != 1) begin \ + if (block_size != `NUM_WARPS) begin \ + assign dst = {src[`NW_WIDTH-1:`CLOG2(block_size)], `CLOG2(block_size)'(block_idx)}; \ + end else begin \ + assign dst = `NW_WIDTH'(block_idx); \ + end \ + end else begin \ + assign dst = src; \ + end + +`define TO_DISPATCH_DATA(data, tid) { \ + data.uuid, \ + data.wis, \ + data.tmask, \ + data.op_type, \ + data.op_mod, \ + data.wb, \ + data.use_PC, \ + data.use_imm, \ + data.PC, \ + data.imm, \ + data.rd, \ + tid, \ + data.rs1_data, \ + data.rs2_data, \ + data.rs3_data} + +/////////////////////////////////////////////////////////////////////////////// + +`endif // VX_DEFINE_VH diff --git a/hw/rtl/VX_gpu_pkg.sv b/hw/rtl/VX_gpu_pkg.sv index b32b9600..94fe7684 100644 --- a/hw/rtl/VX_gpu_pkg.sv +++ b/hw/rtl/VX_gpu_pkg.sv @@ -99,7 +99,7 @@ package VX_gpu_pkg; `ifdef ICACHE_ENABLE localparam ICACHE_MEM_TAG_WIDTH = `CACHE_CLUSTER_MEM_TAG_WIDTH(`ICACHE_MSHR_SIZE, 1, `NUM_ICACHES); `else - localparam ICACHE_MEM_TAG_WIDTH = `CACHE_CLUSTER_BYPASS_TAG_WIDTH(1, ICACHE_LINE_SIZE, ICACHE_WORD_SIZE, ICACHE_TAG_WIDTH, `NUM_SOCKETS, `NUM_ICACHES); + localparam ICACHE_MEM_TAG_WIDTH = `CACHE_CLUSTER_BYPASS_TAG_WIDTH(1, ICACHE_LINE_SIZE, ICACHE_WORD_SIZE, ICACHE_TAG_WIDTH, `SOCKET_SIZE, `NUM_ICACHES); `endif ////////////////////////// Dcache Parameters ////////////////////////////// @@ -147,6 +147,9 @@ package VX_gpu_pkg; /////////////////////////////// L2 Parameters ///////////////////////////// + localparam ICACHE_MEM_ARB_IDX = 0; + localparam DCACHE_MEM_ARB_IDX = ICACHE_MEM_ARB_IDX + 1; + // Word size in bytes localparam L2_WORD_SIZE = `L1_LINE_SIZE; diff --git a/hw/rtl/VX_socket.sv b/hw/rtl/VX_socket.sv index 74a074d1..31a01b50 100644 --- a/hw/rtl/VX_socket.sv +++ b/hw/rtl/VX_socket.sv @@ -66,18 +66,11 @@ module VX_socket import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE VX_mem_perf_if mem_perf_tmp_if(); - cache_perf_t perf_icache; - cache_perf_t perf_dcache; - - assign mem_perf_tmp_if.icache = perf_icache; - assign mem_perf_tmp_if.dcache = perf_dcache; assign mem_perf_tmp_if.l2cache = mem_perf_if.l2cache; assign mem_perf_tmp_if.l3cache = mem_perf_if.l3cache; assign mem_perf_tmp_if.smem = 'x; assign mem_perf_tmp_if.mem = mem_perf_if.mem; -`endif - - +`endif /////////////////////////////////////////////////////////////////////////// @@ -110,7 +103,7 @@ module VX_socket import VX_gpu_pkg::*; #( .MEM_OUT_REG (2) ) icache ( `ifdef PERF_ENABLE - .cache_perf (perf_icache), + .cache_perf (mem_perf_tmp_if.icache), `endif .clk (clk), .reset (icache_reset), @@ -121,7 +114,7 @@ module VX_socket import VX_gpu_pkg::*; #( /////////////////////////////////////////////////////////////////////////// VX_mem_bus_if #( - .DATA_SIZE (DCACHE_WORD_SIZE), + .DATA_SIZE (DCACHE_WORD_SIZE), .TAG_WIDTH (DCACHE_NOSM_TAG_WIDTH) ) per_core_dcache_bus_if[`SOCKET_SIZE * DCACHE_NUM_REQS](); @@ -150,7 +143,7 @@ module VX_socket import VX_gpu_pkg::*; #( .MEM_OUT_REG (2) ) dcache ( `ifdef PERF_ENABLE - .cache_perf (perf_dcache), + .cache_perf (mem_perf_tmp_if.dcache), `endif .clk (clk), .reset (dcache_reset), diff --git a/hw/rtl/VX_types.vh b/hw/rtl/VX_types.vh index a5044ccf..9e875d21 100644 --- a/hw/rtl/VX_types.vh +++ b/hw/rtl/VX_types.vh @@ -97,6 +97,11 @@ `define VX_CSR_MPM_IFETCH_LT_H 12'hB8E `define VX_CSR_MPM_LOAD_LT 12'hB0F `define VX_CSR_MPM_LOAD_LT_H 12'hB8F +// SFU: scoreboard +`define VX_CSR_MPM_SCRB_WCTL 12'hB10 +`define VX_CSR_MPM_SCRB_WCTL_H 12'hB90 +`define VX_CSR_MPM_SCRB_CSRS 12'hB11 +`define VX_CSR_MPM_SCRB_CSRS_H 12'hB91 // Machine Performance-monitoring memory counters // PERF: icache diff --git a/hw/rtl/Vortex.sv b/hw/rtl/Vortex.sv index e9d068f7..a955c8f5 100644 --- a/hw/rtl/Vortex.sv +++ b/hw/rtl/Vortex.sv @@ -22,15 +22,15 @@ module Vortex import VX_gpu_pkg::*; ( // Memory request output wire mem_req_valid, - output wire mem_req_rw, - output wire [`VX_MEM_BYTEEN_WIDTH-1:0] mem_req_byteen, + output wire mem_req_rw, + output wire [`VX_MEM_BYTEEN_WIDTH-1:0] mem_req_byteen, output wire [`VX_MEM_ADDR_WIDTH-1:0] mem_req_addr, output wire [`VX_MEM_DATA_WIDTH-1:0] mem_req_data, output wire [`VX_MEM_TAG_WIDTH-1:0] mem_req_tag, input wire mem_req_ready, // Memory response - input wire mem_rsp_valid, + input wire mem_rsp_valid, input wire [`VX_MEM_DATA_WIDTH-1:0] mem_rsp_data, input wire [`VX_MEM_TAG_WIDTH-1:0] mem_rsp_tag, output wire mem_rsp_ready, @@ -45,17 +45,11 @@ module Vortex import VX_gpu_pkg::*; ( ); `ifdef PERF_ENABLE - VX_mem_perf_if mem_perf_if(); - cache_perf_t perf_l3cache; - mem_perf_t mem_perf; - - assign mem_perf_if.smem = 'x; + VX_mem_perf_if mem_perf_if(); assign mem_perf_if.icache = 'x; assign mem_perf_if.dcache = 'x; assign mem_perf_if.l2cache = 'x; - assign mem_perf_if.l3cache = perf_l3cache; - assign mem_perf_if.mem = mem_perf; -`endif +`endif VX_mem_bus_if #( .DATA_SIZE (`L2_LINE_SIZE), @@ -93,7 +87,7 @@ module Vortex import VX_gpu_pkg::*; ( .reset (l3_reset), `ifdef PERF_ENABLE - .cache_perf (perf_l3cache), + .cache_perf (mem_perf_if.l3cache), `endif .core_bus_if (per_cluster_mem_bus_if), @@ -166,11 +160,12 @@ module Vortex import VX_gpu_pkg::*; ( ); end - `BUFFER_EX(busy, (| per_cluster_busy), 1'b1, (`NUM_CLUSTERS > 1)); + `BUFFER_EX(busy, (| per_cluster_busy), 1'b1, (`NUM_CLUSTERS > 1)); `ifdef PERF_ENABLE - reg [`PERF_CTR_BITS-1:0] perf_mem_pending_reads; + reg [`PERF_CTR_BITS-1:0] perf_mem_pending_reads; + mem_perf_t mem_perf; always @(posedge clk) begin if (reset) begin @@ -193,6 +188,7 @@ module Vortex import VX_gpu_pkg::*; ( mem_perf.latency <= mem_perf.latency + perf_mem_pending_reads; end end + assign mem_perf_if.mem = mem_perf; `endif diff --git a/hw/rtl/cache/VX_cache_cluster.sv b/hw/rtl/cache/VX_cache_cluster.sv index 18e26eb2..46447e4f 100644 --- a/hw/rtl/cache/VX_cache_cluster.sv +++ b/hw/rtl/cache/VX_cache_cluster.sv @@ -83,8 +83,9 @@ module VX_cache_cluster import VX_gpu_pkg::*; #( `STATIC_ASSERT(NUM_INPUTS >= NUM_CACHES, ("invalid parameter")) `ifdef PERF_ENABLE - cache_perf_t perf_cache_unit[NUM_CACHES]; - `PERF_CACHE_REDUCE (cache_perf, perf_cache_unit, NUM_CACHES); + cache_perf_t perf_cache_tmp[1], perf_cache_unit[NUM_CACHES]; + `PERF_CACHE_ADD (perf_cache_tmp, perf_cache_unit, 1, NUM_CACHES) + assign cache_perf = perf_cache_tmp[0]; `endif VX_mem_bus_if #( diff --git a/hw/rtl/cache/VX_cache_define.vh b/hw/rtl/cache/VX_cache_define.vh index 0bb675fa..7567025f 100644 --- a/hw/rtl/cache/VX_cache_define.vh +++ b/hw/rtl/cache/VX_cache_define.vh @@ -62,4 +62,16 @@ `define CS_LINE_TO_FULL_ADDR(x, i) {x, (`XLEN-$bits(x))'(i << (`XLEN-$bits(x)-`CS_BANK_SEL_BITS))} `define CS_MEM_TO_FULL_ADDR(x) {x, (`XLEN-$bits(x))'(0)} +/////////////////////////////////////////////////////////////////////////////// + +`define PERF_CACHE_ADD(dst, src, dcount, scount) \ + `PERF_COUNTER_ADD (dst, src, reads, `PERF_CTR_BITS, dcount, scount, (((scount + dcount - 1) / dcount) > 1)) \ + `PERF_COUNTER_ADD (dst, src, writes, `PERF_CTR_BITS, dcount, scount, (((scount + dcount - 1) / dcount) > 1)) \ + `PERF_COUNTER_ADD (dst, src, read_misses, `PERF_CTR_BITS, dcount, scount, (((scount + dcount - 1) / dcount) > 1)) \ + `PERF_COUNTER_ADD (dst, src, write_misses, `PERF_CTR_BITS, dcount, scount, (((scount + dcount - 1) / dcount) > 1)) \ + `PERF_COUNTER_ADD (dst, src, bank_stalls, `PERF_CTR_BITS, dcount, scount, (((scount + dcount - 1) / dcount) > 1)) \ + `PERF_COUNTER_ADD (dst, src, mshr_stalls, `PERF_CTR_BITS, dcount, scount, (((scount + dcount - 1) / dcount) > 1)) \ + `PERF_COUNTER_ADD (dst, src, mem_stalls, `PERF_CTR_BITS, dcount, scount, (((scount + dcount - 1) / dcount) > 1)) \ + `PERF_COUNTER_ADD (dst, src, crsp_stalls, `PERF_CTR_BITS, dcount, scount, (((scount + dcount - 1) / dcount) > 1)) + `endif // VX_CACHE_DEFINE_VH diff --git a/hw/rtl/core/VX_core.sv b/hw/rtl/core/VX_core.sv index 4d3ce297..dde085a8 100644 --- a/hw/rtl/core/VX_core.sv +++ b/hw/rtl/core/VX_core.sv @@ -1,344 +1,338 @@ -// Copyright © 2019-2023 -// -// Licensed 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. - -`include "VX_define.vh" - -`ifdef EXT_F_ENABLE -`include "VX_fpu_define.vh" -`endif - -module VX_core import VX_gpu_pkg::*; #( - parameter CORE_ID = 0 -) ( - `SCOPE_IO_DECL - - // Clock - input wire clk, - input wire reset, - -`ifdef PERF_ENABLE - VX_mem_perf_if.slave mem_perf_if, -`endif - - VX_dcr_bus_if.slave dcr_bus_if, - - VX_mem_bus_if.master dcache_bus_if [DCACHE_NUM_REQS], - - VX_mem_bus_if.master icache_bus_if, - -`ifdef GBAR_ENABLE - VX_gbar_bus_if.master gbar_bus_if, -`endif - - // simulation helper signals - output wire sim_ebreak, - output wire [`NUM_REGS-1:0][`XLEN-1:0] sim_wb_value, - - // Status - output wire busy -); - VX_schedule_if schedule_if(); - VX_fetch_if fetch_if(); - VX_decode_if decode_if(); - VX_sched_csr_if sched_csr_if(); - VX_decode_sched_if decode_sched_if(); - VX_commit_sched_if commit_sched_if(); - VX_commit_csr_if commit_csr_if(); - VX_branch_ctl_if branch_ctl_if[`NUM_ALU_BLOCKS](); - VX_warp_ctl_if warp_ctl_if(); - - VX_dispatch_if alu_dispatch_if[`ISSUE_WIDTH](); - VX_commit_if alu_commit_if[`ISSUE_WIDTH](); - - VX_dispatch_if lsu_dispatch_if[`ISSUE_WIDTH](); - VX_commit_if lsu_commit_if[`ISSUE_WIDTH](); -`ifdef EXT_F_ENABLE - VX_dispatch_if fpu_dispatch_if[`ISSUE_WIDTH](); - VX_commit_if fpu_commit_if[`ISSUE_WIDTH](); -`endif - VX_dispatch_if sfu_dispatch_if[`ISSUE_WIDTH](); - VX_commit_if sfu_commit_if[`ISSUE_WIDTH](); - - VX_writeback_if writeback_if[`ISSUE_WIDTH](); - - VX_mem_bus_if #( - .DATA_SIZE (DCACHE_WORD_SIZE), - .TAG_WIDTH (DCACHE_TAG_WIDTH) - ) dcache_bus_tmp_if[DCACHE_NUM_REQS](); - -`ifdef PERF_ENABLE - VX_pipeline_perf_if pipeline_perf_if(); - VX_mem_perf_if mem_perf_tmp_if(); - - assign mem_perf_tmp_if.icache = mem_perf_if.icache; - assign mem_perf_tmp_if.dcache = mem_perf_if.dcache; - assign mem_perf_tmp_if.l2cache = mem_perf_if.l2cache; - assign mem_perf_tmp_if.l3cache = mem_perf_if.l3cache; -`ifdef SM_ENABLE - cache_perf_t smem_perf; - assign mem_perf_tmp_if.smem = smem_perf; -`else - assign mem_perf_tmp_if.smem = '0; -`endif - assign mem_perf_tmp_if.mem = mem_perf_if.mem; -`endif - - `RESET_RELAY (dcr_data_reset, reset); - `RESET_RELAY (schedule_reset, reset); - `RESET_RELAY (fetch_reset, reset); - `RESET_RELAY (decode_reset, reset); - `RESET_RELAY (issue_reset, reset); - `RESET_RELAY (execute_reset, reset); - `RESET_RELAY (commit_reset, reset); - - base_dcrs_t base_dcrs; - - VX_dcr_data dcr_data ( - .clk (clk), - .reset (dcr_data_reset), - .dcr_bus_if (dcr_bus_if), - .base_dcrs (base_dcrs) - ); - - `SCOPE_IO_SWITCH (3) - - VX_schedule #( - .CORE_ID (CORE_ID) - ) schedule ( - .clk (clk), - .reset (schedule_reset), - - `ifdef PERF_ENABLE - .perf_schedule_if (pipeline_perf_if.schedule), - `endif - - .base_dcrs (base_dcrs), - - .warp_ctl_if (warp_ctl_if), - .branch_ctl_if (branch_ctl_if), - .decode_sched_if(decode_sched_if), - .commit_sched_if(commit_sched_if), - - .schedule_if (schedule_if), - `ifdef GBAR_ENABLE - .gbar_bus_if (gbar_bus_if), - `endif - .sched_csr_if (sched_csr_if), - - .busy (busy) - ); - - VX_fetch #( - .CORE_ID (CORE_ID) - ) fetch ( - `SCOPE_IO_BIND (0) - .clk (clk), - .reset (fetch_reset), - .icache_bus_if (icache_bus_if), - .schedule_if (schedule_if), - .fetch_if (fetch_if) - ); - - VX_decode #( - .CORE_ID (CORE_ID) - ) decode ( - .clk (clk), - .reset (decode_reset), - .fetch_if (fetch_if), - .decode_if (decode_if), - .decode_sched_if(decode_sched_if) - ); - - VX_issue #( - .CORE_ID (CORE_ID) - ) issue ( - `SCOPE_IO_BIND (1) - - .clk (clk), - .reset (issue_reset), - - `ifdef PERF_ENABLE - .perf_issue_if (pipeline_perf_if.issue), - `endif - - .decode_if (decode_if), - .writeback_if (writeback_if), - - .alu_dispatch_if(alu_dispatch_if), - .lsu_dispatch_if(lsu_dispatch_if), - `ifdef EXT_F_ENABLE - .fpu_dispatch_if(fpu_dispatch_if), - `endif - .sfu_dispatch_if(sfu_dispatch_if) - ); - - VX_execute #( - .CORE_ID (CORE_ID) - ) execute ( - `SCOPE_IO_BIND (2) - - .clk (clk), - .reset (execute_reset), - - .base_dcrs (base_dcrs), - - `ifdef PERF_ENABLE - .mem_perf_if (mem_perf_tmp_if), - .pipeline_perf_if(pipeline_perf_if), - `endif - - .dcache_bus_if (dcache_bus_tmp_if), - - `ifdef EXT_F_ENABLE - .fpu_dispatch_if(fpu_dispatch_if), - .fpu_commit_if (fpu_commit_if), - `endif - - .commit_csr_if (commit_csr_if), - .sched_csr_if (sched_csr_if), - - .alu_dispatch_if(alu_dispatch_if), - .lsu_dispatch_if(lsu_dispatch_if), - .sfu_dispatch_if(sfu_dispatch_if), - - .warp_ctl_if (warp_ctl_if), - .branch_ctl_if (branch_ctl_if), - - .alu_commit_if (alu_commit_if), - .lsu_commit_if (lsu_commit_if), - .sfu_commit_if (sfu_commit_if), - - .sim_ebreak (sim_ebreak) - ); - - VX_commit #( - .CORE_ID (CORE_ID) - ) commit ( - .clk (clk), - .reset (commit_reset), - - .alu_commit_if (alu_commit_if), - .lsu_commit_if (lsu_commit_if), - `ifdef EXT_F_ENABLE - .fpu_commit_if (fpu_commit_if), - `endif - .sfu_commit_if (sfu_commit_if), - - .writeback_if (writeback_if), - - .commit_csr_if (commit_csr_if), - .commit_sched_if(commit_sched_if), - - .sim_wb_value (sim_wb_value) - ); - -`ifdef SM_ENABLE - - VX_smem_unit #( - .CORE_ID (CORE_ID) - ) smem_unit ( - .clk (clk), - .reset (reset), - `ifdef PERF_ENABLE - .cache_perf (smem_perf), - `endif - .dcache_bus_in_if (dcache_bus_tmp_if), - .dcache_bus_out_if (dcache_bus_if) - ); - -`else - - for (genvar i = 0; i < DCACHE_NUM_REQS; ++i) begin - `ASSIGN_VX_MEM_BUS_IF (dcache_bus_if[i], dcache_bus_tmp_if[i]); - end - -`endif - -`ifdef PERF_ENABLE - - wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_rd_req_per_cycle; - wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_wr_req_per_cycle; - wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_rsp_per_cycle; - - wire [1:0] perf_icache_pending_read_cycle; - wire [`CLOG2(DCACHE_NUM_REQS+1)+1-1:0] perf_dcache_pending_read_cycle; - - reg [`PERF_CTR_BITS-1:0] perf_icache_pending_reads; - reg [`PERF_CTR_BITS-1:0] perf_dcache_pending_reads; - - reg [`PERF_CTR_BITS-1:0] perf_ifetches; - reg [`PERF_CTR_BITS-1:0] perf_loads; - reg [`PERF_CTR_BITS-1:0] perf_stores; - - wire perf_icache_req_fire = icache_bus_if.req_valid && icache_bus_if.req_ready; - wire perf_icache_rsp_fire = icache_bus_if.rsp_valid && icache_bus_if.rsp_ready; - - wire [DCACHE_NUM_REQS-1:0] perf_dcache_rd_req_fire, perf_dcache_rd_req_fire_r; - wire [DCACHE_NUM_REQS-1:0] perf_dcache_wr_req_fire, perf_dcache_wr_req_fire_r; - wire [DCACHE_NUM_REQS-1:0] perf_dcache_rsp_fire; - - for (genvar i = 0; i < DCACHE_NUM_REQS; ++i) begin - assign perf_dcache_rd_req_fire[i] = dcache_bus_if[i].req_valid && dcache_bus_if[i].req_ready && ~dcache_bus_if[i].req_data.rw; - assign perf_dcache_wr_req_fire[i] = dcache_bus_if[i].req_valid && dcache_bus_if[i].req_ready && dcache_bus_if[i].req_data.rw; - assign perf_dcache_rsp_fire[i] = dcache_bus_if[i].rsp_valid && dcache_bus_if[i].rsp_ready; - end - - `BUFFER(perf_dcache_rd_req_fire_r, perf_dcache_rd_req_fire); - `BUFFER(perf_dcache_wr_req_fire_r, perf_dcache_wr_req_fire); - - `POP_COUNT(perf_dcache_rd_req_per_cycle, perf_dcache_rd_req_fire_r); - `POP_COUNT(perf_dcache_wr_req_per_cycle, perf_dcache_wr_req_fire_r); - `POP_COUNT(perf_dcache_rsp_per_cycle, perf_dcache_rsp_fire); - - assign perf_icache_pending_read_cycle = perf_icache_req_fire - perf_icache_rsp_fire; - assign perf_dcache_pending_read_cycle = perf_dcache_rd_req_per_cycle - perf_dcache_rsp_per_cycle; - - always @(posedge clk) begin - if (reset) begin - perf_icache_pending_reads <= '0; - perf_dcache_pending_reads <= '0; - end else begin - perf_icache_pending_reads <= $signed(perf_icache_pending_reads) + `PERF_CTR_BITS'($signed(perf_icache_pending_read_cycle)); - perf_dcache_pending_reads <= $signed(perf_dcache_pending_reads) + `PERF_CTR_BITS'($signed(perf_dcache_pending_read_cycle)); - end - end - - reg [`PERF_CTR_BITS-1:0] perf_icache_lat; - reg [`PERF_CTR_BITS-1:0] perf_dcache_lat; - - always @(posedge clk) begin - if (reset) begin - perf_ifetches <= '0; - perf_loads <= '0; - perf_stores <= '0; - perf_icache_lat <= '0; - perf_dcache_lat <= '0; - end else begin - perf_ifetches <= perf_ifetches + `PERF_CTR_BITS'(perf_icache_req_fire); - perf_loads <= perf_loads + `PERF_CTR_BITS'(perf_dcache_rd_req_per_cycle); - perf_stores <= perf_stores + `PERF_CTR_BITS'(perf_dcache_wr_req_per_cycle); - perf_icache_lat <= perf_icache_lat + perf_icache_pending_reads; - perf_dcache_lat <= perf_dcache_lat + perf_dcache_pending_reads; - end - end - - assign pipeline_perf_if.ifetches = perf_ifetches; - assign pipeline_perf_if.loads = perf_loads; - assign pipeline_perf_if.stores = perf_stores; - assign pipeline_perf_if.load_latency = perf_dcache_lat; - assign pipeline_perf_if.ifetch_latency = perf_icache_lat; - assign pipeline_perf_if.load_latency = perf_dcache_lat; - -`endif - -endmodule +// Copyright © 2019-2023 +// +// Licensed 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. + +`include "VX_define.vh" + +`ifdef EXT_F_ENABLE +`include "VX_fpu_define.vh" +`endif + +module VX_core import VX_gpu_pkg::*; #( + parameter CORE_ID = 0 +) ( + `SCOPE_IO_DECL + + // Clock + input wire clk, + input wire reset, + +`ifdef PERF_ENABLE + VX_mem_perf_if.slave mem_perf_if, +`endif + + VX_dcr_bus_if.slave dcr_bus_if, + + VX_mem_bus_if.master dcache_bus_if [DCACHE_NUM_REQS], + + VX_mem_bus_if.master icache_bus_if, + +`ifdef GBAR_ENABLE + VX_gbar_bus_if.master gbar_bus_if, +`endif + + // simulation helper signals + output wire sim_ebreak, + output wire [`NUM_REGS-1:0][`XLEN-1:0] sim_wb_value, + + // Status + output wire busy +); + VX_schedule_if schedule_if(); + VX_fetch_if fetch_if(); + VX_decode_if decode_if(); + VX_sched_csr_if sched_csr_if(); + VX_decode_sched_if decode_sched_if(); + VX_commit_sched_if commit_sched_if(); + VX_commit_csr_if commit_csr_if(); + VX_branch_ctl_if branch_ctl_if[`NUM_ALU_BLOCKS](); + VX_warp_ctl_if warp_ctl_if(); + + VX_dispatch_if alu_dispatch_if[`ISSUE_WIDTH](); + VX_commit_if alu_commit_if[`ISSUE_WIDTH](); + + VX_dispatch_if lsu_dispatch_if[`ISSUE_WIDTH](); + VX_commit_if lsu_commit_if[`ISSUE_WIDTH](); +`ifdef EXT_F_ENABLE + VX_dispatch_if fpu_dispatch_if[`ISSUE_WIDTH](); + VX_commit_if fpu_commit_if[`ISSUE_WIDTH](); +`endif + VX_dispatch_if sfu_dispatch_if[`ISSUE_WIDTH](); + VX_commit_if sfu_commit_if[`ISSUE_WIDTH](); + + VX_writeback_if writeback_if[`ISSUE_WIDTH](); + + VX_mem_bus_if #( + .DATA_SIZE (DCACHE_WORD_SIZE), + .TAG_WIDTH (DCACHE_TAG_WIDTH) + ) dcache_bus_tmp_if[DCACHE_NUM_REQS](); + +`ifdef PERF_ENABLE + VX_mem_perf_if mem_perf_tmp_if(); + VX_pipeline_perf_if pipeline_perf_if(); + + assign mem_perf_tmp_if.icache = mem_perf_if.icache; + assign mem_perf_tmp_if.dcache = mem_perf_if.dcache; + assign mem_perf_tmp_if.l2cache = mem_perf_if.l2cache; + assign mem_perf_tmp_if.l3cache = mem_perf_if.l3cache; + assign mem_perf_tmp_if.mem = mem_perf_if.mem; +`endif + + `RESET_RELAY (dcr_data_reset, reset); + `RESET_RELAY (schedule_reset, reset); + `RESET_RELAY (fetch_reset, reset); + `RESET_RELAY (decode_reset, reset); + `RESET_RELAY (issue_reset, reset); + `RESET_RELAY (execute_reset, reset); + `RESET_RELAY (commit_reset, reset); + + base_dcrs_t base_dcrs; + + VX_dcr_data dcr_data ( + .clk (clk), + .reset (dcr_data_reset), + .dcr_bus_if (dcr_bus_if), + .base_dcrs (base_dcrs) + ); + + `SCOPE_IO_SWITCH (3) + + VX_schedule #( + .CORE_ID (CORE_ID) + ) schedule ( + .clk (clk), + .reset (schedule_reset), + + `ifdef PERF_ENABLE + .perf_schedule_if (pipeline_perf_if.schedule), + `endif + + .base_dcrs (base_dcrs), + + .warp_ctl_if (warp_ctl_if), + .branch_ctl_if (branch_ctl_if), + .decode_sched_if(decode_sched_if), + .commit_sched_if(commit_sched_if), + + .schedule_if (schedule_if), + `ifdef GBAR_ENABLE + .gbar_bus_if (gbar_bus_if), + `endif + .sched_csr_if (sched_csr_if), + + .busy (busy) + ); + + VX_fetch #( + .CORE_ID (CORE_ID) + ) fetch ( + `SCOPE_IO_BIND (0) + .clk (clk), + .reset (fetch_reset), + .icache_bus_if (icache_bus_if), + .schedule_if (schedule_if), + .fetch_if (fetch_if) + ); + + VX_decode #( + .CORE_ID (CORE_ID) + ) decode ( + .clk (clk), + .reset (decode_reset), + .fetch_if (fetch_if), + .decode_if (decode_if), + .decode_sched_if(decode_sched_if) + ); + + VX_issue #( + .CORE_ID (CORE_ID) + ) issue ( + `SCOPE_IO_BIND (1) + + .clk (clk), + .reset (issue_reset), + + `ifdef PERF_ENABLE + .perf_issue_if (pipeline_perf_if.issue), + `endif + + .decode_if (decode_if), + .writeback_if (writeback_if), + + .alu_dispatch_if(alu_dispatch_if), + .lsu_dispatch_if(lsu_dispatch_if), + `ifdef EXT_F_ENABLE + .fpu_dispatch_if(fpu_dispatch_if), + `endif + .sfu_dispatch_if(sfu_dispatch_if) + ); + + VX_execute #( + .CORE_ID (CORE_ID) + ) execute ( + `SCOPE_IO_BIND (2) + + .clk (clk), + .reset (execute_reset), + + .base_dcrs (base_dcrs), + + `ifdef PERF_ENABLE + .mem_perf_if (mem_perf_tmp_if), + .pipeline_perf_if(pipeline_perf_if), + `endif + + .dcache_bus_if (dcache_bus_tmp_if), + + `ifdef EXT_F_ENABLE + .fpu_dispatch_if(fpu_dispatch_if), + .fpu_commit_if (fpu_commit_if), + `endif + + .commit_csr_if (commit_csr_if), + .sched_csr_if (sched_csr_if), + + .alu_dispatch_if(alu_dispatch_if), + .lsu_dispatch_if(lsu_dispatch_if), + .sfu_dispatch_if(sfu_dispatch_if), + + .warp_ctl_if (warp_ctl_if), + .branch_ctl_if (branch_ctl_if), + + .alu_commit_if (alu_commit_if), + .lsu_commit_if (lsu_commit_if), + .sfu_commit_if (sfu_commit_if), + + .sim_ebreak (sim_ebreak) + ); + + VX_commit #( + .CORE_ID (CORE_ID) + ) commit ( + .clk (clk), + .reset (commit_reset), + + .alu_commit_if (alu_commit_if), + .lsu_commit_if (lsu_commit_if), + `ifdef EXT_F_ENABLE + .fpu_commit_if (fpu_commit_if), + `endif + .sfu_commit_if (sfu_commit_if), + + .writeback_if (writeback_if), + + .commit_csr_if (commit_csr_if), + .commit_sched_if(commit_sched_if), + + .sim_wb_value (sim_wb_value) + ); + +`ifdef SM_ENABLE + + VX_smem_unit #( + .CORE_ID (CORE_ID) + ) smem_unit ( + .clk (clk), + .reset (reset), + `ifdef PERF_ENABLE + .cache_perf (mem_perf_tmp_if.smem), + `endif + .dcache_bus_in_if (dcache_bus_tmp_if), + .dcache_bus_out_if (dcache_bus_if) + ); + +`else + + for (genvar i = 0; i < DCACHE_NUM_REQS; ++i) begin + `ASSIGN_VX_MEM_BUS_IF (dcache_bus_if[i], dcache_bus_tmp_if[i]); + end + +`endif + +`ifdef PERF_ENABLE + + wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_rd_req_per_cycle; + wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_wr_req_per_cycle; + wire [`CLOG2(DCACHE_NUM_REQS+1)-1:0] perf_dcache_rsp_per_cycle; + + wire [1:0] perf_icache_pending_read_cycle; + wire [`CLOG2(DCACHE_NUM_REQS+1)+1-1:0] perf_dcache_pending_read_cycle; + + reg [`PERF_CTR_BITS-1:0] perf_icache_pending_reads; + reg [`PERF_CTR_BITS-1:0] perf_dcache_pending_reads; + + reg [`PERF_CTR_BITS-1:0] perf_ifetches; + reg [`PERF_CTR_BITS-1:0] perf_loads; + reg [`PERF_CTR_BITS-1:0] perf_stores; + + wire perf_icache_req_fire = icache_bus_if.req_valid && icache_bus_if.req_ready; + wire perf_icache_rsp_fire = icache_bus_if.rsp_valid && icache_bus_if.rsp_ready; + + wire [DCACHE_NUM_REQS-1:0] perf_dcache_rd_req_fire, perf_dcache_rd_req_fire_r; + wire [DCACHE_NUM_REQS-1:0] perf_dcache_wr_req_fire, perf_dcache_wr_req_fire_r; + wire [DCACHE_NUM_REQS-1:0] perf_dcache_rsp_fire; + + for (genvar i = 0; i < DCACHE_NUM_REQS; ++i) begin + assign perf_dcache_rd_req_fire[i] = dcache_bus_if[i].req_valid && dcache_bus_if[i].req_ready && ~dcache_bus_if[i].req_data.rw; + assign perf_dcache_wr_req_fire[i] = dcache_bus_if[i].req_valid && dcache_bus_if[i].req_ready && dcache_bus_if[i].req_data.rw; + assign perf_dcache_rsp_fire[i] = dcache_bus_if[i].rsp_valid && dcache_bus_if[i].rsp_ready; + end + + `BUFFER(perf_dcache_rd_req_fire_r, perf_dcache_rd_req_fire); + `BUFFER(perf_dcache_wr_req_fire_r, perf_dcache_wr_req_fire); + + `POP_COUNT(perf_dcache_rd_req_per_cycle, perf_dcache_rd_req_fire_r); + `POP_COUNT(perf_dcache_wr_req_per_cycle, perf_dcache_wr_req_fire_r); + `POP_COUNT(perf_dcache_rsp_per_cycle, perf_dcache_rsp_fire); + + assign perf_icache_pending_read_cycle = perf_icache_req_fire - perf_icache_rsp_fire; + assign perf_dcache_pending_read_cycle = perf_dcache_rd_req_per_cycle - perf_dcache_rsp_per_cycle; + + always @(posedge clk) begin + if (reset) begin + perf_icache_pending_reads <= '0; + perf_dcache_pending_reads <= '0; + end else begin + perf_icache_pending_reads <= $signed(perf_icache_pending_reads) + `PERF_CTR_BITS'($signed(perf_icache_pending_read_cycle)); + perf_dcache_pending_reads <= $signed(perf_dcache_pending_reads) + `PERF_CTR_BITS'($signed(perf_dcache_pending_read_cycle)); + end + end + + reg [`PERF_CTR_BITS-1:0] perf_icache_lat; + reg [`PERF_CTR_BITS-1:0] perf_dcache_lat; + + always @(posedge clk) begin + if (reset) begin + perf_ifetches <= '0; + perf_loads <= '0; + perf_stores <= '0; + perf_icache_lat <= '0; + perf_dcache_lat <= '0; + end else begin + perf_ifetches <= perf_ifetches + `PERF_CTR_BITS'(perf_icache_req_fire); + perf_loads <= perf_loads + `PERF_CTR_BITS'(perf_dcache_rd_req_per_cycle); + perf_stores <= perf_stores + `PERF_CTR_BITS'(perf_dcache_wr_req_per_cycle); + perf_icache_lat <= perf_icache_lat + perf_icache_pending_reads; + perf_dcache_lat <= perf_dcache_lat + perf_dcache_pending_reads; + end + end + + assign pipeline_perf_if.ifetches = perf_ifetches; + assign pipeline_perf_if.loads = perf_loads; + assign pipeline_perf_if.stores = perf_stores; + assign pipeline_perf_if.load_latency = perf_dcache_lat; + assign pipeline_perf_if.ifetch_latency = perf_icache_lat; + assign pipeline_perf_if.load_latency = perf_dcache_lat; + +`endif + +endmodule diff --git a/hw/rtl/core/VX_core_top.sv b/hw/rtl/core/VX_core_top.sv index 6ecd4772..83318086 100644 --- a/hw/rtl/core/VX_core_top.sv +++ b/hw/rtl/core/VX_core_top.sv @@ -129,12 +129,12 @@ module VX_core_top import VX_gpu_pkg::*; #( assign icache_rsp_ready = icache_bus_if.rsp_ready; `ifdef PERF_ENABLE - VX_mem_perf_if mem_perf_if(); - assign mem_perf_if.smem = '0; + VX_mem_perf_if mem_perf_if(); assign mem_perf_if.icache = '0; assign mem_perf_if.dcache = '0; assign mem_perf_if.l2cache = '0; - assign mem_perf_if.l3cache = '0; + assign mem_perf_if.l3cache = '0; + assign mem_perf_if.smem = '0; assign mem_perf_if.mem = '0; `endif diff --git a/hw/rtl/core/VX_csr_data.sv b/hw/rtl/core/VX_csr_data.sv index 1b370260..b1e68437 100644 --- a/hw/rtl/core/VX_csr_data.sv +++ b/hw/rtl/core/VX_csr_data.sv @@ -33,7 +33,6 @@ import VX_fpu_pkg::*; `ifdef PERF_ENABLE VX_mem_perf_if.slave mem_perf_if, VX_pipeline_perf_if.slave pipeline_perf_if, - VX_sfu_perf_if.slave sfu_perf_if, `endif VX_commit_csr_if.slave commit_csr_if, @@ -187,103 +186,107 @@ import VX_fpu_pkg::*; `VX_DCR_MPM_CLASS_CORE: begin case (read_addr) // PERF: pipeline - `VX_CSR_MPM_SCHED_ID : read_data_ro_r = pipeline_perf_if.sched_idles[31:0]; - `VX_CSR_MPM_SCHED_ID_H : read_data_ro_r = 32'(pipeline_perf_if.sched_idles[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_SCHED_ST : read_data_ro_r = pipeline_perf_if.sched_stalls[31:0]; - `VX_CSR_MPM_SCHED_ST_H : read_data_ro_r = 32'(pipeline_perf_if.sched_stalls[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_IBUF_ST : read_data_ro_r = pipeline_perf_if.ibf_stalls[31:0]; - `VX_CSR_MPM_IBUF_ST_H : read_data_ro_r = 32'(pipeline_perf_if.ibf_stalls[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_SCRB_ST : read_data_ro_r = pipeline_perf_if.scb_stalls[31:0]; - `VX_CSR_MPM_SCRB_ST_H : read_data_ro_r = 32'(pipeline_perf_if.scb_stalls[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_SCRB_ALU : read_data_ro_r = 32'(pipeline_perf_if.scb_uses[`EX_ALU][`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_SCRB_ALU_H : read_data_ro_r = pipeline_perf_if.scb_uses[`EX_ALU][31:0]; + `VX_CSR_MPM_SCHED_ID : read_data_ro_r = pipeline_perf_if.sched_idles[31:0]; + `VX_CSR_MPM_SCHED_ID_H : read_data_ro_r = 32'(pipeline_perf_if.sched_idles[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SCHED_ST : read_data_ro_r = pipeline_perf_if.sched_stalls[31:0]; + `VX_CSR_MPM_SCHED_ST_H : read_data_ro_r = 32'(pipeline_perf_if.sched_stalls[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_IBUF_ST : read_data_ro_r = pipeline_perf_if.ibf_stalls[31:0]; + `VX_CSR_MPM_IBUF_ST_H : read_data_ro_r = 32'(pipeline_perf_if.ibf_stalls[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SCRB_ST : read_data_ro_r = pipeline_perf_if.scb_stalls[31:0]; + `VX_CSR_MPM_SCRB_ST_H : read_data_ro_r = 32'(pipeline_perf_if.scb_stalls[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SCRB_ALU : read_data_ro_r = pipeline_perf_if.units_uses[`EX_ALU][31:0]; + `VX_CSR_MPM_SCRB_ALU_H : read_data_ro_r = 32'(pipeline_perf_if.units_uses[`EX_ALU][`PERF_CTR_BITS-1:32]); `ifdef EXT_F_ENABLE - `VX_CSR_MPM_SCRB_FPU : read_data_ro_r = 32'(pipeline_perf_if.scb_uses[`EX_FPU][`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_SCRB_FPU_H : read_data_ro_r = pipeline_perf_if.scb_uses[`EX_FPU][31:0]; + `VX_CSR_MPM_SCRB_FPU : read_data_ro_r = pipeline_perf_if.units_uses[`EX_FPU][31:0]; + `VX_CSR_MPM_SCRB_FPU_H : read_data_ro_r = 32'(pipeline_perf_if.units_uses[`EX_FPU][`PERF_CTR_BITS-1:32]); `else - `VX_CSR_MPM_SCRB_FPU : read_data_ro_r = '0; - `VX_CSR_MPM_SCRB_FPU_H : read_data_ro_r = '0; + `VX_CSR_MPM_SCRB_FPU : read_data_ro_r = '0; + `VX_CSR_MPM_SCRB_FPU_H : read_data_ro_r = '0; `endif - `VX_CSR_MPM_SCRB_LSU : read_data_ro_r = 32'(pipeline_perf_if.scb_uses[`EX_LSU][`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_SCRB_LSU_H : read_data_ro_r = pipeline_perf_if.scb_uses[`EX_LSU][31:0]; - `VX_CSR_MPM_SCRB_SFU : read_data_ro_r = 32'(pipeline_perf_if.scb_uses[`EX_SFU][`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_SCRB_SFU_H : read_data_ro_r = pipeline_perf_if.scb_uses[`EX_SFU][31:0]; + `VX_CSR_MPM_SCRB_LSU : read_data_ro_r = pipeline_perf_if.units_uses[`EX_LSU][31:0]; + `VX_CSR_MPM_SCRB_LSU_H : read_data_ro_r = 32'(pipeline_perf_if.units_uses[`EX_LSU][`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SCRB_SFU : read_data_ro_r = pipeline_perf_if.units_uses[`EX_SFU][31:0]; + `VX_CSR_MPM_SCRB_SFU_H : read_data_ro_r = 32'(pipeline_perf_if.units_uses[`EX_SFU][`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SCRB_CSRS : read_data_ro_r = pipeline_perf_if.sfu_uses[`SFU_CSRS][31:0]; + `VX_CSR_MPM_SCRB_CSRS_H : read_data_ro_r = 32'(pipeline_perf_if.sfu_uses[`SFU_CSRS][`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SCRB_WCTL : read_data_ro_r = pipeline_perf_if.sfu_uses[`SFU_WCTL][31:0]; + `VX_CSR_MPM_SCRB_WCTL_H : read_data_ro_r = 32'(pipeline_perf_if.sfu_uses[`SFU_WCTL][`PERF_CTR_BITS-1:32]); // PERF: memory - `VX_CSR_MPM_IFETCHES : read_data_ro_r = pipeline_perf_if.ifetches[31:0]; - `VX_CSR_MPM_IFETCHES_H : read_data_ro_r = 32'(pipeline_perf_if.ifetches[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_LOADS : read_data_ro_r = pipeline_perf_if.loads[31:0]; - `VX_CSR_MPM_LOADS_H : read_data_ro_r = 32'(pipeline_perf_if.loads[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_STORES : read_data_ro_r = pipeline_perf_if.stores[31:0]; - `VX_CSR_MPM_STORES_H : read_data_ro_r = 32'(pipeline_perf_if.stores[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_IFETCH_LT : read_data_ro_r = pipeline_perf_if.ifetch_latency[31:0]; - `VX_CSR_MPM_IFETCH_LT_H : read_data_ro_r = 32'(pipeline_perf_if.ifetch_latency[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_LOAD_LT : read_data_ro_r = pipeline_perf_if.load_latency[31:0]; - `VX_CSR_MPM_LOAD_LT_H : read_data_ro_r = 32'(pipeline_perf_if.load_latency[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_IFETCHES : read_data_ro_r = pipeline_perf_if.ifetches[31:0]; + `VX_CSR_MPM_IFETCHES_H : read_data_ro_r = 32'(pipeline_perf_if.ifetches[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_LOADS : read_data_ro_r = pipeline_perf_if.loads[31:0]; + `VX_CSR_MPM_LOADS_H : read_data_ro_r = 32'(pipeline_perf_if.loads[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_STORES : read_data_ro_r = pipeline_perf_if.stores[31:0]; + `VX_CSR_MPM_STORES_H : read_data_ro_r = 32'(pipeline_perf_if.stores[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_IFETCH_LT : read_data_ro_r = pipeline_perf_if.ifetch_latency[31:0]; + `VX_CSR_MPM_IFETCH_LT_H : read_data_ro_r = 32'(pipeline_perf_if.ifetch_latency[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_LOAD_LT : read_data_ro_r = pipeline_perf_if.load_latency[31:0]; + `VX_CSR_MPM_LOAD_LT_H : read_data_ro_r = 32'(pipeline_perf_if.load_latency[`PERF_CTR_BITS-1:32]); default:; endcase end `VX_DCR_MPM_CLASS_MEM: begin case (read_addr) // PERF: icache - `VX_CSR_MPM_ICACHE_READS : read_data_ro_r = mem_perf_if.icache.reads[31:0]; - `VX_CSR_MPM_ICACHE_READS_H : read_data_ro_r = 32'(mem_perf_if.icache.reads[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_ICACHE_MISS_R : read_data_ro_r = mem_perf_if.icache.read_misses[31:0]; - `VX_CSR_MPM_ICACHE_MISS_R_H : read_data_ro_r = 32'(mem_perf_if.icache.read_misses[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_ICACHE_MSHR_ST : read_data_ro_r = mem_perf_if.icache.mshr_stalls[31:0]; - `VX_CSR_MPM_ICACHE_MSHR_ST_H : read_data_ro_r = 32'(mem_perf_if.icache.mshr_stalls[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_ICACHE_READS : read_data_ro_r = mem_perf_if.icache.reads[31:0]; + `VX_CSR_MPM_ICACHE_READS_H : read_data_ro_r = 32'(mem_perf_if.icache.reads[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_ICACHE_MISS_R : read_data_ro_r = mem_perf_if.icache.read_misses[31:0]; + `VX_CSR_MPM_ICACHE_MISS_R_H : read_data_ro_r = 32'(mem_perf_if.icache.read_misses[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_ICACHE_MSHR_ST : read_data_ro_r = mem_perf_if.icache.mshr_stalls[31:0]; + `VX_CSR_MPM_ICACHE_MSHR_ST_H: read_data_ro_r = 32'(mem_perf_if.icache.mshr_stalls[`PERF_CTR_BITS-1:32]); // PERF: dcache - `VX_CSR_MPM_DCACHE_READS : read_data_ro_r = mem_perf_if.dcache.reads[31:0]; - `VX_CSR_MPM_DCACHE_READS_H : read_data_ro_r = 32'(mem_perf_if.dcache.reads[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_DCACHE_WRITES : read_data_ro_r = mem_perf_if.dcache.writes[31:0]; - `VX_CSR_MPM_DCACHE_WRITES_H : read_data_ro_r = 32'(mem_perf_if.dcache.writes[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_DCACHE_MISS_R : read_data_ro_r = mem_perf_if.dcache.read_misses[31:0]; - `VX_CSR_MPM_DCACHE_MISS_R_H : read_data_ro_r = 32'(mem_perf_if.dcache.read_misses[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_DCACHE_MISS_W : read_data_ro_r = mem_perf_if.dcache.write_misses[31:0]; - `VX_CSR_MPM_DCACHE_MISS_W_H : read_data_ro_r = 32'(mem_perf_if.dcache.write_misses[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_DCACHE_BANK_ST : read_data_ro_r = mem_perf_if.dcache.bank_stalls[31:0]; - `VX_CSR_MPM_DCACHE_BANK_ST_H : read_data_ro_r = 32'(mem_perf_if.dcache.bank_stalls[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_DCACHE_MSHR_ST : read_data_ro_r = mem_perf_if.dcache.mshr_stalls[31:0]; - `VX_CSR_MPM_DCACHE_MSHR_ST_H : read_data_ro_r = 32'(mem_perf_if.dcache.mshr_stalls[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_DCACHE_READS : read_data_ro_r = mem_perf_if.dcache.reads[31:0]; + `VX_CSR_MPM_DCACHE_READS_H : read_data_ro_r = 32'(mem_perf_if.dcache.reads[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_DCACHE_WRITES : read_data_ro_r = mem_perf_if.dcache.writes[31:0]; + `VX_CSR_MPM_DCACHE_WRITES_H : read_data_ro_r = 32'(mem_perf_if.dcache.writes[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_DCACHE_MISS_R : read_data_ro_r = mem_perf_if.dcache.read_misses[31:0]; + `VX_CSR_MPM_DCACHE_MISS_R_H : read_data_ro_r = 32'(mem_perf_if.dcache.read_misses[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_DCACHE_MISS_W : read_data_ro_r = mem_perf_if.dcache.write_misses[31:0]; + `VX_CSR_MPM_DCACHE_MISS_W_H : read_data_ro_r = 32'(mem_perf_if.dcache.write_misses[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_DCACHE_BANK_ST : read_data_ro_r = mem_perf_if.dcache.bank_stalls[31:0]; + `VX_CSR_MPM_DCACHE_BANK_ST_H: read_data_ro_r = 32'(mem_perf_if.dcache.bank_stalls[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_DCACHE_MSHR_ST : read_data_ro_r = mem_perf_if.dcache.mshr_stalls[31:0]; + `VX_CSR_MPM_DCACHE_MSHR_ST_H: read_data_ro_r = 32'(mem_perf_if.dcache.mshr_stalls[`PERF_CTR_BITS-1:32]); // PERF: smem - `VX_CSR_MPM_SMEM_READS : read_data_ro_r = mem_perf_if.smem.reads[31:0]; - `VX_CSR_MPM_SMEM_READS_H : read_data_ro_r = 32'(mem_perf_if.smem.reads[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_SMEM_WRITES : read_data_ro_r = mem_perf_if.smem.writes[31:0]; - `VX_CSR_MPM_SMEM_WRITES_H : read_data_ro_r = 32'(mem_perf_if.smem.writes[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_SMEM_BANK_ST : read_data_ro_r = mem_perf_if.smem.bank_stalls[31:0]; - `VX_CSR_MPM_SMEM_BANK_ST_H : read_data_ro_r = 32'(mem_perf_if.smem.bank_stalls[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SMEM_READS : read_data_ro_r = mem_perf_if.smem.reads[31:0]; + `VX_CSR_MPM_SMEM_READS_H : read_data_ro_r = 32'(mem_perf_if.smem.reads[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SMEM_WRITES : read_data_ro_r = mem_perf_if.smem.writes[31:0]; + `VX_CSR_MPM_SMEM_WRITES_H : read_data_ro_r = 32'(mem_perf_if.smem.writes[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_SMEM_BANK_ST : read_data_ro_r = mem_perf_if.smem.bank_stalls[31:0]; + `VX_CSR_MPM_SMEM_BANK_ST_H : read_data_ro_r = 32'(mem_perf_if.smem.bank_stalls[`PERF_CTR_BITS-1:32]); // PERF: l2cache - `VX_CSR_MPM_L2CACHE_READS : read_data_ro_r = mem_perf_if.l2cache.reads[31:0]; - `VX_CSR_MPM_L2CACHE_READS_H : read_data_ro_r = 32'(mem_perf_if.l2cache.reads[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_L2CACHE_WRITES : read_data_ro_r = mem_perf_if.l2cache.writes[31:0]; - `VX_CSR_MPM_L2CACHE_WRITES_H : read_data_ro_r = 32'(mem_perf_if.l2cache.writes[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_L2CACHE_MISS_R : read_data_ro_r = mem_perf_if.l2cache.read_misses[31:0]; - `VX_CSR_MPM_L2CACHE_MISS_R_H : read_data_ro_r = 32'(mem_perf_if.l2cache.read_misses[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_L2CACHE_MISS_W : read_data_ro_r = mem_perf_if.l2cache.write_misses[31:0]; - `VX_CSR_MPM_L2CACHE_MISS_W_H : read_data_ro_r = 32'(mem_perf_if.l2cache.write_misses[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_L2CACHE_BANK_ST : read_data_ro_r = mem_perf_if.l2cache.bank_stalls[31:0]; - `VX_CSR_MPM_L2CACHE_BANK_ST_H : read_data_ro_r = 32'(mem_perf_if.l2cache.bank_stalls[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_L2CACHE_MSHR_ST : read_data_ro_r = mem_perf_if.l2cache.mshr_stalls[31:0]; - `VX_CSR_MPM_L2CACHE_MSHR_ST_H : read_data_ro_r = 32'(mem_perf_if.l2cache.mshr_stalls[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_L2CACHE_READS : read_data_ro_r = mem_perf_if.l2cache.reads[31:0]; + `VX_CSR_MPM_L2CACHE_READS_H : read_data_ro_r = 32'(mem_perf_if.l2cache.reads[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_L2CACHE_WRITES : read_data_ro_r = mem_perf_if.l2cache.writes[31:0]; + `VX_CSR_MPM_L2CACHE_WRITES_H: read_data_ro_r = 32'(mem_perf_if.l2cache.writes[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_L2CACHE_MISS_R : read_data_ro_r = mem_perf_if.l2cache.read_misses[31:0]; + `VX_CSR_MPM_L2CACHE_MISS_R_H: read_data_ro_r = 32'(mem_perf_if.l2cache.read_misses[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_L2CACHE_MISS_W : read_data_ro_r = mem_perf_if.l2cache.write_misses[31:0]; + `VX_CSR_MPM_L2CACHE_MISS_W_H: read_data_ro_r = 32'(mem_perf_if.l2cache.write_misses[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_L2CACHE_BANK_ST : read_data_ro_r = mem_perf_if.l2cache.bank_stalls[31:0]; + `VX_CSR_MPM_L2CACHE_BANK_ST_H: read_data_ro_r = 32'(mem_perf_if.l2cache.bank_stalls[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_L2CACHE_MSHR_ST : read_data_ro_r = mem_perf_if.l2cache.mshr_stalls[31:0]; + `VX_CSR_MPM_L2CACHE_MSHR_ST_H: read_data_ro_r = 32'(mem_perf_if.l2cache.mshr_stalls[`PERF_CTR_BITS-1:32]); // PERF: l3cache - `VX_CSR_MPM_L3CACHE_READS : read_data_ro_r = mem_perf_if.l3cache.reads[31:0]; - `VX_CSR_MPM_L3CACHE_READS_H : read_data_ro_r = 32'(mem_perf_if.l3cache.reads[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_L3CACHE_WRITES : read_data_ro_r = mem_perf_if.l3cache.writes[31:0]; - `VX_CSR_MPM_L3CACHE_WRITES_H : read_data_ro_r = 32'(mem_perf_if.l3cache.writes[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_L3CACHE_MISS_R : read_data_ro_r = mem_perf_if.l3cache.read_misses[31:0]; - `VX_CSR_MPM_L3CACHE_MISS_R_H : read_data_ro_r = 32'(mem_perf_if.l3cache.read_misses[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_L3CACHE_MISS_W : read_data_ro_r = mem_perf_if.l3cache.write_misses[31:0]; - `VX_CSR_MPM_L3CACHE_MISS_W_H : read_data_ro_r = 32'(mem_perf_if.l3cache.write_misses[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_L3CACHE_BANK_ST : read_data_ro_r = mem_perf_if.l3cache.bank_stalls[31:0]; - `VX_CSR_MPM_L3CACHE_BANK_ST_H : read_data_ro_r = 32'(mem_perf_if.l3cache.bank_stalls[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_L3CACHE_MSHR_ST : read_data_ro_r = mem_perf_if.l3cache.mshr_stalls[31:0]; - `VX_CSR_MPM_L3CACHE_MSHR_ST_H : read_data_ro_r = 32'(mem_perf_if.l3cache.mshr_stalls[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_L3CACHE_READS : read_data_ro_r = mem_perf_if.l3cache.reads[31:0]; + `VX_CSR_MPM_L3CACHE_READS_H : read_data_ro_r = 32'(mem_perf_if.l3cache.reads[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_L3CACHE_WRITES : read_data_ro_r = mem_perf_if.l3cache.writes[31:0]; + `VX_CSR_MPM_L3CACHE_WRITES_H: read_data_ro_r = 32'(mem_perf_if.l3cache.writes[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_L3CACHE_MISS_R : read_data_ro_r = mem_perf_if.l3cache.read_misses[31:0]; + `VX_CSR_MPM_L3CACHE_MISS_R_H: read_data_ro_r = 32'(mem_perf_if.l3cache.read_misses[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_L3CACHE_MISS_W : read_data_ro_r = mem_perf_if.l3cache.write_misses[31:0]; + `VX_CSR_MPM_L3CACHE_MISS_W_H: read_data_ro_r = 32'(mem_perf_if.l3cache.write_misses[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_L3CACHE_BANK_ST : read_data_ro_r = mem_perf_if.l3cache.bank_stalls[31:0]; + `VX_CSR_MPM_L3CACHE_BANK_ST_H: read_data_ro_r = 32'(mem_perf_if.l3cache.bank_stalls[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_L3CACHE_MSHR_ST : read_data_ro_r = mem_perf_if.l3cache.mshr_stalls[31:0]; + `VX_CSR_MPM_L3CACHE_MSHR_ST_H: read_data_ro_r = 32'(mem_perf_if.l3cache.mshr_stalls[`PERF_CTR_BITS-1:32]); // PERF: memory - `VX_CSR_MPM_MEM_READS : read_data_ro_r = mem_perf_if.mem.reads[31:0]; - `VX_CSR_MPM_MEM_READS_H : read_data_ro_r = 32'(mem_perf_if.mem.reads[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_MEM_WRITES : read_data_ro_r = mem_perf_if.mem.writes[31:0]; - `VX_CSR_MPM_MEM_WRITES_H : read_data_ro_r = 32'(mem_perf_if.mem.writes[`PERF_CTR_BITS-1:32]); - `VX_CSR_MPM_MEM_LT : read_data_ro_r = mem_perf_if.mem.latency[31:0]; - `VX_CSR_MPM_MEM_LT_H : read_data_ro_r = 32'(mem_perf_if.mem.latency[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_MEM_READS : read_data_ro_r = mem_perf_if.mem.reads[31:0]; + `VX_CSR_MPM_MEM_READS_H : read_data_ro_r = 32'(mem_perf_if.mem.reads[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_MEM_WRITES : read_data_ro_r = mem_perf_if.mem.writes[31:0]; + `VX_CSR_MPM_MEM_WRITES_H : read_data_ro_r = 32'(mem_perf_if.mem.writes[`PERF_CTR_BITS-1:32]); + `VX_CSR_MPM_MEM_LT : read_data_ro_r = mem_perf_if.mem.latency[31:0]; + `VX_CSR_MPM_MEM_LT_H : read_data_ro_r = 32'(mem_perf_if.mem.latency[`PERF_CTR_BITS-1:32]); default:; endcase end @@ -303,8 +306,6 @@ import VX_fpu_pkg::*; `RUNTIME_ASSERT(~read_enable || read_addr_valid_r, ("%t: *** invalid CSR read address: 0x%0h (#%0d)", $time, read_addr, read_uuid)) `ifdef PERF_ENABLE - wire [`PERF_CTR_BITS-1:0] perf_wctl_stalls = sfu_perf_if.wctl_stalls; - `UNUSED_VAR (perf_wctl_stalls); `UNUSED_VAR (mem_perf_if.icache); `UNUSED_VAR (mem_perf_if.smem); `endif diff --git a/hw/rtl/core/VX_csr_unit.sv b/hw/rtl/core/VX_csr_unit.sv index 14b633fa..91cb37ab 100644 --- a/hw/rtl/core/VX_csr_unit.sv +++ b/hw/rtl/core/VX_csr_unit.sv @@ -25,7 +25,6 @@ module VX_csr_unit import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE VX_mem_perf_if.slave mem_perf_if, VX_pipeline_perf_if.slave pipeline_perf_if, - VX_sfu_perf_if.slave sfu_perf_if, `endif `ifdef EXT_F_ENABLE @@ -81,7 +80,6 @@ module VX_csr_unit import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE .mem_perf_if (mem_perf_if), .pipeline_perf_if(pipeline_perf_if), - .sfu_perf_if (sfu_perf_if), `endif .commit_csr_if (commit_csr_if), diff --git a/hw/rtl/core/VX_issue.sv b/hw/rtl/core/VX_issue.sv index 912abc97..1ba4ca28 100644 --- a/hw/rtl/core/VX_issue.sv +++ b/hw/rtl/core/VX_issue.sv @@ -61,7 +61,8 @@ module VX_issue #( .reset (scoreboard_reset), `ifdef PERF_ENABLE .perf_scb_stalls(perf_issue_if.scb_stalls), - .perf_scb_uses (perf_issue_if.scb_uses), + .perf_units_uses(perf_issue_if.units_uses), + .perf_sfu_uses (perf_issue_if.sfu_uses), `endif .writeback_if (writeback_if), .ibuffer_if (ibuffer_if), diff --git a/hw/rtl/core/VX_scoreboard.sv b/hw/rtl/core/VX_scoreboard.sv index 1c5f3676..a4792c8d 100644 --- a/hw/rtl/core/VX_scoreboard.sv +++ b/hw/rtl/core/VX_scoreboard.sv @@ -21,7 +21,8 @@ module VX_scoreboard import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE output reg [`PERF_CTR_BITS-1:0] perf_scb_stalls, - output reg [`PERF_CTR_BITS-1:0] perf_scb_uses [`NUM_EX_UNITS], + output reg [`PERF_CTR_BITS-1:0] perf_units_uses [`NUM_EX_UNITS], + output reg [`PERF_CTR_BITS-1:0] perf_sfu_uses [`NUM_SFU_UNITS], `endif VX_writeback_if.slave writeback_if [`ISSUE_WIDTH], @@ -32,21 +33,66 @@ module VX_scoreboard import VX_gpu_pkg::*; #( localparam DATAW = `UUID_WIDTH + ISSUE_WIS_W + `NUM_THREADS + `XLEN + `EX_BITS + `INST_OP_BITS + `INST_MOD_BITS + 1 + 1 + `XLEN + (`NR_BITS * 4) + 1; `ifdef PERF_ENABLE - wire [`NUM_EX_UNITS-1:0] perf_uses_per_cycle; - wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] perf_stalls_per_cycle; - reg [`ISSUE_WIDTH-1:0][`NUM_EX_UNITS-1:0] perf_issue_uses_per_cycle; - wire [`ISSUE_WIDTH-1:0] perf_issue_stalls_per_cycle; + reg [`ISSUE_WIDTH-1:0][`NUM_EX_UNITS-1:0] perf_issue_units_per_cycle; + wire [`NUM_EX_UNITS-1:0] perf_units_per_cycle, perf_units_per_cycle_r; - `POP_COUNT(perf_stalls_per_cycle, perf_issue_stalls_per_cycle); + reg [`ISSUE_WIDTH-1:0][`NUM_SFU_UNITS-1:0] perf_issue_sfu_per_cycle; + wire [`NUM_SFU_UNITS-1:0] perf_sfu_per_cycle, perf_sfu_per_cycle_r; + + wire [`ISSUE_WIDTH-1:0] perf_issue_stalls_per_cycle; + wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] perf_stalls_per_cycle, perf_stalls_per_cycle_r; + + `POP_COUNT(perf_stalls_per_cycle, perf_issue_stalls_per_cycle); VX_reduce #( .DATAW_IN (`NUM_EX_UNITS), .N (`ISSUE_WIDTH), .OP ("|") - ) reduce ( - .data_in (perf_issue_uses_per_cycle), - .data_out (perf_uses_per_cycle) + ) perf_units_reduce ( + .data_in (perf_issue_units_per_cycle), + .data_out (perf_units_per_cycle) + ); + + VX_reduce #( + .DATAW_IN (`NUM_SFU_UNITS), + .N (`ISSUE_WIDTH), + .OP ("|") + ) perf_sfu_reduce ( + .data_in (perf_issue_sfu_per_cycle), + .data_out (perf_sfu_per_cycle) ); + + `BUFFER(perf_stalls_per_cycle_r, perf_stalls_per_cycle); + `BUFFER(perf_units_per_cycle_r, perf_units_per_cycle); + `BUFFER(perf_sfu_per_cycle_r, perf_sfu_per_cycle); + + always @(posedge clk) begin + if (reset) begin + perf_scb_stalls <= '0; + end else begin + perf_scb_stalls <= perf_scb_stalls + `PERF_CTR_BITS'(perf_stalls_per_cycle_r); + end + end + + for (genvar i = 0; i < `NUM_EX_UNITS; ++i) begin + always @(posedge clk) begin + if (reset) begin + perf_units_uses[i] <= '0; + end else begin + perf_units_uses[i] <= perf_units_uses[i] + `PERF_CTR_BITS'(perf_units_per_cycle_r[i]); + end + end + end + + for (genvar i = 0; i < `NUM_SFU_UNITS; ++i) begin + always @(posedge clk) begin + if (reset) begin + perf_sfu_uses[i] <= '0; + end else begin + perf_sfu_uses[i] <= perf_sfu_uses[i] + `PERF_CTR_BITS'(perf_sfu_per_cycle_r[i]); + end + end + end `endif for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin @@ -60,21 +106,46 @@ module VX_scoreboard import VX_gpu_pkg::*; #( wire inuse_rs3 = inuse_regs[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs3]; `ifdef PERF_ENABLE - reg [`UP(ISSUE_RATIO)-1:0][`NUM_REGS-1:0][`EX_BITS-1:0] inuse_units; + reg [`UP(ISSUE_RATIO)-1:0][`NUM_REGS-1:0][`EX_WIDTH-1:0] inuse_units; + reg [`UP(ISSUE_RATIO)-1:0][`NUM_REGS-1:0][`SFU_WIDTH-1:0] inuse_sfu; + + reg [`SFU_WIDTH-1:0] sfu_type; always @(*) begin - perf_issue_uses_per_cycle[i] = '0; + case (scoreboard_if[i].data.op_type) + `INST_SFU_CSRRW, + `INST_SFU_CSRRS, + `INST_SFU_CSRRC: sfu_type = `SFU_CSRS; + default: sfu_type = `SFU_WCTL; + endcase + end + + always @(*) begin + perf_issue_units_per_cycle[i] = '0; + perf_issue_sfu_per_cycle[i] = '0; if (ibuffer_if[i].valid) begin if (inuse_rd) begin - perf_issue_uses_per_cycle[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd]] = 1; + perf_issue_units_per_cycle[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd]] = 1; + if (inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd] == `EX_SFU) begin + perf_issue_sfu_per_cycle[i][inuse_sfu[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd]] = 1; + end end if (inuse_rs1) begin - perf_issue_uses_per_cycle[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs1]] = 1; + perf_issue_units_per_cycle[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs1]] = 1; + if (inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs1] == `EX_SFU) begin + perf_issue_sfu_per_cycle[i][inuse_sfu[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs1]] = 1; + end end if (inuse_rs2) begin - perf_issue_uses_per_cycle[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs2]] = 1; + perf_issue_units_per_cycle[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs2]] = 1; + if (inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs2] == `EX_SFU) begin + perf_issue_sfu_per_cycle[i][inuse_sfu[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs2]] = 1; + end end if (inuse_rs3) begin - perf_issue_uses_per_cycle[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs3]] = 1; + perf_issue_units_per_cycle[i][inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs3]] = 1; + if (inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs3] == `EX_SFU) begin + perf_issue_sfu_per_cycle[i][inuse_sfu[ibuffer_if[i].data.wis][ibuffer_if[i].data.rs3]] = 1; + end end end end @@ -97,8 +168,8 @@ module VX_scoreboard import VX_gpu_pkg::*; #( always @(posedge clk) begin if (reset) begin valid_out_r <= 0; - inuse_regs <= '0; - end else begin + inuse_regs <= '0; + end else begin if (writeback_fire) begin inuse_regs[writeback_if[i].data.wis][writeback_if[i].data.rd] <= 0; end @@ -109,6 +180,9 @@ module VX_scoreboard import VX_gpu_pkg::*; #( inuse_regs[scoreboard_if[i].data.wis][scoreboard_if[i].data.rd] <= 1; `ifdef PERF_ENABLE inuse_units[scoreboard_if[i].data.wis][scoreboard_if[i].data.rd] <= scoreboard_if[i].data.ex_type; + if (scoreboard_if[i].data.ex_type == `EX_SFU) begin + inuse_sfu[scoreboard_if[i].data.wis][scoreboard_if[i].data.rd] <= sfu_type; + end `endif end valid_out_r <= 0; @@ -141,7 +215,7 @@ module VX_scoreboard import VX_gpu_pkg::*; #( timeout_ctr <= '0; end end - end + end `RUNTIME_ASSERT((timeout_ctr < `STALL_TIMEOUT), ("%t: *** core%0d-scoreboard-timeout: wid=%0d, PC=0x%0h, tmask=%b, cycles=%0d, inuse=%b (#%0d)", @@ -153,32 +227,6 @@ module VX_scoreboard import VX_gpu_pkg::*; #( $time, CORE_ID, wis_to_wid(writeback_if[i].data.wis, i), writeback_if[i].data.PC, writeback_if[i].data.tmask, writeback_if[i].data.rd, writeback_if[i].data.uuid)); `endif - end - -`ifdef PERF_ENABLE - wire [`CLOG2(`ISSUE_WIDTH+1)-1:0] perf_stalls_per_cycle_r; - wire [`NUM_EX_UNITS-1:0] perf_uses_per_cycle_r; - - `BUFFER(perf_stalls_per_cycle_r, perf_stalls_per_cycle); - `BUFFER(perf_uses_per_cycle_r, perf_uses_per_cycle); - - always @(posedge clk) begin - if (reset) begin - perf_scb_stalls <= '0; - end else begin - perf_scb_stalls <= perf_scb_stalls + `PERF_CTR_BITS'(perf_stalls_per_cycle_r); - end end - for (genvar i = 0; i < `NUM_EX_UNITS; ++i) begin - always @(posedge clk) begin - if (reset) begin - perf_scb_uses[i] <= '0; - end else begin - perf_scb_uses[i] <= perf_scb_uses[i] + `PERF_CTR_BITS'(perf_uses_per_cycle_r[i]); - end - end - end -`endif - endmodule diff --git a/hw/rtl/core/VX_sfu_unit.sv b/hw/rtl/core/VX_sfu_unit.sv index b531e75b..6fb2cb9f 100644 --- a/hw/rtl/core/VX_sfu_unit.sv +++ b/hw/rtl/core/VX_sfu_unit.sv @@ -48,7 +48,7 @@ module VX_sfu_unit import VX_gpu_pkg::*; #( localparam RSP_ARB_DATAW = `UUID_WIDTH + `NW_WIDTH + NUM_LANES + (NUM_LANES * `XLEN) + `NR_BITS + 1 + `XLEN + PID_WIDTH + 1 + 1; localparam RSP_ARB_SIZE = 1 + 1; localparam RSP_ARB_IDX_WCTL = 0; - localparam RSP_ARB_IDX_CSR = 1; + localparam RSP_ARB_IDX_CSRS = 1; VX_execute_if #( .NUM_LANES (NUM_LANES) @@ -71,9 +71,6 @@ module VX_sfu_unit import VX_gpu_pkg::*; #( wire [RSP_ARB_SIZE-1:0] rsp_arb_ready_in; wire [RSP_ARB_SIZE-1:0][RSP_ARB_DATAW-1:0] rsp_arb_data_in; -`ifdef PERF_ENABLE - VX_sfu_perf_if sfu_perf_if(); -`endif // Warp control block VX_execute_if #( @@ -129,7 +126,6 @@ module VX_sfu_unit import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE .mem_perf_if (mem_perf_if), .pipeline_perf_if(pipeline_perf_if), - .sfu_perf_if (sfu_perf_if), `endif `ifdef EXT_F_ENABLE @@ -141,21 +137,21 @@ module VX_sfu_unit import VX_gpu_pkg::*; #( .commit_if (csr_commit_if) ); - assign rsp_arb_valid_in[RSP_ARB_IDX_CSR] = csr_commit_if.valid; - assign rsp_arb_data_in[RSP_ARB_IDX_CSR] = csr_commit_if.data; - assign csr_commit_if.ready = rsp_arb_ready_in[RSP_ARB_IDX_CSR]; + assign rsp_arb_valid_in[RSP_ARB_IDX_CSRS] = csr_commit_if.valid; + assign rsp_arb_data_in[RSP_ARB_IDX_CSRS] = csr_commit_if.data; + assign csr_commit_if.ready = rsp_arb_ready_in[RSP_ARB_IDX_CSRS]; // can accept new request? reg sfu_req_ready; always @(*) begin case (execute_if[0].data.op_type) - `INST_SFU_CSRRW, - `INST_SFU_CSRRS, - `INST_SFU_CSRRC: sfu_req_ready = csr_execute_if.ready; + `INST_SFU_CSRRW, + `INST_SFU_CSRRS, + `INST_SFU_CSRRC: sfu_req_ready = csr_execute_if.ready; default: sfu_req_ready = wctl_execute_if.ready; endcase - end + end assign execute_if[0].ready = sfu_req_ready; // response arbitration @@ -194,19 +190,4 @@ module VX_sfu_unit import VX_gpu_pkg::*; #( .commit_out_if (commit_if) ); -`ifdef PERF_ENABLE - reg [`PERF_CTR_BITS-1:0] perf_wctl_stalls; - - wire wctl_execute_stall = wctl_execute_if.valid && ~wctl_execute_if.ready; - - always @(posedge clk) begin - if (reset) begin - perf_wctl_stalls <= '0; - end else begin - perf_wctl_stalls <= perf_wctl_stalls + `PERF_CTR_BITS'(wctl_execute_stall); - end - end - assign sfu_perf_if.wctl_stalls = perf_wctl_stalls; -`endif - endmodule diff --git a/hw/rtl/interfaces/VX_pipeline_perf_if.sv b/hw/rtl/interfaces/VX_pipeline_perf_if.sv index 2ae0f678..7d421875 100644 --- a/hw/rtl/interfaces/VX_pipeline_perf_if.sv +++ b/hw/rtl/interfaces/VX_pipeline_perf_if.sv @@ -18,7 +18,8 @@ interface VX_pipeline_perf_if (); wire [`PERF_CTR_BITS-1:0] sched_stalls; wire [`PERF_CTR_BITS-1:0] ibf_stalls; wire [`PERF_CTR_BITS-1:0] scb_stalls; - wire [`PERF_CTR_BITS-1:0] scb_uses [`NUM_EX_UNITS]; + wire [`PERF_CTR_BITS-1:0] units_uses [`NUM_EX_UNITS]; + wire [`PERF_CTR_BITS-1:0] sfu_uses [`NUM_SFU_UNITS]; wire [`PERF_CTR_BITS-1:0] ifetches; wire [`PERF_CTR_BITS-1:0] loads; @@ -34,7 +35,8 @@ interface VX_pipeline_perf_if (); modport issue ( output ibf_stalls, output scb_stalls, - output scb_uses + output units_uses, + output sfu_uses ); modport slave ( @@ -42,7 +44,8 @@ interface VX_pipeline_perf_if (); input sched_stalls, input ibf_stalls, input scb_stalls, - input scb_uses, + input units_uses, + input sfu_uses, input ifetches, input loads, input stores, diff --git a/runtime/common/utils.cpp b/runtime/common/utils.cpp index 5f472c84..104a2795 100644 --- a/runtime/common/utils.cpp +++ b/runtime/common/utils.cpp @@ -208,6 +208,8 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { uint64_t scrb_fpu = 0; uint64_t scrb_lsu = 0; uint64_t scrb_sfu = 0; + uint64_t scrb_wctl = 0; + uint64_t scrb_csrs = 0; uint64_t ifetches = 0; uint64_t loads = 0; uint64_t stores = 0; @@ -268,44 +270,69 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { // PERF: pipeline // scheduler idles { - uint64_t sched_idles_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCHED_ID); - int idles_percent_per_core = calcAvgPercent(sched_idles_per_core, cycles_per_core); - if (num_cores > 1) fprintf(stream, "PERF: core%d: scheduler idles=%ld (%d%%)\n", core_id, sched_idles_per_core, idles_percent_per_core); + uint64_t sched_idles_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCHED_ID); + if (num_cores > 1) { + int idles_percent_per_core = calcAvgPercent(sched_idles_per_core, cycles_per_core); + fprintf(stream, "PERF: core%d: scheduler idle=%ld (%d%%)\n", core_id, sched_idles_per_core, idles_percent_per_core); + } sched_idles += sched_idles_per_core; } // scheduler stalls { - uint64_t sched_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCHED_ST); - int stalls_percent_per_core = calcAvgPercent(sched_stalls_per_core, cycles_per_core); - if (num_cores > 1) fprintf(stream, "PERF: core%d: scheduler stalls=%ld (%d%%)\n", core_id, sched_stalls_per_core, stalls_percent_per_core); + uint64_t sched_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCHED_ST); + if (num_cores > 1) { + int stalls_percent_per_core = calcAvgPercent(sched_stalls_per_core, cycles_per_core); + fprintf(stream, "PERF: core%d: scheduler stalls=%ld (%d%%)\n", core_id, sched_stalls_per_core, stalls_percent_per_core); + } sched_stalls += sched_stalls_per_core; } // ibuffer_stalls { - uint64_t ibuffer_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_IBUF_ST); - int ibuffer_percent_per_core = calcAvgPercent(ibuffer_stalls_per_core, cycles_per_core); - if (num_cores > 1) fprintf(stream, "PERF: core%d: ibuffer stalls=%ld (%d%%)\n", core_id, ibuffer_stalls_per_core, ibuffer_percent_per_core); + uint64_t ibuffer_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_IBUF_ST); + if (num_cores > 1) { + int ibuffer_percent_per_core = calcAvgPercent(ibuffer_stalls_per_core, cycles_per_core); + fprintf(stream, "PERF: core%d: ibuffer stalls=%ld (%d%%)\n", core_id, ibuffer_stalls_per_core, ibuffer_percent_per_core); + } ibuffer_stalls += ibuffer_stalls_per_core; } - // scrb_stalls + // issue_stalls { uint64_t scrb_stalls_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_ST); uint64_t scrb_alu_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_ALU); uint64_t scrb_fpu_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_FPU); uint64_t scrb_lsu_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_LSU); - uint64_t scrb_sfu_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_SFU); - uint64_t scrb_total = scrb_alu_per_core + scrb_fpu_per_core + scrb_lsu_per_core + scrb_sfu_per_core; + uint64_t scrb_sfu_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_SFU); scrb_alu += scrb_alu_per_core; scrb_fpu += scrb_fpu_per_core; scrb_lsu += scrb_lsu_per_core; scrb_sfu += scrb_sfu_per_core; - if (num_cores > 1) fprintf(stream, "PERF: core%d: scoreboard stalls=%ld (alu=%d%%, fpu=%d%%, lsu=%d%%, sfu=%d%%)\n", core_id, scrb_stalls_per_core, + if (num_cores > 1) { + uint64_t scrb_total = scrb_alu_per_core + scrb_fpu_per_core + scrb_lsu_per_core + scrb_sfu_per_core; + fprintf(stream, "PERF: core%d: issue stalls=%ld (alu=%d%%, fpu=%d%%, lsu=%d%%, sfu=%d%%)\n", core_id, scrb_stalls_per_core, calcAvgPercent(scrb_alu_per_core, scrb_total), calcAvgPercent(scrb_fpu_per_core, scrb_total), calcAvgPercent(scrb_lsu_per_core, scrb_total), calcAvgPercent(scrb_sfu_per_core, scrb_total)); + } scrb_stalls += scrb_stalls_per_core; } + // sfu_stalls + { + uint64_t scrb_sfu_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_SFU); + uint64_t scrb_wctl_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_WCTL); + uint64_t scrb_csrs_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_CSRS); + if (num_cores > 1) { + uint64_t sfu_total = scrb_wctl_per_core + scrb_csrs_per_core + scrb_tex_per_core + scrb_raster_per_core + scrb_om_per_core; + fprintf(stream, "PERF: core%d: sfu stalls=%ld (scrs=%d%%, wctl=%d%%)\n" + , core_id + , scrb_sfu_per_core + , calcAvgPercent(scrb_csrs_per_core, sfu_total) + , calcAvgPercent(scrb_wctl_per_core, sfu_total) + ); + } + scrb_wctl += scrb_wctl_per_core; + scrb_csrs += scrb_csrs_per_core; + } // PERF: memory // ifetches { @@ -313,9 +340,11 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { if (num_cores > 1) fprintf(stream, "PERF: core%d: ifetches=%ld\n", core_id, ifetches_per_core); ifetches += ifetches_per_core; - uint64_t ifetch_lat_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_IFETCH_LT); - int mem_avg_lat = caclAverage(ifetch_lat_per_core, ifetches_per_core); - if (num_cores > 1) fprintf(stream, "PERF: core%d: ifetch latency=%d cycles\n", core_id, mem_avg_lat); + uint64_t ifetch_lat_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_IFETCH_LT); + if (num_cores > 1) { + int mem_avg_lat = caclAverage(ifetch_lat_per_core, ifetches_per_core); + fprintf(stream, "PERF: core%d: ifetch latency=%d cycles\n", core_id, mem_avg_lat); + } ifetch_lat += ifetch_lat_per_core; } // loads @@ -324,9 +353,11 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { if (num_cores > 1) fprintf(stream, "PERF: core%d: loads=%ld\n", core_id, loads_per_core); loads += loads_per_core; - uint64_t load_lat_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_LOAD_LT); - int mem_avg_lat = caclAverage(load_lat_per_core, loads_per_core); - if (num_cores > 1) fprintf(stream, "PERF: core%d: load latency=%d cycles\n", core_id, mem_avg_lat); + uint64_t load_lat_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_LOAD_LT); + if (num_cores > 1) { + int mem_avg_lat = caclAverage(load_lat_per_core, loads_per_core); + fprintf(stream, "PERF: core%d: load latency=%d cycles\n", core_id, mem_avg_lat); + } load_lat += load_lat_per_core; } // stores @@ -428,14 +459,20 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { int ifetch_avg_lat = (int)(double(ifetch_lat) / double(ifetches)); int load_avg_lat = (int)(double(load_lat) / double(loads)); uint64_t scrb_total = scrb_alu + scrb_fpu + scrb_lsu + scrb_sfu; - fprintf(stream, "PERF: scheduler idles=%ld (%d%%)\n", sched_idles, sched_idles_percent); + uint64_t sfu_total = scrb_wctl + scrb_csrs; + fprintf(stream, "PERF: scheduler idle=%ld (%d%%)\n", sched_idles, sched_idles_percent); fprintf(stream, "PERF: scheduler stalls=%ld (%d%%)\n", sched_stalls, sched_stalls_percent); fprintf(stream, "PERF: ibuffer stalls=%ld (%d%%)\n", ibuffer_stalls, ibuffer_percent); - fprintf(stream, "PERF: scoreboard stalls=%ld (alu=%d%%, fpu=%d%%, lsu=%d%%, sfu=%d%%)\n", scrb_stalls, + fprintf(stream, "PERF: issue stalls=%ld (alu=%d%%, fpu=%d%%, lsu=%d%%, sfu=%d%%)\n", scrb_stalls, calcAvgPercent(scrb_alu, scrb_total), calcAvgPercent(scrb_fpu, scrb_total), calcAvgPercent(scrb_lsu, scrb_total), - calcAvgPercent(scrb_sfu, scrb_total)); + calcAvgPercent(scrb_sfu, scrb_total)); + fprintf(stream, "PERF: sfu stalls=%ld (scrs=%d%%, wctl=%d%%)\n" + , scrb_sfu + , calcAvgPercent(scrb_csrs, sfu_total) + , calcAvgPercent(scrb_wctl, sfu_total) + ); fprintf(stream, "PERF: ifetches=%ld\n", ifetches); fprintf(stream, "PERF: loads=%ld\n", loads); fprintf(stream, "PERF: stores=%ld\n", stores); diff --git a/sim/simx/cluster.cpp b/sim/simx/cluster.cpp index 7f690fb6..3ac80cb6 100644 --- a/sim/simx/cluster.cpp +++ b/sim/simx/cluster.cpp @@ -18,20 +18,20 @@ using namespace vortex; Cluster::Cluster(const SimContext& ctx, uint32_t cluster_id, ProcessorImpl* processor, - const Arch &arch, const - DCRS &dcrs) + const Arch &arch, + const DCRS &dcrs) : SimObject(ctx, "cluster") , mem_req_port(this) , mem_rsp_port(this) , cluster_id_(cluster_id) - , sockets_(NUM_SOCKETS) - , barriers_(arch.num_barriers(), 0) , processor_(processor) + , sockets_(NUM_SOCKETS) + , barriers_(arch.num_barriers(), 0) , cores_per_socket_(arch.socket_size()) { char sname[100]; - auto sockets_per_cluster = sockets_.size(); + uint32_t sockets_per_cluster = sockets_.size(); // create sockets @@ -43,7 +43,10 @@ Cluster::Cluster(const SimContext& ctx, for (uint32_t i = 0; i < sockets_per_cluster; ++i) { uint32_t socket_id = cluster_id * sockets_per_cluster + i; - auto socket = Socket::Create(socket_id, this, arch, dcrs); + auto socket = Socket::Create(socket_id, + this, + arch, + dcrs); socket->icache_mem_req_port.bind(&icache_switch->ReqIn.at(i)); icache_switch->RspIn.at(i).bind(&socket->icache_mem_rsp_port); @@ -154,7 +157,7 @@ void Cluster::barrier(uint32_t bar_id, uint32_t count, uint32_t core_id) { } Cluster::PerfStats Cluster::perf_stats() const { - Cluster::PerfStats perf; - perf.l2cache = l2cache_->perf_stats(); - return perf; + PerfStats perf_stats; + perf_stats.l2cache = l2cache_->perf_stats(); + return perf_stats; } \ No newline at end of file diff --git a/sim/simx/cluster.h b/sim/simx/cluster.h index 2547486d..81e93e10 100644 --- a/sim/simx/cluster.h +++ b/sim/simx/cluster.h @@ -17,6 +17,7 @@ #include "dcrs.h" #include "arch.h" #include "cache_cluster.h" +#include "shared_mem.h" #include "core.h" #include "socket.h" #include "constants.h" @@ -27,13 +28,8 @@ class ProcessorImpl; class Cluster : public SimObject { public: - struct PerfStats { + struct PerfStats { CacheSim::PerfStats l2cache; - - PerfStats& operator+=(const PerfStats& rhs) { - this->l2cache += rhs.l2cache; - return *this; - } }; SimPort mem_req_port; @@ -67,15 +63,15 @@ public: void barrier(uint32_t bar_id, uint32_t count, uint32_t core_id); - Cluster::PerfStats perf_stats() const; + PerfStats perf_stats() const; private: - uint32_t cluster_id_; - std::vector sockets_; - std::vector barriers_; - CacheSim::Ptr l2cache_; - ProcessorImpl* processor_; - uint32_t cores_per_socket_; + uint32_t cluster_id_; + ProcessorImpl* processor_; + std::vector sockets_; + std::vector barriers_; + CacheSim::Ptr l2cache_; + uint32_t cores_per_socket_; }; } // namespace vortex \ No newline at end of file diff --git a/sim/simx/core.cpp b/sim/simx/core.cpp index 7a549ebd..1c155011 100644 --- a/sim/simx/core.cpp +++ b/sim/simx/core.cpp @@ -28,13 +28,18 @@ using namespace vortex; -Core::Core(const SimContext& ctx, uint32_t core_id, Socket* socket, const Arch &arch, const DCRS &dcrs) +Core::Core(const SimContext& ctx, + uint32_t core_id, + Socket* socket, + const Arch &arch, + const DCRS &dcrs) : SimObject(ctx, "core") , icache_req_ports(1, this) , icache_rsp_ports(1, this) , dcache_req_ports(NUM_LSU_LANES, this) , dcache_rsp_ports(NUM_LSU_LANES, this) , core_id_(core_id) + , socket_(socket) , arch_(arch) , dcrs_(dcrs) , decoder_(arch) @@ -42,7 +47,7 @@ Core::Core(const SimContext& ctx, uint32_t core_id, Socket* socket, const Arch & , barriers_(arch.num_barriers(), 0) , fcsrs_(arch.num_warps(), 0) , ibuffers_(arch.num_warps(), IBUF_SIZE) - , scoreboard_(arch_) + , scoreboard_(arch_) , operands_(ISSUE_WIDTH) , dispatchers_((uint32_t)ExeType::ExeTypeCount) , exe_units_((uint32_t)ExeType::ExeTypeCount) @@ -50,8 +55,7 @@ Core::Core(const SimContext& ctx, uint32_t core_id, Socket* socket, const Arch & , fetch_latch_("fetch") , decode_latch_("decode") , pending_icache_(arch_.num_warps()) - , csrs_(arch.num_warps()) - , socket_(socket) + , csrs_(arch.num_warps()) , commit_arbs_(ISSUE_WIDTH) { char sname[100]; @@ -69,6 +73,7 @@ Core::Core(const SimContext& ctx, uint32_t core_id, Socket* socket, const Arch & } // initialize shared memory + snprintf(sname, 100, "core%d-shared_mem", core_id); shared_mem_ = SharedMem::Create(sname, SharedMem::Config{ (1 << SMEM_LOG_SIZE), sizeof(Word), @@ -77,17 +82,17 @@ Core::Core(const SimContext& ctx, uint32_t core_id, Socket* socket, const Arch & false }); for (uint32_t i = 0; i < NUM_LSU_LANES; ++i) { - snprintf(sname, 100, "smem_demux%d_%d", core_id, i); - auto smem_demux = SMemDemux::Create(sname); - - smem_demux->ReqDC.bind(&dcache_req_ports.at(i)); - dcache_rsp_ports.at(i).bind(&smem_demux->RspDC); + snprintf(sname, 100, "core%d-smem_demux%d", core_id, i); + auto smem_demux = SMemDemux::Create(sname); + + smem_demux->ReqDC.bind(&dcache_req_ports.at(i)); + dcache_rsp_ports.at(i).bind(&smem_demux->RspDC); - smem_demux->ReqSM.bind(&shared_mem_->Inputs.at(i)); - shared_mem_->Outputs.at(i).bind(&smem_demux->RspSM); + smem_demux->ReqSM.bind(&shared_mem_->Inputs.at(i)); + shared_mem_->Outputs.at(i).bind(&smem_demux->RspSM); - smem_demuxs_.at(i) = smem_demux; - } + smem_demuxs_.at(i) = smem_demux; + } // initialize dispatchers dispatchers_.at((int)ExeType::ALU) = SimPlatform::instance().create_object(arch, 2, NUM_ALU_BLOCKS, NUM_ALU_LANES); @@ -103,7 +108,7 @@ Core::Core(const SimContext& ctx, uint32_t core_id, Socket* socket, const Arch & // bind commit arbiters for (uint32_t i = 0; i < ISSUE_WIDTH; ++i) { - snprintf(sname, 100, "commit-arb%d", i); + snprintf(sname, 100, "core%d-commit-arb%d", core_id, i); auto arbiter = TraceSwitch::Create(sname, ArbiterType::RoundRobin, (uint32_t)ExeType::ExeTypeCount, 1); for (uint32_t j = 0; j < (uint32_t)ExeType::ExeTypeCount; ++j) { exe_units_.at(j)->Outputs.at(i).bind(&arbiter->Inputs.at(j)); @@ -128,7 +133,7 @@ void Core::reset() { for (auto& exe_unit : exe_units_) { exe_unit->reset(); } - + for (auto& commit_arb : commit_arbs_) { commit_arb->reset(); } @@ -184,7 +189,7 @@ void Core::schedule() { } } if (scheduled_warp == -1) { - ++perf_stats_.sched_idles; + ++perf_stats_.sched_idle; return; } @@ -229,7 +234,7 @@ void Core::fetch() { mem_req.uuid = trace->uuid; icache_req_ports.at(0).send(mem_req, 2); DT(3, "icache-req: addr=0x" << std::hex << mem_req.addr << ", tag=" << mem_req.tag << ", " << *trace); - fetch_latch_.pop(); + fetch_latch_.pop(); ++perf_stats_.ifetches; ++pending_ifetches_; } @@ -311,7 +316,21 @@ void Core::issue() { case ExeType::ALU: ++perf_stats_.scrb_alu; break; case ExeType::FPU: ++perf_stats_.scrb_fpu; break; case ExeType::LSU: ++perf_stats_.scrb_lsu; break; - case ExeType::SFU: ++perf_stats_.scrb_sfu; break; + case ExeType::SFU: { + ++perf_stats_.scrb_sfu; + switch (use.sfu_type) { + case SfuType::TMC: + case SfuType::WSPAWN: + case SfuType::SPLIT: + case SfuType::JOIN: + case SfuType::BAR: + case SfuType::PRED: ++perf_stats_.scrb_wctl; break; + case SfuType::CSRRW: + case SfuType::CSRRS: + case SfuType::CSRRC: ++perf_stats_.scrb_csrs; break; + default: assert(false); + } + } break; default: assert(false); } } @@ -356,7 +375,6 @@ void Core::commit() { auto& commit_arb = commit_arbs_.at(i); if (commit_arb->Outputs.at(0).empty()) continue; - auto trace = commit_arb->Outputs.at(0).front(); // advance to commit stage @@ -558,8 +576,8 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { break; case VX_DCR_MPM_CLASS_CORE: { switch (addr) { - case VX_CSR_MPM_SCHED_ID: return perf_stats_.sched_idles & 0xffffffff; - case VX_CSR_MPM_SCHED_ID_H:return perf_stats_.sched_idles >> 32; + case VX_CSR_MPM_SCHED_ID: return perf_stats_.sched_idle & 0xffffffff; + case VX_CSR_MPM_SCHED_ID_H:return perf_stats_.sched_idle >> 32; case VX_CSR_MPM_SCHED_ST: return perf_stats_.sched_stalls & 0xffffffff; case VX_CSR_MPM_SCHED_ST_H:return perf_stats_.sched_stalls >> 32; case VX_CSR_MPM_IBUF_ST: return perf_stats_.ibuf_stalls & 0xffffffff; @@ -574,6 +592,10 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { case VX_CSR_MPM_SCRB_LSU_H:return perf_stats_.scrb_lsu >> 32; case VX_CSR_MPM_SCRB_SFU: return perf_stats_.scrb_sfu & 0xffffffff; case VX_CSR_MPM_SCRB_SFU_H:return perf_stats_.scrb_sfu >> 32; + case VX_CSR_MPM_SCRB_WCTL: return perf_stats_.scrb_wctl & 0xffffffff; + case VX_CSR_MPM_SCRB_WCTL_H: return perf_stats_.scrb_wctl >> 32; + case VX_CSR_MPM_SCRB_CSRS: return perf_stats_.scrb_csrs & 0xffffffff; + case VX_CSR_MPM_SCRB_CSRS_H: return perf_stats_.scrb_csrs >> 32; case VX_CSR_MPM_IFETCHES: return perf_stats_.ifetches & 0xffffffff; case VX_CSR_MPM_IFETCHES_H: return perf_stats_.ifetches >> 32; case VX_CSR_MPM_LOADS: return perf_stats_.loads & 0xffffffff; @@ -588,6 +610,7 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { } break; case VX_DCR_MPM_CLASS_MEM: { auto proc_perf = socket_->cluster()->processor()->perf_stats(); + auto cluster_perf = socket_->cluster()->perf_stats(); auto socket_perf = socket_->perf_stats(); auto smem_perf = shared_mem_->perf_stats(); switch (addr) { @@ -611,18 +634,18 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { case VX_CSR_MPM_DCACHE_MSHR_ST: return socket_perf.dcache.mshr_stalls & 0xffffffff; case VX_CSR_MPM_DCACHE_MSHR_ST_H: return socket_perf.dcache.mshr_stalls >> 32; - case VX_CSR_MPM_L2CACHE_READS: return proc_perf.clusters.l2cache.reads & 0xffffffff; - case VX_CSR_MPM_L2CACHE_READS_H: return proc_perf.clusters.l2cache.reads >> 32; - case VX_CSR_MPM_L2CACHE_WRITES: return proc_perf.clusters.l2cache.writes & 0xffffffff; - case VX_CSR_MPM_L2CACHE_WRITES_H: return proc_perf.clusters.l2cache.writes >> 32; - case VX_CSR_MPM_L2CACHE_MISS_R: return proc_perf.clusters.l2cache.read_misses & 0xffffffff; - case VX_CSR_MPM_L2CACHE_MISS_R_H: return proc_perf.clusters.l2cache.read_misses >> 32; - case VX_CSR_MPM_L2CACHE_MISS_W: return proc_perf.clusters.l2cache.write_misses & 0xffffffff; - case VX_CSR_MPM_L2CACHE_MISS_W_H: return proc_perf.clusters.l2cache.write_misses >> 32; - case VX_CSR_MPM_L2CACHE_BANK_ST: return proc_perf.clusters.l2cache.bank_stalls & 0xffffffff; - case VX_CSR_MPM_L2CACHE_BANK_ST_H:return proc_perf.clusters.l2cache.bank_stalls >> 32; - case VX_CSR_MPM_L2CACHE_MSHR_ST: return proc_perf.clusters.l2cache.mshr_stalls & 0xffffffff; - case VX_CSR_MPM_L2CACHE_MSHR_ST_H:return proc_perf.clusters.l2cache.mshr_stalls >> 32; + case VX_CSR_MPM_L2CACHE_READS: return cluster_perf.l2cache.reads & 0xffffffff; + case VX_CSR_MPM_L2CACHE_READS_H: return cluster_perf.l2cache.reads >> 32; + case VX_CSR_MPM_L2CACHE_WRITES: return cluster_perf.l2cache.writes & 0xffffffff; + case VX_CSR_MPM_L2CACHE_WRITES_H: return cluster_perf.l2cache.writes >> 32; + case VX_CSR_MPM_L2CACHE_MISS_R: return cluster_perf.l2cache.read_misses & 0xffffffff; + case VX_CSR_MPM_L2CACHE_MISS_R_H: return cluster_perf.l2cache.read_misses >> 32; + case VX_CSR_MPM_L2CACHE_MISS_W: return cluster_perf.l2cache.write_misses & 0xffffffff; + case VX_CSR_MPM_L2CACHE_MISS_W_H: return cluster_perf.l2cache.write_misses >> 32; + case VX_CSR_MPM_L2CACHE_BANK_ST: return cluster_perf.l2cache.bank_stalls & 0xffffffff; + case VX_CSR_MPM_L2CACHE_BANK_ST_H:return cluster_perf.l2cache.bank_stalls >> 32; + case VX_CSR_MPM_L2CACHE_MSHR_ST: return cluster_perf.l2cache.mshr_stalls & 0xffffffff; + case VX_CSR_MPM_L2CACHE_MSHR_ST_H:return cluster_perf.l2cache.mshr_stalls >> 32; case VX_CSR_MPM_L3CACHE_READS: return proc_perf.l3cache.reads & 0xffffffff; case VX_CSR_MPM_L3CACHE_READS_H: return proc_perf.l3cache.reads >> 32; @@ -638,7 +661,7 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { case VX_CSR_MPM_L3CACHE_MSHR_ST_H:return proc_perf.l3cache.mshr_stalls >> 32; case VX_CSR_MPM_MEM_READS: return proc_perf.mem_reads & 0xffffffff; - case VX_CSR_MPM_MEM_READS_H: return proc_perf.mem_reads >> 32; + case VX_CSR_MPM_MEM_READS_H: return proc_perf.mem_reads >> 32; case VX_CSR_MPM_MEM_WRITES: return proc_perf.mem_writes & 0xffffffff; case VX_CSR_MPM_MEM_WRITES_H: return proc_perf.mem_writes >> 32; case VX_CSR_MPM_MEM_LT: return proc_perf.mem_latency & 0xffffffff; @@ -652,6 +675,10 @@ uint32_t Core::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { case VX_CSR_MPM_SMEM_BANK_ST_H: return smem_perf.bank_stalls >> 32; } } break; + default: { + std::cout << std::dec << "Error: invalid MPM CLASS: value=" << perf_class << std::endl; + std::abort(); + } break; } } else { std::cout << std::hex << "Error: invalid CSR read addr=0x" << addr << std::endl; diff --git a/sim/simx/core.h b/sim/simx/core.h index 343fdb31..0ccb5d02 100644 --- a/sim/simx/core.h +++ b/sim/simx/core.h @@ -49,7 +49,7 @@ public: struct PerfStats { uint64_t cycles; uint64_t instrs; - uint64_t sched_idles; + uint64_t sched_idle; uint64_t sched_stalls; uint64_t ibuf_stalls; uint64_t scrb_stalls; @@ -57,6 +57,8 @@ public: uint64_t scrb_fpu; uint64_t scrb_lsu; uint64_t scrb_sfu; + uint64_t scrb_wctl; + uint64_t scrb_csrs; uint64_t ifetches; uint64_t loads; uint64_t stores; @@ -66,7 +68,7 @@ public: PerfStats() : cycles(0) , instrs(0) - , sched_idles(0) + , sched_idle(0) , sched_stalls(0) , ibuf_stalls(0) , scrb_stalls(0) @@ -74,6 +76,8 @@ public: , scrb_fpu(0) , scrb_lsu(0) , scrb_sfu(0) + , scrb_wctl(0) + , scrb_csrs(0) , ifetches(0) , loads(0) , stores(0) @@ -88,7 +92,11 @@ public: std::vector> dcache_req_ports; std::vector> dcache_rsp_ports; - Core(const SimContext& ctx, uint32_t core_id, Socket* socket, const Arch &arch, const DCRS &dcrs); + Core(const SimContext& ctx, + uint32_t core_id, + Socket* socket, + const Arch &arch, + const DCRS &dcrs); ~Core(); @@ -158,6 +166,7 @@ private: void cout_flush(); uint32_t core_id_; + Socket* socket_; const Arch& arch_; const DCRS &dcrs_; @@ -193,10 +202,9 @@ private: PerfStats perf_stats_; - Socket* socket_; - std::vector commit_arbs_; + uint32_t commit_exe_; uint32_t ibuffer_idx_; friend class Warp; diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index 77021dbd..8e8c1062 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -113,6 +113,7 @@ void ProcessorImpl::reset() { perf_mem_writes_ = 0; perf_mem_latency_ = 0; perf_mem_pending_reads_ = 0; + } void ProcessorImpl::write_dcr(uint32_t addr, uint32_t value) { @@ -125,9 +126,6 @@ ProcessorImpl::PerfStats ProcessorImpl::perf_stats() const { perf.mem_writes = perf_mem_writes_; perf.mem_latency = perf_mem_latency_; perf.l3cache = l3cache_->perf_stats(); - for (auto cluster : clusters_) { - perf.clusters += cluster->perf_stats(); - } return perf; } diff --git a/sim/simx/processor_impl.h b/sim/simx/processor_impl.h index 02d92e95..072247a7 100644 --- a/sim/simx/processor_impl.h +++ b/sim/simx/processor_impl.h @@ -24,17 +24,10 @@ namespace vortex { class ProcessorImpl { public: struct PerfStats { + CacheSim::PerfStats l3cache; uint64_t mem_reads; uint64_t mem_writes; uint64_t mem_latency; - CacheSim::PerfStats l3cache; - Cluster::PerfStats clusters; - - PerfStats() - : mem_reads(0) - , mem_writes(0) - , mem_latency(0) - {} }; ProcessorImpl(const Arch& arch); @@ -46,7 +39,7 @@ public: void write_dcr(uint32_t addr, uint32_t value); - ProcessorImpl::PerfStats perf_stats() const; + PerfStats perf_stats() const; private: @@ -55,7 +48,7 @@ private: const Arch& arch_; std::vector> clusters_; DCRS dcrs_; - MemSim::Ptr memsim_; + MemSim::Ptr memsim_; CacheSim::Ptr l3cache_; uint64_t perf_mem_reads_; uint64_t perf_mem_writes_; diff --git a/sim/simx/scoreboard.h b/sim/simx/scoreboard.h index 5c247b73..58dbc2fb 100644 --- a/sim/simx/scoreboard.h +++ b/sim/simx/scoreboard.h @@ -25,6 +25,7 @@ public: RegType reg_type; uint32_t reg_id; ExeType exe_type; + SfuType sfu_type; uint64_t uuid; }; @@ -62,7 +63,7 @@ public: if (used_iregs.test(r)) { uint32_t tag = (r << 16) | (trace->wid << 4) | (int)RegType::Integer; auto owner = owners_.at(tag); - out.push_back({RegType::Integer, r, owner->exe_type, owner->uuid}); + out.push_back({RegType::Integer, r, owner->exe_type, owner->sfu_type, owner->uuid}); } } @@ -70,7 +71,7 @@ public: if (used_fregs.test(r)) { uint32_t tag = (r << 16) | (trace->wid << 4) | (int)RegType::Float; auto owner = owners_.at(tag); - out.push_back({RegType::Float, r, owner->exe_type, owner->uuid}); + out.push_back({RegType::Float, r, owner->exe_type, owner->sfu_type, owner->uuid}); } } @@ -78,7 +79,7 @@ public: if (used_vregs.test(r)) { uint32_t tag = (r << 16) | (trace->wid << 4) | (int)RegType::Vector; auto owner = owners_.at(tag); - out.push_back({RegType::Vector, r, owner->exe_type, owner->uuid}); + out.push_back({RegType::Vector, r, owner->exe_type, owner->sfu_type, owner->uuid}); } } diff --git a/sim/simx/socket.cpp b/sim/simx/socket.cpp index fb620d62..dd9f9697 100644 --- a/sim/simx/socket.cpp +++ b/sim/simx/socket.cpp @@ -19,16 +19,16 @@ using namespace vortex; Socket::Socket(const SimContext& ctx, uint32_t socket_id, Cluster* cluster, - const Arch &arch, const - DCRS &dcrs) + const Arch &arch, + const DCRS &dcrs) : SimObject(ctx, "socket") , icache_mem_req_port(this) , icache_mem_rsp_port(this) , dcache_mem_req_port(this) , dcache_mem_rsp_port(this) , socket_id_(socket_id) - , cores_(arch.socket_size()) , cluster_(cluster) + , cores_(arch.socket_size()) { auto cores_per_socket = cores_.size(); @@ -77,7 +77,10 @@ Socket::Socket(const SimContext& ctx, for (uint32_t i = 0; i < cores_per_socket; ++i) { uint32_t core_id = socket_id * cores_per_socket + i; - cores_.at(i) = Core::Create(core_id, this, arch, dcrs); + cores_.at(i) = Core::Create(core_id, + this, + arch, + dcrs); cores_.at(i)->icache_req_ports.at(0).bind(&icaches_->CoreReqPorts.at(i).at(0)); icaches_->CoreRspPorts.at(i).at(0).bind(&cores_.at(i)->icache_rsp_ports.at(0)); @@ -139,8 +142,8 @@ void Socket::resume(uint32_t core_index) { } Socket::PerfStats Socket::perf_stats() const { - Socket::PerfStats perf; - perf.icache = icaches_->perf_stats(); - perf.dcache = dcaches_->perf_stats(); - return perf; + PerfStats perf_stats; + perf_stats.icache = icaches_->perf_stats(); + perf_stats.dcache = dcaches_->perf_stats(); + return perf_stats; } \ No newline at end of file diff --git a/sim/simx/socket.h b/sim/simx/socket.h index 5c94c31f..5105f99e 100644 --- a/sim/simx/socket.h +++ b/sim/simx/socket.h @@ -30,12 +30,6 @@ public: struct PerfStats { CacheSim::PerfStats icache; CacheSim::PerfStats dcache; - - PerfStats& operator+=(const PerfStats& rhs) { - this->icache += rhs.icache; - this->dcache += rhs.dcache; - return *this; - } }; SimPort icache_mem_req_port; @@ -74,14 +68,14 @@ public: void resume(uint32_t core_id); - Socket::PerfStats perf_stats() const; + PerfStats perf_stats() const; private: - uint32_t socket_id_; + uint32_t socket_id_; + Cluster* cluster_; std::vector cores_; CacheCluster::Ptr icaches_; CacheCluster::Ptr dcaches_; - Cluster* cluster_; }; } // namespace vortex \ No newline at end of file diff --git a/tests/opencl/Makefile b/tests/opencl/Makefile index 5d18f9cd..92df373f 100644 --- a/tests/opencl/Makefile +++ b/tests/opencl/Makefile @@ -15,10 +15,10 @@ all: $(MAKE) -C blackscholes $(MAKE) -C transpose $(MAKE) -C convolution -# $(MAKE) -C cutcp -# $(MAKE) -C sgemm2 -# $(MAKE) -C vectorhypot -# $(MAKE) -C mri-q run-simx + $(MAKE) -C cutcp + $(MAKE) -C sgemm2 + $(MAKE) -C vectorhypot + $(MAKE) -C mri-q run-simx run-simx: $(MAKE) -C vecadd run-simx @@ -125,7 +125,7 @@ clean-all: $(MAKE) -C oclprintf clean-all $(MAKE) -C blackscholes clean-all $(MAKE) -C convolution clean-all -# $(MAKE) -C cutcp clean-all -# $(MAKE) -C sgemm2 clean-all -# $(MAKE) -C vectorhypot clean-all -# $(MAKE) -C mri-q clean-all + $(MAKE) -C cutcp clean-all + $(MAKE) -C sgemm2 clean-all + $(MAKE) -C vectorhypot clean-all + $(MAKE) -C mri-q clean-all From 36f5dd87fe4fcd34e1339df7eeb595ccbec82e09 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Thu, 28 Dec 2023 12:22:22 -0800 Subject: [PATCH 34/57] minor update --- tests/opencl/Makefile | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/opencl/Makefile b/tests/opencl/Makefile index 92df373f..5d18f9cd 100644 --- a/tests/opencl/Makefile +++ b/tests/opencl/Makefile @@ -15,10 +15,10 @@ all: $(MAKE) -C blackscholes $(MAKE) -C transpose $(MAKE) -C convolution - $(MAKE) -C cutcp - $(MAKE) -C sgemm2 - $(MAKE) -C vectorhypot - $(MAKE) -C mri-q run-simx +# $(MAKE) -C cutcp +# $(MAKE) -C sgemm2 +# $(MAKE) -C vectorhypot +# $(MAKE) -C mri-q run-simx run-simx: $(MAKE) -C vecadd run-simx @@ -125,7 +125,7 @@ clean-all: $(MAKE) -C oclprintf clean-all $(MAKE) -C blackscholes clean-all $(MAKE) -C convolution clean-all - $(MAKE) -C cutcp clean-all - $(MAKE) -C sgemm2 clean-all - $(MAKE) -C vectorhypot clean-all - $(MAKE) -C mri-q clean-all +# $(MAKE) -C cutcp clean-all +# $(MAKE) -C sgemm2 clean-all +# $(MAKE) -C vectorhypot clean-all +# $(MAKE) -C mri-q clean-all From 51e621cdf1cb95b8d05cf1e24e2bf3bfc75fe4fa Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Thu, 28 Dec 2023 16:08:26 -0800 Subject: [PATCH 35/57] minor update --- runtime/common/utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/common/utils.cpp b/runtime/common/utils.cpp index 104a2795..6d601555 100644 --- a/runtime/common/utils.cpp +++ b/runtime/common/utils.cpp @@ -322,7 +322,7 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { uint64_t scrb_wctl_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_WCTL); uint64_t scrb_csrs_per_core = get_csr_64(staging_buf.data(), VX_CSR_MPM_SCRB_CSRS); if (num_cores > 1) { - uint64_t sfu_total = scrb_wctl_per_core + scrb_csrs_per_core + scrb_tex_per_core + scrb_raster_per_core + scrb_om_per_core; + uint64_t sfu_total = scrb_wctl_per_core + scrb_csrs_per_core; fprintf(stream, "PERF: core%d: sfu stalls=%ld (scrs=%d%%, wctl=%d%%)\n" , core_id , scrb_sfu_per_core From e62d122c9b946bdec745ee3b38486c67a37aba11 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Thu, 28 Dec 2023 20:06:10 -0800 Subject: [PATCH 36/57] enabling temporary build directory for blackbox multiple instances --- ci/blackbox.sh | 159 ++++++++++++++++++++++++++++++---------- runtime/opae/Makefile | 34 ++++----- runtime/rtlsim/Makefile | 16 ++-- runtime/simx/Makefile | 14 ++-- sim/opaesim/Makefile | 10 +-- sim/rtlsim/Makefile | 6 +- sim/simx/Makefile | 2 +- 7 files changed, 158 insertions(+), 83 deletions(-) diff --git a/ci/blackbox.sh b/ci/blackbox.sh index 5e06ae65..d5deacec 100755 --- a/ci/blackbox.sh +++ b/ci/blackbox.sh @@ -16,7 +16,17 @@ show_usage() { echo "Vortex BlackBox Test Driver v1.0" - echo "Usage: $0 [[--clusters=#n] [--cores=#n] [--warps=#n] [--threads=#n] [--l2cache] [--l3cache] [[--driver=#name] [--app=#app] [--args=#args] [--debug=#level] [--scope] [--perf=#class] [--rebuild=0|1] [--log=logfile] [--help]]" + echo "Usage: $0 [[--clusters=#n] [--cores=#n] [--warps=#n] [--threads=#n] [--l2cache] [--l3cache] [[--driver=#name] [--app=#app] [--args=#args] [--debug=#level] [--scope] [--perf=#class] [--rebuild=#n] [--log=logfile] [--help]]" +} + +show_help() +{ + show_usage + echo " where" + echo "--driver: simx, rtlsim, oape, xrt" + echo "--app: any subfolder test under regression or opencl" + echo "--class: 0=disable, 1=pipeline, 2=memsys" + echo "--rebuild: 0=disable, 1=force, 2=auto, 3=temp" } SCRIPT_DIR=$(dirname "$0") @@ -36,6 +46,7 @@ SCOPE=0 HAS_ARGS=0 PERF_CLASS=0 REBUILD=2 +TEMPBUILD=0 LOGFILE=run.log for i in "$@" @@ -102,7 +113,7 @@ case $i in shift ;; --help) - show_usage + show_help exit 0 ;; *) @@ -112,6 +123,12 @@ case $i in esac done +if [ $REBUILD -eq 3 ]; +then + REBUILD=1 + TEMPBUILD=1 +fi + case $DRIVER in simx) DRIVER_PATH=$VORTEX_HOME/runtime/simx @@ -174,53 +191,119 @@ make -C $VORTEX_HOME/runtime/stub > /dev/null if [ $DEBUG -ne 0 ] then - # driver initialization - if [ $SCOPE -eq 1 ] - then - echo "running: DEBUG=$DEBUG_LEVEL SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH" - DEBUG=$DEBUG_LEVEL SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null - else - echo "running: DEBUG=$DEBUG_LEVEL CONFIGS="$CONFIGS" make -C $DRIVER_PATH" - DEBUG=$DEBUG_LEVEL CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null - fi - # running application - if [ $HAS_ARGS -eq 1 ] + if [ $TEMPBUILD -eq 1 ] then - echo "running: OPTS=$ARGS make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1" - OPTS=$ARGS make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1 - status=$? + # setup temp directory + TEMPDIR=$(mktemp -d) + mkdir -p "$TEMPDIR/$DRIVER" + + # driver initialization + if [ $SCOPE -eq 1 ] + then + echo "running: DESTDIR=$TEMPDIR/$DRIVER DEBUG=$DEBUG_LEVEL SCOPE=1 CONFIGS=$CONFIGS make -C $DRIVER_PATH" + DESTDIR="$TEMPDIR/$DRIVER" DEBUG=$DEBUG_LEVEL SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null + else + echo "running: DESTDIR=$TEMPDIR/$DRIVER DEBUG=$DEBUG_LEVEL CONFIGS=$CONFIGS make -C $DRIVER_PATH" + DESTDIR="$TEMPDIR/$DRIVER" DEBUG=$DEBUG_LEVEL CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null + fi + + # running application + if [ $HAS_ARGS -eq 1 ] + then + echo "running: VORTEX_RT_PATH=$TEMPDIR OPTS=$ARGS make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1" + VORTEX_RT_PATH=$TEMPDIR OPTS=$ARGS make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1 + status=$? + else + echo "running: VORTEX_RT_PATH=$TEMPDIR make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1" + VORTEX_RT_PATH=$TEMPDIR make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1 + status=$? + fi + + # cleanup temp directory + trap "rm -rf $TEMPDIR" EXIT else - echo "running: make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1" - make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1 - status=$? + # driver initialization + if [ $SCOPE -eq 1 ] + then + echo "running: DEBUG=$DEBUG_LEVEL SCOPE=1 CONFIGS=$CONFIGS make -C $DRIVER_PATH" + DEBUG=$DEBUG_LEVEL SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null + else + echo "running: DEBUG=$DEBUG_LEVEL CONFIGS=$CONFIGS make -C $DRIVER_PATH" + DEBUG=$DEBUG_LEVEL CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null + fi + + # running application + if [ $HAS_ARGS -eq 1 ] + then + echo "running: OPTS=$ARGS make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1" + OPTS=$ARGS make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1 + status=$? + else + echo "running: make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1" + make -C $APP_PATH run-$DRIVER > $LOGFILE 2>&1 + status=$? + fi fi if [ -f "$APP_PATH/trace.vcd" ] then mv -f $APP_PATH/trace.vcd . fi -else - # driver initialization - if [ $SCOPE -eq 1 ] +else + if [ $TEMPBUILD -eq 1 ] then - echo "running: SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH" - SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null + # setup temp directory + TEMPDIR=$(mktemp -d) + mkdir -p "$TEMPDIR/$DRIVER" + + # driver initialization + if [ $SCOPE -eq 1 ] + then + echo "running: DESTDIR=$TEMPDIR/$DRIVER SCOPE=1 CONFIGS=$CONFIGS make -C $DRIVER_PATH" + DESTDIR="$TEMPDIR/$DRIVER" SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null + else + echo "running: DESTDIR=$TEMPDIR/$DRIVER CONFIGS=$CONFIGS make -C $DRIVER_PATH" + DESTDIR="$TEMPDIR/$DRIVER" CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null + fi + + # running application + if [ $HAS_ARGS -eq 1 ] + then + echo "running: VORTEX_RT_PATH=$TEMPDIR OPTS=$ARGS make -C $APP_PATH run-$DRIVER" + VORTEX_RT_PATH=$TEMPDIR OPTS=$ARGS make -C $APP_PATH run-$DRIVER + status=$? + else + echo "running: VORTEX_RT_PATH=$TEMPDIR make -C $APP_PATH run-$DRIVER" + VORTEX_RT_PATH=$TEMPDIR make -C $APP_PATH run-$DRIVER + status=$? + fi + + # cleanup temp directory + trap "rm -rf $TEMPDIR" EXIT else - echo "running: CONFIGS="$CONFIGS" make -C $DRIVER_PATH" - CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null - fi - - # running application - if [ $HAS_ARGS -eq 1 ] - then - echo "running: OPTS=$ARGS make -C $APP_PATH run-$DRIVER" - OPTS=$ARGS make -C $APP_PATH run-$DRIVER - status=$? - else - echo "running: make -C $APP_PATH run-$DRIVER" - make -C $APP_PATH run-$DRIVER - status=$? + + # driver initialization + if [ $SCOPE -eq 1 ] + then + echo "running: SCOPE=1 CONFIGS=$CONFIGS make -C $DRIVER_PATH" + SCOPE=1 CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null + else + echo "running: CONFIGS=$CONFIGS make -C $DRIVER_PATH" + CONFIGS="$CONFIGS" make -C $DRIVER_PATH > /dev/null + fi + + # running application + if [ $HAS_ARGS -eq 1 ] + then + echo "running: OPTS=$ARGS make -C $APP_PATH run-$DRIVER" + OPTS=$ARGS make -C $APP_PATH run-$DRIVER + status=$? + else + echo "running: make -C $APP_PATH run-$DRIVER" + make -C $APP_PATH run-$DRIVER + status=$? + fi fi fi diff --git a/runtime/opae/Makefile b/runtime/opae/Makefile index 82d0b69c..153e33b3 100644 --- a/runtime/opae/Makefile +++ b/runtime/opae/Makefile @@ -1,25 +1,15 @@ XLEN ?= 32 - TARGET ?= opaesim - +DESTDIR ?= $(CURDIR) OPAESIM_DIR = ../../sim/opaesim - RTL_DIR=../../hw/rtl - SYN_DIR=../../hw/syn/altera/opae - SCRIPT_DIR=../../hw/scripts CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic -Wfatal-errors -CXXFLAGS += -I. -I../include -I../common/ -I../../hw +CXXFLAGS += -I$(DESTDIR) -I../include -I../common/ -I../../hw CXXFLAGS += -DXLEN_$(XLEN) -ifeq ($(TARGET), opaesim) - CXXFLAGS += -I$(OPAESIM_DIR) -else - CXXFLAGS += -I$(SYN_DIR) -endif - # Position independent code CXXFLAGS += -fPIC @@ -35,9 +25,11 @@ SRCS = vortex.cpp driver.cpp ../common/utils.cpp # set up target types ifeq ($(TARGET), opaesim) - CXXFLAGS += -DOPAESIM - OPAESIM = libopae-c-sim.so + OPAESIM = $(DESTDIR)/libopae-c-sim.so + CXXFLAGS += -DOPAESIM -I$(OPAESIM_DIR) + LDFLAGS += -L$(DESTDIR) -lopae-c-sim else + CXXFLAGS += -I$(SYN_DIR) ifeq ($(TARGET), asesim) CXXFLAGS += -DASESIM else @@ -65,14 +57,14 @@ endif PROJECT = libvortex.so -all: $(PROJECT) +all: $(DESTDIR)/$(PROJECT) -libopae-c-sim.so: - DESTDIR=../../runtime/opae $(MAKE) -C $(OPAESIM_DIR) ../../runtime/opae/libopae-c-sim.so +$(DESTDIR)/libopae-c-sim.so: + DESTDIR=$(DESTDIR) $(MAKE) -C $(OPAESIM_DIR) $(DESTDIR)/libopae-c-sim.so -$(PROJECT): $(SRCS) $(OPAESIM) - $(CXX) $(CXXFLAGS) $(SRCS) $(LDFLAGS) -o $(PROJECT) +$(DESTDIR)/$(PROJECT): $(SRCS) $(OPAESIM) + $(CXX) $(CXXFLAGS) $(SRCS) $(LDFLAGS) -o $@ clean: - DESTDIR=../../runtime/opae $(MAKE) -C $(OPAESIM_DIR) clean - rm -rf $(PROJECT) + DESTDIR=$(DESTDIR) $(MAKE) -C $(OPAESIM_DIR) clean + rm -rf $(DESTDIR)/$(PROJECT) diff --git a/runtime/rtlsim/Makefile b/runtime/rtlsim/Makefile index 57f58df4..4b400f84 100644 --- a/runtime/rtlsim/Makefile +++ b/runtime/rtlsim/Makefile @@ -1,5 +1,5 @@ XLEN ?= 32 - +DESTDIR ?= $(CURDIR) RTLSIM_DIR = ../../sim/rtlsim CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic -Wfatal-errors @@ -16,7 +16,7 @@ CXXFLAGS += $(CONFIGS) CXXFLAGS += -DDUMP_PERF_STATS LDFLAGS += -shared -pthread -LDFLAGS += -L. -lrtlsim +LDFLAGS += -L$(DESTDIR) -lrtlsim SRCS = vortex.cpp ../common/utils.cpp @@ -34,12 +34,12 @@ endif PROJECT = libvortex.so -all: $(PROJECT) +all: $(DESTDIR)/$(PROJECT) -$(PROJECT): $(SRCS) - DESTDIR=../../runtime/rtlsim $(MAKE) -C $(RTLSIM_DIR) ../../runtime/rtlsim/librtlsim.so - $(CXX) $(CXXFLAGS) $(SRCS) $(LDFLAGS) -o $(PROJECT) +$(DESTDIR)/$(PROJECT): $(SRCS) + DESTDIR=$(DESTDIR) $(MAKE) -C $(RTLSIM_DIR) $(DESTDIR)/librtlsim.so + $(CXX) $(CXXFLAGS) $(SRCS) $(LDFLAGS) -o $@ clean: - DESTDIR=../../runtime/rtlsim $(MAKE) -C $(RTLSIM_DIR) clean - rm -rf $(PROJECT) *.o \ No newline at end of file + DESTDIR=$(DESTDIR) $(MAKE) -C $(RTLSIM_DIR) clean + rm -rf $(DESTDIR)/$(PROJECT) *.o \ No newline at end of file diff --git a/runtime/simx/Makefile b/runtime/simx/Makefile index c9f157fd..9397ec24 100644 --- a/runtime/simx/Makefile +++ b/runtime/simx/Makefile @@ -1,5 +1,5 @@ XLEN ?= 32 - +DESTDIR ?= $(CURDIR) SIMX_DIR = ../../sim/simx CXXFLAGS += -std=c++11 -Wall -Wextra -Wfatal-errors @@ -10,7 +10,7 @@ CXXFLAGS += -DDUMP_PERF_STATS CXXFLAGS += -DXLEN_$(XLEN) LDFLAGS += -shared -pthread -LDFLAGS += -L. -lsimx +LDFLAGS += -L$(DESTDIR) -lsimx SRCS = vortex.cpp ../common/utils.cpp @@ -23,12 +23,12 @@ endif PROJECT = libvortex.so -all: $(PROJECT) +all: $(DESTDIR)/$(PROJECT) -$(PROJECT): $(SRCS) - DESTDIR=../../runtime/simx $(MAKE) -C $(SIMX_DIR) ../../runtime/simx/libsimx.so +$(DESTDIR)/$(PROJECT): $(SRCS) + DESTDIR=$(DESTDIR) $(MAKE) -C $(SIMX_DIR) $(DESTDIR)/libsimx.so $(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ clean: - DESTDIR=../../runtime/simx $(MAKE) -C $(SIMX_DIR) clean - rm -rf libsimx.so $(PROJECT) *.o \ No newline at end of file + DESTDIR=$(DESTDIR) $(MAKE) -C $(SIMX_DIR) clean + rm -rf $(DESTDIR)/$(PROJECT) *.o \ No newline at end of file diff --git a/sim/opaesim/Makefile b/sim/opaesim/Makefile index 3b906bc5..93f2da33 100644 --- a/sim/opaesim/Makefile +++ b/sim/opaesim/Makefile @@ -1,5 +1,5 @@ XLEN ?= 32 -DESTDIR ?= . +DESTDIR ?= $(CURDIR) RTL_DIR = ../../hw/rtl DPI_DIR = ../../hw/dpi AFU_DIR = $(RTL_DIR)/afu/opae @@ -119,16 +119,16 @@ PROJECT = libopae-c-sim.so all: $(DESTDIR)/$(PROJECT) $(DESTDIR)/vortex.xml: - verilator --xml-only -O0 $(VL_FLAGS) $(TOP) --xml-output $(DESTDIR)/vortex.xml + verilator --xml-only -O0 $(VL_FLAGS) $(TOP) --xml-output $@ $(DESTDIR)/scope.json: $(DESTDIR)/vortex.xml - $(SCRIPT_DIR)/scope.py $(DESTDIR)/vortex.xml -o $(DESTDIR)/scope.json + $(SCRIPT_DIR)/scope.py $^ -o $@ $(DESTDIR)/vortex_afu.h : $(AFU_DIR)/vortex_afu.vh - $(SCRIPT_DIR)/gen_config.py -i $(AFU_DIR)/vortex_afu.vh -o $(DESTDIR)/vortex_afu.h + $(SCRIPT_DIR)/gen_config.py -i $^ -o $@ $(DESTDIR)/$(PROJECT): $(SRCS) $(DESTDIR)/vortex_afu.h $(SCOPE_JSON) - verilator --build --exe -O3 $(VL_FLAGS) --cc $(TOP) --top-module $(TOP) $(SRCS) -CFLAGS '$(CXXFLAGS)' -LDFLAGS '$(LDFLAGS)' -o ../$(DESTDIR)/$(PROJECT) + verilator --build --exe -O3 $(VL_FLAGS) --cc $(TOP) --top-module $(TOP) $(SRCS) -CFLAGS '$(CXXFLAGS)' -LDFLAGS '$(LDFLAGS)' -o $@ clean: rm -rf obj_dir $(DESTDIR)/vortex.xml $(DESTDIR)/scope.json $(DESTDIR)/vortex_afu.h $(DESTDIR)/$(PROJECT) diff --git a/sim/rtlsim/Makefile b/sim/rtlsim/Makefile index 1d43ea4f..228cdd8b 100644 --- a/sim/rtlsim/Makefile +++ b/sim/rtlsim/Makefile @@ -1,5 +1,5 @@ XLEN ?= 32 -DESTDIR ?= . +DESTDIR ?= $(CURDIR) RTL_DIR = ../../hw/rtl DPI_DIR = ../../hw/dpi THIRD_PARTY_DIR = ../../third_party @@ -88,10 +88,10 @@ PROJECT = rtlsim all: $(DESTDIR)/$(PROJECT) $(DESTDIR)/$(PROJECT): $(SRCS) main.cpp - verilator --build $(VL_FLAGS) $^ -CFLAGS '$(CXXFLAGS) -DSTARTUP_ADDR=0x80000000' -LDFLAGS '$(LDFLAGS)' -o ../$@ + verilator --build $(VL_FLAGS) $^ -CFLAGS '$(CXXFLAGS) -DSTARTUP_ADDR=0x80000000' -LDFLAGS '$(LDFLAGS)' -o $@ $(DESTDIR)/lib$(PROJECT).so: $(SRCS) - verilator --build $(VL_FLAGS) $^ -CFLAGS '$(CXXFLAGS)' -LDFLAGS '-shared $(LDFLAGS)' -o ../$@ + verilator --build $(VL_FLAGS) $^ -CFLAGS '$(CXXFLAGS)' -LDFLAGS '-shared $(LDFLAGS)' -o $@ clean: rm -rf obj_dir $(DESTDIR)/$(PROJECT) $(DESTDIR)/lib$(PROJECT).so diff --git a/sim/simx/Makefile b/sim/simx/Makefile index bb67dbb5..3cce8de0 100644 --- a/sim/simx/Makefile +++ b/sim/simx/Makefile @@ -1,5 +1,5 @@ XLEN ?= 32 -DESTDIR ?= . +DESTDIR ?= $(CURDIR) RTL_DIR = ../hw/rtl THIRD_PARTY_DIR = ../../third_party From 7425446b1596600ae74f5b48f298a3c938455ca0 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Fri, 29 Dec 2023 14:11:16 -0800 Subject: [PATCH 37/57] fixed DESTDIR support in simumation Makefiles --- runtime/opae/Makefile | 15 +++++++-------- runtime/rtlsim/Makefile | 9 +++++---- runtime/simx/Makefile | 9 +++++---- runtime/stub/Makefile | 7 ++++++- sim/opaesim/Makefile | 28 +++++++++++++++------------- sim/rtlsim/Makefile | 30 ++++++++++++++++-------------- sim/simx/Makefile | 9 +++++---- 7 files changed, 59 insertions(+), 48 deletions(-) diff --git a/runtime/opae/Makefile b/runtime/opae/Makefile index 153e33b3..168d5a11 100644 --- a/runtime/opae/Makefile +++ b/runtime/opae/Makefile @@ -1,13 +1,12 @@ XLEN ?= 32 TARGET ?= opaesim DESTDIR ?= $(CURDIR) -OPAESIM_DIR = ../../sim/opaesim -RTL_DIR=../../hw/rtl -SYN_DIR=../../hw/syn/altera/opae -SCRIPT_DIR=../../hw/scripts +SIM_DIR = $(abspath ../../sim) +HW_DIR = $(abspath ../../hw) +SYN_DIR = $(HW_DIR)/syn/altera/opae CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic -Wfatal-errors -CXXFLAGS += -I$(DESTDIR) -I../include -I../common/ -I../../hw +CXXFLAGS += -I../include -I../common -I$(HW_DIR) -I$(DESTDIR) CXXFLAGS += -DXLEN_$(XLEN) # Position independent code @@ -26,7 +25,7 @@ SRCS = vortex.cpp driver.cpp ../common/utils.cpp # set up target types ifeq ($(TARGET), opaesim) OPAESIM = $(DESTDIR)/libopae-c-sim.so - CXXFLAGS += -DOPAESIM -I$(OPAESIM_DIR) + CXXFLAGS += -DOPAESIM -I$(SIM_DIR)/opaesim LDFLAGS += -L$(DESTDIR) -lopae-c-sim else CXXFLAGS += -I$(SYN_DIR) @@ -60,11 +59,11 @@ PROJECT = libvortex.so all: $(DESTDIR)/$(PROJECT) $(DESTDIR)/libopae-c-sim.so: - DESTDIR=$(DESTDIR) $(MAKE) -C $(OPAESIM_DIR) $(DESTDIR)/libopae-c-sim.so + DESTDIR=$(DESTDIR) $(MAKE) -C $(SIM_DIR)/opaesim $(DESTDIR)/libopae-c-sim.so $(DESTDIR)/$(PROJECT): $(SRCS) $(OPAESIM) $(CXX) $(CXXFLAGS) $(SRCS) $(LDFLAGS) -o $@ clean: - DESTDIR=$(DESTDIR) $(MAKE) -C $(OPAESIM_DIR) clean + DESTDIR=$(DESTDIR) $(MAKE) -C $(SIM_DIR)/opaesim clean rm -rf $(DESTDIR)/$(PROJECT) diff --git a/runtime/rtlsim/Makefile b/runtime/rtlsim/Makefile index 4b400f84..5f85bdc3 100644 --- a/runtime/rtlsim/Makefile +++ b/runtime/rtlsim/Makefile @@ -1,9 +1,10 @@ XLEN ?= 32 DESTDIR ?= $(CURDIR) -RTLSIM_DIR = ../../sim/rtlsim +SIM_DIR = $(abspath ../../sim) +HW_DIR = $(abspath ../../hw) CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic -Wfatal-errors -CXXFLAGS += -I../include -I../common -I../../hw -I$(RTLSIM_DIR) -I$(RTLSIM_DIR)/../common +CXXFLAGS += -I../include -I../common -I$(HW_DIR) -I$(SIM_DIR)/rtlsim -I$(SIM_DIR)/common CXXFLAGS += -DXLEN_$(XLEN) # Position independent code @@ -37,9 +38,9 @@ PROJECT = libvortex.so all: $(DESTDIR)/$(PROJECT) $(DESTDIR)/$(PROJECT): $(SRCS) - DESTDIR=$(DESTDIR) $(MAKE) -C $(RTLSIM_DIR) $(DESTDIR)/librtlsim.so + DESTDIR=$(DESTDIR) $(MAKE) -C $(SIM_DIR)/rtlsim $(DESTDIR)/librtlsim.so $(CXX) $(CXXFLAGS) $(SRCS) $(LDFLAGS) -o $@ clean: - DESTDIR=$(DESTDIR) $(MAKE) -C $(RTLSIM_DIR) clean + DESTDIR=$(DESTDIR) $(MAKE) -C $(SIM_DIR)/rtlsim clean rm -rf $(DESTDIR)/$(PROJECT) *.o \ No newline at end of file diff --git a/runtime/simx/Makefile b/runtime/simx/Makefile index 9397ec24..7cfd6c38 100644 --- a/runtime/simx/Makefile +++ b/runtime/simx/Makefile @@ -1,10 +1,11 @@ XLEN ?= 32 DESTDIR ?= $(CURDIR) -SIMX_DIR = ../../sim/simx +SIM_DIR = $(abspath ../../sim) +HW_DIR = $(abspath ../../hw) CXXFLAGS += -std=c++11 -Wall -Wextra -Wfatal-errors CXXFLAGS += -fPIC -Wno-maybe-uninitialized -CXXFLAGS += -I../include -I../common -I../../hw -I$(SIMX_DIR) -I$(SIMX_DIR)/../common +CXXFLAGS += -I../include -I../common -I$(HW_DIR) -I$(SIM_DIR)/simx -I$(SIM_DIR)/common CXXFLAGS += $(CONFIGS) CXXFLAGS += -DDUMP_PERF_STATS CXXFLAGS += -DXLEN_$(XLEN) @@ -26,9 +27,9 @@ PROJECT = libvortex.so all: $(DESTDIR)/$(PROJECT) $(DESTDIR)/$(PROJECT): $(SRCS) - DESTDIR=$(DESTDIR) $(MAKE) -C $(SIMX_DIR) $(DESTDIR)/libsimx.so + DESTDIR=$(DESTDIR) $(MAKE) -C $(SIM_DIR)/simx $(DESTDIR)/libsimx.so $(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@ clean: - DESTDIR=$(DESTDIR) $(MAKE) -C $(SIMX_DIR) clean + DESTDIR=$(DESTDIR) $(MAKE) -C $(SIM_DIR)/simx clean rm -rf $(DESTDIR)/$(PROJECT) *.o \ No newline at end of file diff --git a/runtime/stub/Makefile b/runtime/stub/Makefile index 28441a3d..9c1c40bd 100644 --- a/runtime/stub/Makefile +++ b/runtime/stub/Makefile @@ -1,6 +1,11 @@ +XLEN ?= 32 +DESTDIR ?= $(CURDIR) +SIM_DIR = $(abspath ../../sim) +HW_DIR = $(abspath ../../hw) + CXXFLAGS += -std=c++11 -O2 -Wall -Wextra -pedantic -Wfatal-errors -CXXFLAGS += -I../include -I../../runtime -I../../hw -I../../sim/common +CXXFLAGS += -I../include -I../common -I$(HW_DIR) -I$(SIM_DIR)/common CXXFLAGS += -fPIC diff --git a/sim/opaesim/Makefile b/sim/opaesim/Makefile index 93f2da33..97c8aaf7 100644 --- a/sim/opaesim/Makefile +++ b/sim/opaesim/Makefile @@ -1,20 +1,22 @@ XLEN ?= 32 DESTDIR ?= $(CURDIR) -RTL_DIR = ../../hw/rtl -DPI_DIR = ../../hw/dpi +HW_DIR = $(abspath ../../hw) +COMMON_DIR = $(abspath ../common) +THIRD_PARTY_DIR = $(abspath ../../third_party) +RTL_DIR = $(HW_DIR)/rtl +DPI_DIR = $(HW_DIR)/dpi AFU_DIR = $(RTL_DIR)/afu/opae -SCRIPT_DIR = ../../hw/scripts -THIRD_PARTY_DIR = ../../third_party +SCRIPT_DIR = $(HW_DIR)/scripts CXXFLAGS += -std=c++11 -Wall -Wextra -Wfatal-errors -Wno-array-bounds CXXFLAGS += -fPIC -Wno-maybe-uninitialized -CXXFLAGS += -I.. -I../../../hw -I../../common -I$(abspath $(DESTDIR)) -CXXFLAGS += -I../$(THIRD_PARTY_DIR)/softfloat/source/include -CXXFLAGS += -I../$(THIRD_PARTY_DIR) +CXXFLAGS += -I$(CURDIR) -I$(HW_DIR) -I$(COMMON_DIR) -I$(DESTDIR) +CXXFLAGS += -I/$(THIRD_PARTY_DIR)/softfloat/source/include +CXXFLAGS += -I/$(THIRD_PARTY_DIR) CXXFLAGS += -DXLEN_$(XLEN) -LDFLAGS += -shared ../$(THIRD_PARTY_DIR)/softfloat/build/Linux-x86_64-GCC/softfloat.a -LDFLAGS += -L../$(THIRD_PARTY_DIR)/ramulator -lramulator -pthread +LDFLAGS += -shared $(THIRD_PARTY_DIR)/softfloat/build/Linux-x86_64-GCC/softfloat.a +LDFLAGS += -L$(THIRD_PARTY_DIR)/ramulator -lramulator -pthread # control RTL debug tracing states DBG_TRACE_FLAGS += -DDBG_TRACE_CORE_PIPELINE @@ -53,9 +55,9 @@ endif DBG_FLAGS += -DDEBUG_LEVEL=$(DEBUG) -DVCD_OUTPUT $(DBG_TRACE_FLAGS) -SRCS = ../common/util.cpp ../common/mem.cpp ../common/rvfloats.cpp +SRCS = $(COMMON_DIR)/util.cpp $(COMMON_DIR)/mem.cpp $(COMMON_DIR)/rvfloats.cpp SRCS += $(DPI_DIR)/util_dpi.cpp $(DPI_DIR)/float_dpi.cpp -SRCS += fpga.cpp opae_sim.cpp +SRCS += $(CURDIR)/fpga.cpp $(CURDIR)/opae_sim.cpp RTL_PKGS = $(AFU_DIR)/local_mem_cfg_pkg.sv $(AFU_DIR)/ccip/ccip_if_pkg.sv RTL_PKGS += $(RTL_DIR)/VX_gpu_pkg.sv $(RTL_DIR)/fpu/VX_fpu_pkg.sv @@ -128,7 +130,7 @@ $(DESTDIR)/vortex_afu.h : $(AFU_DIR)/vortex_afu.vh $(SCRIPT_DIR)/gen_config.py -i $^ -o $@ $(DESTDIR)/$(PROJECT): $(SRCS) $(DESTDIR)/vortex_afu.h $(SCOPE_JSON) - verilator --build --exe -O3 $(VL_FLAGS) --cc $(TOP) --top-module $(TOP) $(SRCS) -CFLAGS '$(CXXFLAGS)' -LDFLAGS '$(LDFLAGS)' -o $@ + verilator --build --exe -O3 $(VL_FLAGS) --cc $(TOP) --top-module $(TOP) $(SRCS) -CFLAGS '$(CXXFLAGS)' -LDFLAGS '$(LDFLAGS)' --Mdir $(DESTDIR)/obj_dir -o $@ clean: - rm -rf obj_dir $(DESTDIR)/vortex.xml $(DESTDIR)/scope.json $(DESTDIR)/vortex_afu.h $(DESTDIR)/$(PROJECT) + rm -rf $(DESTDIR)/obj_dir $(DESTDIR)/vortex.xml $(DESTDIR)/scope.json $(DESTDIR)/vortex_afu.h $(DESTDIR)/$(PROJECT) diff --git a/sim/rtlsim/Makefile b/sim/rtlsim/Makefile index 228cdd8b..3734a03b 100644 --- a/sim/rtlsim/Makefile +++ b/sim/rtlsim/Makefile @@ -1,18 +1,20 @@ XLEN ?= 32 DESTDIR ?= $(CURDIR) -RTL_DIR = ../../hw/rtl -DPI_DIR = ../../hw/dpi -THIRD_PARTY_DIR = ../../third_party +HW_DIR = $(abspath ../../hw) +COMMON_DIR = $(abspath ../common) +THIRD_PARTY_DIR = $(abspath ../../third_party) +RTL_DIR = $(HW_DIR)/rtl +DPI_DIR = $(HW_DIR)/dpi CXXFLAGS += -std=c++11 -Wall -Wextra -Wfatal-errors -Wno-array-bounds CXXFLAGS += -fPIC -Wno-maybe-uninitialized -CXXFLAGS += -I../../../hw -I../../common -CXXFLAGS += -I../$(THIRD_PARTY_DIR)/softfloat/source/include -CXXFLAGS += -I../$(THIRD_PARTY_DIR) +CXXFLAGS += -I$(HW_DIR) -I$(COMMON_DIR) +CXXFLAGS += -I$(THIRD_PARTY_DIR)/softfloat/source/include +CXXFLAGS += -I$(THIRD_PARTY_DIR) CXXFLAGS += -DXLEN_$(XLEN) -LDFLAGS += ../$(THIRD_PARTY_DIR)/softfloat/build/Linux-x86_64-GCC/softfloat.a -LDFLAGS += -L../$(THIRD_PARTY_DIR)/ramulator -lramulator +LDFLAGS += $(THIRD_PARTY_DIR)/softfloat/build/Linux-x86_64-GCC/softfloat.a +LDFLAGS += -L$(THIRD_PARTY_DIR)/ramulator -lramulator # control RTL debug tracing states DBG_TRACE_FLAGS += -DDBG_TRACE_CORE_PIPELINE @@ -38,9 +40,9 @@ ifneq (,$(findstring FPU_FPNEW,$(CONFIGS))) endif RTL_INCLUDE = -I$(RTL_DIR) -I$(DPI_DIR) -I$(RTL_DIR)/libs -I$(RTL_DIR)/interfaces -I$(RTL_DIR)/core -I$(RTL_DIR)/mem -I$(RTL_DIR)/cache $(FPU_INCLUDE) -SRCS = ../common/util.cpp ../common/mem.cpp ../common/rvfloats.cpp +SRCS = $(COMMON_DIR)/util.cpp $(COMMON_DIR)/mem.cpp $(COMMON_DIR)/rvfloats.cpp SRCS += $(DPI_DIR)/util_dpi.cpp $(DPI_DIR)/float_dpi.cpp -SRCS += processor.cpp +SRCS += $(CURDIR)/processor.cpp ifdef AXI_BUS TOP = Vortex_axi @@ -87,11 +89,11 @@ PROJECT = rtlsim all: $(DESTDIR)/$(PROJECT) -$(DESTDIR)/$(PROJECT): $(SRCS) main.cpp - verilator --build $(VL_FLAGS) $^ -CFLAGS '$(CXXFLAGS) -DSTARTUP_ADDR=0x80000000' -LDFLAGS '$(LDFLAGS)' -o $@ +$(DESTDIR)/$(PROJECT): $(SRCS) $(CURDIR)/main.cpp + verilator --build $(VL_FLAGS) $^ -CFLAGS '$(CXXFLAGS) -DSTARTUP_ADDR=0x80000000' -LDFLAGS '$(LDFLAGS)' --Mdir $(DESTDIR)/obj_dir -o $@ $(DESTDIR)/lib$(PROJECT).so: $(SRCS) - verilator --build $(VL_FLAGS) $^ -CFLAGS '$(CXXFLAGS)' -LDFLAGS '-shared $(LDFLAGS)' -o $@ + verilator --build $(VL_FLAGS) $^ -CFLAGS '$(CXXFLAGS)' -LDFLAGS '-shared $(LDFLAGS)' --Mdir $(DESTDIR)/obj_dir -o $@ clean: - rm -rf obj_dir $(DESTDIR)/$(PROJECT) $(DESTDIR)/lib$(PROJECT).so + rm -rf $(DESTDIR)/obj_dir $(DESTDIR)/$(PROJECT) $(DESTDIR)/lib$(PROJECT).so diff --git a/sim/simx/Makefile b/sim/simx/Makefile index 3cce8de0..36f0b63e 100644 --- a/sim/simx/Makefile +++ b/sim/simx/Makefile @@ -1,11 +1,12 @@ XLEN ?= 32 DESTDIR ?= $(CURDIR) -RTL_DIR = ../hw/rtl -THIRD_PARTY_DIR = ../../third_party +HW_DIR = $(abspath ../../hw) +COMMON_DIR = $(abspath ../common) +THIRD_PARTY_DIR = $(abspath ../../third_party) CXXFLAGS += -std=c++17 -Wall -Wextra -Wfatal-errors CXXFLAGS += -fPIC -Wno-maybe-uninitialized -CXXFLAGS += -I. -I../common -I../../hw +CXXFLAGS += -I$(CURDIR) -I$(COMMON_DIR) -I$(HW_DIR) CXXFLAGS += -I$(THIRD_PARTY_DIR)/softfloat/source/include CXXFLAGS += -I$(THIRD_PARTY_DIR) CXXFLAGS += -DXLEN_$(XLEN) @@ -14,7 +15,7 @@ CXXFLAGS += $(CONFIGS) LDFLAGS += $(THIRD_PARTY_DIR)/softfloat/build/Linux-x86_64-GCC/softfloat.a LDFLAGS += -L$(THIRD_PARTY_DIR)/ramulator -lramulator -SRCS = ../common/util.cpp ../common/mem.cpp ../common/rvfloats.cpp +SRCS = $(COMMON_DIR)/util.cpp $(COMMON_DIR)/mem.cpp $(COMMON_DIR)/rvfloats.cpp SRCS += processor.cpp cluster.cpp socket.cpp core.cpp warp.cpp decode.cpp execute.cpp exe_unit.cpp cache_sim.cpp mem_sim.cpp shared_mem.cpp dcrs.cpp # Debugigng From 031d24e6955ac478fb3aa49899741b7016e712a9 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sat, 30 Dec 2023 00:52:44 -0800 Subject: [PATCH 38/57] minor updates --- hw/rtl/VX_cluster.sv | 68 +- hw/rtl/VX_config.vh | 4 +- hw/rtl/VX_gpu_pkg.sv | 11 +- hw/rtl/VX_socket.sv | 47 +- hw/rtl/core/VX_fpu_unit.sv | 4 +- tests/opencl/Makefile | 26 +- tests/opencl/cutcp/Makefile | 9 - tests/opencl/cutcp/args.c | 617 -- tests/opencl/cutcp/atom.h | 37 - tests/opencl/cutcp/cutcpu.c | 195 - tests/opencl/cutcp/cutoff.c | 508 -- tests/opencl/cutcp/cutoff.h | 72 - tests/opencl/cutcp/excl.c | 157 - tests/opencl/cutcp/gpu_info.c | 55 - tests/opencl/cutcp/gpu_info.h | 28 - tests/opencl/cutcp/kernel.cl | 104 - tests/opencl/cutcp/macros.h | 69 - tests/opencl/cutcp/main.cc | 190 - tests/opencl/cutcp/ocl.c | 49 - tests/opencl/cutcp/ocl.h | 25 - tests/opencl/cutcp/output.c | 67 - tests/opencl/cutcp/output.h | 25 - tests/opencl/cutcp/parboil.h | 348 -- tests/opencl/cutcp/parboil_opencl.c | 1394 ----- tests/opencl/cutcp/readatom.c | 139 - tests/opencl/cutcp/watbox.sl40.pqr | 5945 ------------------- tests/opencl/fft/.depend | 7 + tests/opencl/{sgemm2 => fft}/Makefile | 2 +- tests/opencl/fft/common.h | 3 + tests/opencl/fft/fft4 | Bin 0 -> 19016 bytes tests/opencl/fft/fft_radix4.dump | 5495 +++++++++++++++++ tests/opencl/fft/kernel.cl | 63 + tests/opencl/fft/kernel.pocl | Bin 0 -> 74401 bytes tests/opencl/{sgemm2 => fft}/main.cc | 155 +- tests/opencl/fft/main.cc.o | Bin 0 -> 15368 bytes tests/opencl/mri-q/32_32_32_dataset.bin | Bin 454664 -> 0 bytes tests/opencl/mri-q/Makefile | 9 - tests/opencl/mri-q/args.c | 617 -- tests/opencl/mri-q/computeQ.c | 118 - tests/opencl/mri-q/computeQ.h | 22 - tests/opencl/mri-q/file.cc | 78 - tests/opencl/mri-q/file.h | 22 - tests/opencl/mri-q/gpu_info.c | 55 - tests/opencl/mri-q/gpu_info.h | 28 - tests/opencl/mri-q/kernel.cl | 51 - tests/opencl/mri-q/macros.h | 21 - tests/opencl/mri-q/main.cc | 321 - tests/opencl/mri-q/ocl copy.c | 50 - tests/opencl/mri-q/ocl copy.h | 21 - tests/opencl/mri-q/ocl.c | 50 - tests/opencl/mri-q/ocl.h | 31 - tests/opencl/mri-q/parboil.h | 348 -- tests/opencl/mri-q/parboil_opencl.c | 1394 ----- tests/opencl/sgemm2/kernel.cl | 73 - tests/opencl/vectorhypot/Makefile | 10 - tests/opencl/vectorhypot/cmd_arg_reader.cpp | 152 - tests/opencl/vectorhypot/cmd_arg_reader.h | 488 -- tests/opencl/vectorhypot/exception.h | 151 - tests/opencl/vectorhypot/kernel.cl | 41 - tests/opencl/vectorhypot/main.cc | 702 --- tests/opencl/vectorhypot/oclUtils.cpp | 806 --- tests/opencl/vectorhypot/oclUtils.h | 198 - tests/opencl/vectorhypot/shrQATest.h | 238 - tests/opencl/vectorhypot/shrUtils.cpp | 1954 ------ tests/opencl/vectorhypot/shrUtils.h | 642 -- 65 files changed, 5705 insertions(+), 18904 deletions(-) delete mode 100644 tests/opencl/cutcp/Makefile delete mode 100644 tests/opencl/cutcp/args.c delete mode 100644 tests/opencl/cutcp/atom.h delete mode 100644 tests/opencl/cutcp/cutcpu.c delete mode 100644 tests/opencl/cutcp/cutoff.c delete mode 100644 tests/opencl/cutcp/cutoff.h delete mode 100644 tests/opencl/cutcp/excl.c delete mode 100644 tests/opencl/cutcp/gpu_info.c delete mode 100644 tests/opencl/cutcp/gpu_info.h delete mode 100644 tests/opencl/cutcp/kernel.cl delete mode 100644 tests/opencl/cutcp/macros.h delete mode 100644 tests/opencl/cutcp/main.cc delete mode 100644 tests/opencl/cutcp/ocl.c delete mode 100644 tests/opencl/cutcp/ocl.h delete mode 100644 tests/opencl/cutcp/output.c delete mode 100644 tests/opencl/cutcp/output.h delete mode 100644 tests/opencl/cutcp/parboil.h delete mode 100644 tests/opencl/cutcp/parboil_opencl.c delete mode 100644 tests/opencl/cutcp/readatom.c delete mode 100755 tests/opencl/cutcp/watbox.sl40.pqr create mode 100644 tests/opencl/fft/.depend rename tests/opencl/{sgemm2 => fft}/Makefile (75%) create mode 100644 tests/opencl/fft/common.h create mode 100755 tests/opencl/fft/fft4 create mode 100644 tests/opencl/fft/fft_radix4.dump create mode 100644 tests/opencl/fft/kernel.cl create mode 100644 tests/opencl/fft/kernel.pocl rename tests/opencl/{sgemm2 => fft}/main.cc (61%) create mode 100644 tests/opencl/fft/main.cc.o delete mode 100755 tests/opencl/mri-q/32_32_32_dataset.bin delete mode 100644 tests/opencl/mri-q/Makefile delete mode 100644 tests/opencl/mri-q/args.c delete mode 100644 tests/opencl/mri-q/computeQ.c delete mode 100644 tests/opencl/mri-q/computeQ.h delete mode 100644 tests/opencl/mri-q/file.cc delete mode 100644 tests/opencl/mri-q/file.h delete mode 100644 tests/opencl/mri-q/gpu_info.c delete mode 100644 tests/opencl/mri-q/gpu_info.h delete mode 100644 tests/opencl/mri-q/kernel.cl delete mode 100644 tests/opencl/mri-q/macros.h delete mode 100644 tests/opencl/mri-q/main.cc delete mode 100644 tests/opencl/mri-q/ocl copy.c delete mode 100644 tests/opencl/mri-q/ocl copy.h delete mode 100644 tests/opencl/mri-q/ocl.c delete mode 100644 tests/opencl/mri-q/ocl.h delete mode 100644 tests/opencl/mri-q/parboil.h delete mode 100644 tests/opencl/mri-q/parboil_opencl.c delete mode 100644 tests/opencl/sgemm2/kernel.cl delete mode 100644 tests/opencl/vectorhypot/Makefile delete mode 100644 tests/opencl/vectorhypot/cmd_arg_reader.cpp delete mode 100644 tests/opencl/vectorhypot/cmd_arg_reader.h delete mode 100644 tests/opencl/vectorhypot/exception.h delete mode 100644 tests/opencl/vectorhypot/kernel.cl delete mode 100644 tests/opencl/vectorhypot/main.cc delete mode 100644 tests/opencl/vectorhypot/oclUtils.cpp delete mode 100644 tests/opencl/vectorhypot/oclUtils.h delete mode 100644 tests/opencl/vectorhypot/shrQATest.h delete mode 100644 tests/opencl/vectorhypot/shrUtils.cpp delete mode 100644 tests/opencl/vectorhypot/shrUtils.h diff --git a/hw/rtl/VX_cluster.sv b/hw/rtl/VX_cluster.sv index 2d220c24..02505171 100644 --- a/hw/rtl/VX_cluster.sv +++ b/hw/rtl/VX_cluster.sv @@ -82,64 +82,9 @@ module VX_cluster import VX_gpu_pkg::*; #( `endif VX_mem_bus_if #( - .DATA_SIZE (L2_WORD_SIZE), - .TAG_WIDTH (L2_TAG_WIDTH) - ) l2_mem_bus_if[L2_NUM_REQS](); - - VX_mem_bus_if #( - .DATA_SIZE (ICACHE_LINE_SIZE), - .TAG_WIDTH (ICACHE_MEM_TAG_WIDTH) - ) per_socket_icache_mem_bus_if[`NUM_SOCKETS](); - - VX_mem_bus_if #( - .DATA_SIZE (DCACHE_LINE_SIZE), - .TAG_WIDTH (DCACHE_MEM_TAG_WIDTH) - ) per_socket_dcache_mem_bus_if[`NUM_SOCKETS](); - - VX_mem_bus_if #( - .DATA_SIZE (ICACHE_LINE_SIZE), - .TAG_WIDTH (ICACHE_MEM_ARB_TAG_WIDTH) - ) icache_mem_bus_if[1](); - - VX_mem_bus_if #( - .DATA_SIZE (DCACHE_LINE_SIZE), - .TAG_WIDTH (DCACHE_MEM_ARB_TAG_WIDTH) - ) dcache_mem_bus_if[1](); - - `RESET_RELAY (l1_mem_arb_reset, reset); - - VX_mem_arb #( - .NUM_INPUTS (`NUM_SOCKETS), - .DATA_SIZE (ICACHE_LINE_SIZE), - .TAG_WIDTH (ICACHE_MEM_TAG_WIDTH), - .TAG_SEL_IDX (1), // Skip 0 for NC flag - .ARBITER ("R"), - .OUT_REG_REQ (2), - .OUT_REG_RSP (2) - ) icache_mem_arb ( - .clk (clk), - .reset (l1_mem_arb_reset), - .bus_in_if (per_socket_icache_mem_bus_if), - .bus_out_if (icache_mem_bus_if) - ); - - VX_mem_arb #( - .NUM_INPUTS (`NUM_SOCKETS), - .DATA_SIZE (DCACHE_LINE_SIZE), - .TAG_WIDTH (DCACHE_MEM_TAG_WIDTH), - .TAG_SEL_IDX (1), // Skip 0 for NC flag - .ARBITER ("R"), - .OUT_REG_REQ (2), - .OUT_REG_RSP (2) - ) dcache_mem_arb ( - .clk (clk), - .reset (l1_mem_arb_reset), - .bus_in_if (per_socket_dcache_mem_bus_if), - .bus_out_if (dcache_mem_bus_if) - ); - - `ASSIGN_VX_MEM_BUS_IF_X (l2_mem_bus_if[ICACHE_MEM_ARB_IDX], icache_mem_bus_if[0], L1_MEM_TAG_WIDTH, ICACHE_MEM_ARB_TAG_WIDTH); - `ASSIGN_VX_MEM_BUS_IF_X (l2_mem_bus_if[DCACHE_MEM_ARB_IDX], dcache_mem_bus_if[0], L1_MEM_TAG_WIDTH, DCACHE_MEM_ARB_TAG_WIDTH); + .DATA_SIZE (`L1_LINE_SIZE), + .TAG_WIDTH (L1_MEM_ARB_TAG_WIDTH) + ) per_socket_mem_bus_if[`NUM_SOCKETS](); `RESET_RELAY (l2_reset, reset); @@ -155,7 +100,7 @@ module VX_cluster import VX_gpu_pkg::*; #( .MSHR_SIZE (`L2_MSHR_SIZE), .MRSQ_SIZE (`L2_MRSQ_SIZE), .MREQ_SIZE (`L2_MREQ_SIZE), - .TAG_WIDTH (L1_MEM_TAG_WIDTH), + .TAG_WIDTH (L2_TAG_WIDTH), .WRITE_ENABLE (1), .UUID_WIDTH (`UUID_WIDTH), .CORE_OUT_REG (2), @@ -168,7 +113,7 @@ module VX_cluster import VX_gpu_pkg::*; #( `ifdef PERF_ENABLE .cache_perf (mem_perf_tmp_if.l2cache), `endif - .core_bus_if (l2_mem_bus_if), + .core_bus_if (per_socket_mem_bus_if), .mem_bus_if (mem_bus_if) ); @@ -209,8 +154,7 @@ module VX_cluster import VX_gpu_pkg::*; #( .dcr_bus_if (socket_dcr_bus_if), - .icache_mem_bus_if (per_socket_icache_mem_bus_if[i]), - .dcache_mem_bus_if (per_socket_dcache_mem_bus_if[i]), + .mem_bus_if (per_socket_mem_bus_if[i]), `ifdef GBAR_ENABLE .gbar_bus_if (per_socket_gbar_bus_if[i]), diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index d35d906b..80ac5fef 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -292,8 +292,8 @@ // Floating-Point Units /////////////////////////////////////////////////////// // Size of FPU Request Queue -`ifndef FPU_REQ_QUEUE_SIZE -`define FPU_REQ_QUEUE_SIZE (2 * (`NUM_THREADS / `NUM_FPU_LANES)) +`ifndef FPUQ_SIZE +`define FPUQ_SIZE (2 * (`NUM_THREADS / `NUM_FPU_LANES)) `endif // FNCP Latency diff --git a/hw/rtl/VX_gpu_pkg.sv b/hw/rtl/VX_gpu_pkg.sv index 94fe7684..49dc9564 100644 --- a/hw/rtl/VX_gpu_pkg.sv +++ b/hw/rtl/VX_gpu_pkg.sv @@ -141,10 +141,9 @@ package VX_gpu_pkg; /////////////////////////////// L1 Parameters ///////////////////////////// - localparam ICACHE_MEM_ARB_TAG_WIDTH = (ICACHE_MEM_TAG_WIDTH + `CLOG2(`NUM_SOCKETS)); - localparam DCACHE_MEM_ARB_TAG_WIDTH = (DCACHE_MEM_TAG_WIDTH + `CLOG2(`NUM_SOCKETS)); - localparam L1_MEM_TAG_WIDTH = `MAX(ICACHE_MEM_ARB_TAG_WIDTH, DCACHE_MEM_ARB_TAG_WIDTH); - + localparam L1_MEM_TAG_WIDTH = `MAX(ICACHE_MEM_TAG_WIDTH, DCACHE_MEM_TAG_WIDTH); + localparam L1_MEM_ARB_TAG_WIDTH = (L1_MEM_TAG_WIDTH + `CLOG2(2)); + /////////////////////////////// L2 Parameters ///////////////////////////// localparam ICACHE_MEM_ARB_IDX = 0; @@ -154,10 +153,10 @@ package VX_gpu_pkg; localparam L2_WORD_SIZE = `L1_LINE_SIZE; // Input request size - localparam L2_NUM_REQS = 2; + localparam L2_NUM_REQS = `NUM_SOCKETS; // Core request tag bits - localparam L2_TAG_WIDTH = L1_MEM_TAG_WIDTH; + localparam L2_TAG_WIDTH = L1_MEM_ARB_TAG_WIDTH; // Memory request data bits localparam L2_MEM_DATA_WIDTH = (`L2_LINE_SIZE * 8); diff --git a/hw/rtl/VX_socket.sv b/hw/rtl/VX_socket.sv index 31a01b50..563cf5ba 100644 --- a/hw/rtl/VX_socket.sv +++ b/hw/rtl/VX_socket.sv @@ -30,8 +30,7 @@ module VX_socket import VX_gpu_pkg::*; #( VX_dcr_bus_if.slave dcr_bus_if, // Memory - VX_mem_bus_if.master icache_mem_bus_if, - VX_mem_bus_if.master dcache_mem_bus_if, + VX_mem_bus_if.master mem_bus_if, `ifdef GBAR_ENABLE // Barrier @@ -79,6 +78,11 @@ module VX_socket import VX_gpu_pkg::*; #( .TAG_WIDTH (ICACHE_TAG_WIDTH) ) per_core_icache_bus_if[`SOCKET_SIZE](); + VX_mem_bus_if #( + .DATA_SIZE (ICACHE_LINE_SIZE), + .TAG_WIDTH (ICACHE_MEM_TAG_WIDTH) + ) icache_mem_bus_if(); + `RESET_RELAY (icache_reset, reset); VX_cache_cluster #( @@ -117,6 +121,11 @@ module VX_socket import VX_gpu_pkg::*; #( .DATA_SIZE (DCACHE_WORD_SIZE), .TAG_WIDTH (DCACHE_NOSM_TAG_WIDTH) ) per_core_dcache_bus_if[`SOCKET_SIZE * DCACHE_NUM_REQS](); + + VX_mem_bus_if #( + .DATA_SIZE (DCACHE_LINE_SIZE), + .TAG_WIDTH (DCACHE_MEM_TAG_WIDTH) + ) dcache_mem_bus_if(); `RESET_RELAY (dcache_reset, reset); @@ -151,6 +160,40 @@ module VX_socket import VX_gpu_pkg::*; #( .mem_bus_if (dcache_mem_bus_if) ); + /////////////////////////////////////////////////////////////////////////// + + VX_mem_bus_if #( + .DATA_SIZE (`L1_LINE_SIZE), + .TAG_WIDTH (L1_MEM_TAG_WIDTH) + ) l1_mem_bus_if[2](); + + VX_mem_bus_if #( + .DATA_SIZE (`L1_LINE_SIZE), + .TAG_WIDTH (L1_MEM_ARB_TAG_WIDTH) + ) l1_mem_arb_bus_if[1](); + + `ASSIGN_VX_MEM_BUS_IF_X (l1_mem_bus_if[0], icache_mem_bus_if, L1_MEM_TAG_WIDTH, ICACHE_MEM_TAG_WIDTH); + `ASSIGN_VX_MEM_BUS_IF_X (l1_mem_bus_if[1], dcache_mem_bus_if, L1_MEM_TAG_WIDTH, DCACHE_MEM_TAG_WIDTH); + + `RESET_RELAY (mem_arb_reset, reset); + + VX_mem_arb #( + .NUM_INPUTS (2), + .DATA_SIZE (`L1_LINE_SIZE), + .TAG_WIDTH (L1_MEM_TAG_WIDTH), + .TAG_SEL_IDX (1), // Skip 0 for NC flag + .ARBITER ("R"), + .OUT_REG_REQ (2), + .OUT_REG_RSP (2) + ) mem_arb ( + .clk (clk), + .reset (mem_arb_reset), + .bus_in_if (l1_mem_bus_if), + .bus_out_if (l1_mem_arb_bus_if) + ); + + `ASSIGN_VX_MEM_BUS_IF (mem_bus_if, l1_mem_arb_bus_if[0]); + /////////////////////////////////////////////////////////////////////////// wire [`SOCKET_SIZE-1:0] per_core_sim_ebreak; diff --git a/hw/rtl/core/VX_fpu_unit.sv b/hw/rtl/core/VX_fpu_unit.sv index 1aecd3e8..e00883b5 100644 --- a/hw/rtl/core/VX_fpu_unit.sv +++ b/hw/rtl/core/VX_fpu_unit.sv @@ -30,7 +30,7 @@ module VX_fpu_unit import VX_fpu_pkg::*; #( localparam NUM_LANES = `NUM_FPU_LANES; localparam PID_BITS = `CLOG2(`NUM_THREADS / NUM_LANES); localparam PID_WIDTH = `UP(PID_BITS); - localparam TAG_WIDTH = `LOG2UP(`FPU_REQ_QUEUE_SIZE); + localparam TAG_WIDTH = `LOG2UP(`FPUQ_SIZE); localparam PARTIAL_BW = (BLOCK_SIZE != `ISSUE_WIDTH) || (NUM_LANES != `NUM_THREADS); VX_execute_if #( @@ -87,7 +87,7 @@ module VX_fpu_unit import VX_fpu_pkg::*; #( VX_index_buffer #( .DATAW (`UUID_WIDTH + `NW_WIDTH + NUM_LANES + `XLEN + `NR_BITS + PID_WIDTH + 1 + 1), - .SIZE (`FPU_REQ_QUEUE_SIZE) + .SIZE (`FPUQ_SIZE) ) tag_store ( .clk (clk), .reset (reset), diff --git a/tests/opencl/Makefile b/tests/opencl/Makefile index 5d18f9cd..5635643e 100644 --- a/tests/opencl/Makefile +++ b/tests/opencl/Makefile @@ -15,10 +15,6 @@ all: $(MAKE) -C blackscholes $(MAKE) -C transpose $(MAKE) -C convolution -# $(MAKE) -C cutcp -# $(MAKE) -C sgemm2 -# $(MAKE) -C vectorhypot -# $(MAKE) -C mri-q run-simx run-simx: $(MAKE) -C vecadd run-simx @@ -37,10 +33,6 @@ run-simx: $(MAKE) -C blackscholes run-simx $(MAKE) -C transpose run-simx $(MAKE) -C convolution run-simx -# $(MAKE) -C cutcp run-simx -# $(MAKE) -C sgemm2 run-simx -# $(MAKE) -C vectorhypot run-simx -# $(MAKE) -C mri-q run-simx run-rtlsim: $(MAKE) -C vecadd run-rtlsim @@ -59,10 +51,6 @@ run-rtlsim: $(MAKE) -C oclprintf run-rtlsim $(MAKE) -C blackscholes run-rtlsim $(MAKE) -C convolution run-rtlsim -# $(MAKE) -C cutcp run-rtlsim -# $(MAKE) -C sgemm2 run-rtlsim -# $(MAKE) -C vectorhypot run-rtlsim -# $(MAKE) -C mri-q run-rtlsim run-opae: $(MAKE) -C vecadd run-opae @@ -81,10 +69,6 @@ run-opae: $(MAKE) -C oclprintf run-opae $(MAKE) -C blackscholes run-opae $(MAKE) -C convolution run-opae -# $(MAKE) -C cutcp run-opae -# $(MAKE) -C sgemm2 run-opae -# $(MAKE) -C vectorhypot run-opae -# $(MAKE) -C mri-q run-opae clean: $(MAKE) -C vecadd clean @@ -103,10 +87,6 @@ clean: $(MAKE) -C oclprintf clean $(MAKE) -C blackscholes clean $(MAKE) -C convolution clean -# $(MAKE) -C cutcp clean -# $(MAKE) -C sgemm2 clean -# $(MAKE) -C vectorhypot clean -# $(MAKE) -C mri-q clean clean-all: $(MAKE) -C vecadd clean-all @@ -124,8 +104,4 @@ clean-all: $(MAKE) -C lbm clean-all $(MAKE) -C oclprintf clean-all $(MAKE) -C blackscholes clean-all - $(MAKE) -C convolution clean-all -# $(MAKE) -C cutcp clean-all -# $(MAKE) -C sgemm2 clean-all -# $(MAKE) -C vectorhypot clean-all -# $(MAKE) -C mri-q clean-all + $(MAKE) -C convolution clean-all \ No newline at end of file diff --git a/tests/opencl/cutcp/Makefile b/tests/opencl/cutcp/Makefile deleted file mode 100644 index d16ddb11..00000000 --- a/tests/opencl/cutcp/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -PROJECT = cutcp - -SRCS = main.cc args.c parboil_opencl.c ocl.c gpu_info.c cutoff.c cutcpu.c output.c readatom.c excl.c - -CXXFLAGS += -I. - -OPTS ?= - -include ../common.mk diff --git a/tests/opencl/cutcp/args.c b/tests/opencl/cutcp/args.c deleted file mode 100644 index 9d751e29..00000000 --- a/tests/opencl/cutcp/args.c +++ /dev/null @@ -1,617 +0,0 @@ - -#include -#include -#include -#include -#include -#include - -/*****************************************************************************/ -/* Memory management routines */ - -/* Free an array of owned strings. */ -void -pb_FreeStringArray(char **string_array) -{ - char **p; - - if (!string_array) return; - for (p = string_array; *p; p++) free(*p); - free(string_array); -} - -struct pb_PlatformParam * -pb_PlatformParam(char *name, char *version) -{ - if (name == NULL) { - fprintf(stderr, "pb_PlatformParam: Invalid argument\n"); - exit(-1); - } - - struct pb_PlatformParam *ret = - (struct pb_PlatformParam *)malloc(sizeof (struct pb_PlatformParam)); - - ret->name = name; - ret->version = version; - return ret; -} - -void -pb_FreePlatformParam(struct pb_PlatformParam *p) -{ - if (p == NULL) return; - - free(p->name); - free(p->version); - free(p); -} - -struct pb_DeviceParam * -pb_DeviceParam_index(int index) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_INDEX; - ret->index = index; - return ret; -} - -struct pb_DeviceParam * -pb_DeviceParam_cpu(void) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_CPU; - return ret; -} - -struct pb_DeviceParam * -pb_DeviceParam_gpu(void) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_GPU; - return ret; -} - -struct pb_DeviceParam * -pb_DeviceParam_accelerator(void) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_ACCELERATOR; - return ret; -} - -struct pb_DeviceParam * -pb_DeviceParam_name(char *name) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_NAME; - ret->name = name; - return ret; -} - -void -pb_FreeDeviceParam(struct pb_DeviceParam *p) -{ - if (p == NULL) return; - - switch(p->criterion) { - case pb_Device_NAME: - free(p->name); - break; - case pb_Device_INDEX: - case pb_Device_CPU: - case pb_Device_ACCELERATOR: - break; - default: - fprintf(stderr, "pb_FreeDeviceParam: Invalid argument\n"); - exit(-1); - } -} - -void -pb_FreeParameters(struct pb_Parameters *p) -{ - free(p->outFile); - pb_FreeStringArray(p->inpFiles); - pb_FreePlatformParam(p->platform); - pb_FreeDeviceParam(p->device); - free(p); -} - -/*****************************************************************************/ - -/* Parse a comma-delimited list of strings into an - * array of strings. */ -static char ** -read_string_array(char *in) -{ - char **ret; - int i; - int count; /* Number of items in the input */ - char *substring; /* Current substring within 'in' */ - - /* Count the number of items in the string */ - count = 1; - for (i = 0; in[i]; i++) if (in[i] == ',') count++; - - /* Allocate storage */ - ret = (char **)malloc((count + 1) * sizeof(char *)); - - /* Create copies of the strings from the list */ - substring = in; - for (i = 0; i < count; i++) { - char *substring_end; - int substring_length; - - /* Find length of substring */ - for (substring_end = substring; - (*substring_end != ',') && (*substring_end != 0); - substring_end++); - - substring_length = substring_end - substring; - - /* Allocate memory and copy the substring */ - ret[i] = (char *)malloc(substring_length + 1); - memcpy(ret[i], substring, substring_length); - ret[i][substring_length] = 0; - - /* go to next substring */ - substring = substring_end + 1; - } - ret[i] = NULL; /* Write the sentinel value */ - - return ret; -} - -static void -report_parse_error(const char *str) -{ - fputs(str, stderr); -} - -/* Interpret a string as a 'pb_DeviceParam' value. - * Return a pointer to a new value, or NULL on failure. - */ -static struct pb_DeviceParam * -read_device_param(char *str) -{ - /* Try different ways of interpreting 'device_string' until one works */ - - /* If argument is an integer, then interpret it as a device index */ - errno = 0; - char *end; - long device_int = strtol(str, &end, 10); - if (!errno) { - /* Negative numbers are not valid */ - if (device_int < 0 || device_int > INT_MAX) return NULL; - - return pb_DeviceParam_index(device_int); - } - - /* Match against predefined strings */ - if (strcmp(str, "CPU") == 0) - return pb_DeviceParam_cpu(); - if (strcmp(str, "GPU") == 0) - return pb_DeviceParam_gpu(); - if (strcmp(str, "ACCELERATOR") == 0) - return pb_DeviceParam_accelerator(); - - /* Assume any other string is a device name */ - return pb_DeviceParam_name(strdup(str)); -} - -/* Interpret a string as a 'pb_PlatformParam' value. - * Return a pointer to a new value, or NULL on failure. - */ -static struct pb_PlatformParam * -read_platform_param(char *str) -{ - int separator_index; /* Index of the '-' character separating - * name and version number. It's -1 if - * there's no '-' character. */ - - /* Find the last occurrence of '-' in 'str' */ - { - char *cur; - separator_index = -1; - for (cur = str; *cur; cur++) { - if (*cur == '-') separator_index = cur - str; - } - } - - /* The platform name is either the entire string, or all characters before - * the separator */ - int name_length = separator_index == -1 ? strlen(str) : separator_index; - char *name_str = (char *)malloc(name_length + 1); - memcpy(name_str, str, name_length); - name_str[name_length] = 0; - - /* The version is either NULL, or all characters after the separator */ - char *version_str; - if (separator_index == -1) { - version_str = NULL; - } - else { - const char *version_input_str = str + separator_index + 1; - int version_length = strlen(version_input_str); - - version_str = (char *)malloc(version_length + 1); - memcpy(version_str, version_input_str, version_length); - version_str[version_length] = 0; - } - - /* Create output structure */ - return pb_PlatformParam(name_str, version_str); -} - -/****************************************************************************/ -/* Argument parsing state */ - -/* Argument parsing state. - * - * Arguments that are interpreted by the argument parser are removed from - * the list. Variables 'argc' and 'argn' do not count arguments that have - * been removed. - * - * During argument parsing, the array of arguments is compacted, overwriting - * the erased arguments. Variable 'argv_put' points to the array element - * where the next argument will be written. Variable 'argv_get' points to - * the array element where the next argument will be read from. - */ -struct argparse { - int argc; /* Number of arguments. Mutable. */ - int argn; /* Current argument index. */ - char **argv_get; /* Argument value being read. */ - char **argv_put; /* Argument value being written. - * argv_put <= argv_get. */ -}; - -static void -initialize_argparse(struct argparse *ap, int argc, char **argv) -{ - ap->argc = argc; - ap->argn = 0; - ap->argv_get = ap->argv_put = argv; -} - -/* Finish argument parsing, without processing the remaining arguments. - * Write new argument count into _argc. */ -static void -finalize_argparse(struct argparse *ap, int *_argc, char **argv) -{ - /* Move the remaining arguments */ - for(; ap->argn < ap->argc; ap->argn++) - *ap->argv_put++ = *ap->argv_get++; - - /* Update the argument count */ - *_argc = ap->argc; - - /* Insert a terminating NULL */ - argv[ap->argc] = NULL; -} - -/* Delete the current argument. The argument will not be visible - * when argument parsing is done. */ -static void -delete_argument(struct argparse *ap) -{ - if (ap->argn >= ap->argc) { - fprintf(stderr, "delete_argument\n"); - } - ap->argc--; - ap->argv_get++; -} - -/* Go to the next argument. Also, move the current argument to its - * final location in argv. */ -static void -next_argument(struct argparse *ap) -{ - if (ap->argn >= ap->argc) { - fprintf(stderr, "next_argument\n"); - } - /* Move argument to its new location. */ - *ap->argv_put++ = *ap->argv_get++; - ap->argn++; -} - -static int -is_end_of_arguments(struct argparse *ap) -{ - return ap->argn == ap->argc; -} - -/* Get the current argument */ -static char * -get_argument(struct argparse *ap) -{ - return *ap->argv_get; -} - -/* Get the current argument, and also delete it */ -static char * -consume_argument(struct argparse *ap) -{ - char *ret = get_argument(ap); - delete_argument(ap); - return ret; -} - -/****************************************************************************/ - -/* The result of parsing a command-line argument */ -typedef enum { - ARGPARSE_OK, /* Success */ - ARGPARSE_ERROR, /* Error */ - ARGPARSE_DONE /* Success, and do not continue parsing */ -} result; - -typedef result parse_action(struct argparse *ap, struct pb_Parameters *params); - - -/* A command-line option */ -struct option { - char short_name; /* If not 0, the one-character - * name of this option */ - const char *long_name; /* If not NULL, the long name of this option */ - parse_action *action; /* What to do when this option occurs. - * Sentinel value is NULL. - */ -}; - -/* Output file - * - * -o FILE - */ -static result -parse_output_file(struct argparse *ap, struct pb_Parameters *params) -{ - if (is_end_of_arguments(ap)) - { - report_parse_error("Expecting file name after '-o'\n"); - return ARGPARSE_ERROR; - } - - /* Replace the output file name */ - free(params->outFile); - params->outFile = strdup(consume_argument(ap)); - - return ARGPARSE_OK; -} - -/* Input files - * - * -i FILE,FILE,... - */ -static result -parse_input_files(struct argparse *ap, struct pb_Parameters *params) -{ - if (is_end_of_arguments(ap)) - { - report_parse_error("Expecting file name after '-i'\n"); - return ARGPARSE_ERROR; - } - - /* Replace the input file list */ - pb_FreeStringArray(params->inpFiles); - params->inpFiles = read_string_array(consume_argument(ap)); - return ARGPARSE_OK; -} - -/* End of options - * - * -- - */ - -static result -parse_end_options(struct argparse *ap, struct pb_Parameters *params) -{ - return ARGPARSE_DONE; -} - -/* OpenCL device - * - * --device X - */ - -static result -parse_device(struct argparse *ap, struct pb_Parameters *params) -{ - /* Read the next argument, which specifies a device */ - - if (is_end_of_arguments(ap)) - { - report_parse_error("Expecting device specification after '--device'\n"); - return ARGPARSE_ERROR; - } - - char *device_string = consume_argument(ap); - struct pb_DeviceParam *device_param = read_device_param(device_string); - - if (!device_param) { - report_parse_error("Unrecognized device specification format on command line\n"); - return ARGPARSE_ERROR; - } - - /* Save the result */ - pb_FreeDeviceParam(params->device); - params->device = device_param; - - return ARGPARSE_OK; -} - -static result -parse_platform(struct argparse *ap, struct pb_Parameters *params) -{ - /* Read the next argument, which specifies a platform */ - - if (is_end_of_arguments(ap)) - { - report_parse_error("Expecting device specification after '--platform'\n"); - return ARGPARSE_ERROR; - } - - char *platform_string = consume_argument(ap); - struct pb_PlatformParam *platform_param = read_platform_param(platform_string); - - if (!platform_param) { - report_parse_error("Unrecognized platform specification format on command line\n"); - return ARGPARSE_ERROR; - } - - /* Save the result */ - pb_FreePlatformParam(params->platform); - params->platform = platform_param; - - return ARGPARSE_OK; -} - - -static struct option options[] = { - { 'o', NULL, &parse_output_file }, - { 'i', NULL, &parse_input_files }, - { '-', NULL, &parse_end_options }, - { 0, "device", &parse_device }, - { 0, "platform", &parse_platform }, - { 0, NULL, NULL } -}; - -static int -is_last_option(struct option *op) -{ - return op->action == NULL; -} - -/****************************************************************************/ - -/* Parse command-line parameters. - * Return zero on error, nonzero otherwise. - * On error, the other outputs may be invalid. - * - * The information collected from parameters is used to update - * 'ret'. 'ret' should be initialized. - * - * '_argc' and 'argv' are updated to contain only the unprocessed arguments. - */ -static int -pb_ParseParameters (struct pb_Parameters *ret, int *_argc, char **argv) -{ - char *err_message; - struct argparse ap; - - /* Each argument */ - initialize_argparse(&ap, *_argc, argv); - while(!is_end_of_arguments(&ap)) { - result arg_result; /* Result of parsing this option */ - char *arg = get_argument(&ap); - - /* Process this argument */ - if (arg[0] == '-') { - /* Single-character flag */ - if ((arg[1] != 0) && (arg[2] == 0)) { - delete_argument(&ap); /* This argument is consumed here */ - - /* Find a matching short option */ - struct option *op; - for (op = options; !is_last_option(op); op++) { - if (op->short_name == arg[1]) { - arg_result = (*op->action)(&ap, ret); - goto option_was_processed; - } - } - - /* No option matches */ - report_parse_error("Unexpected command-line parameter\n"); - arg_result = ARGPARSE_ERROR; - goto option_was_processed; - } - - /* Long flag */ - if (arg[1] == '-') { - delete_argument(&ap); /* This argument is consumed here */ - - /* Find a matching long option */ - struct option *op; - for (op = options; !is_last_option(op); op++) { - if (op->long_name && strcmp(&arg[2], op->long_name) == 0) { - arg_result = (*op->action)(&ap, ret); - goto option_was_processed; - } - } - - /* No option matches */ - report_parse_error("Unexpected command-line parameter\n"); - arg_result = ARGPARSE_ERROR; - goto option_was_processed; - } - } - else { - /* Other arguments are ignored */ - next_argument(&ap); - arg_result = ARGPARSE_OK; - goto option_was_processed; - } - - option_was_processed: - /* Decide what to do next based on 'arg_result' */ - switch(arg_result) { - case ARGPARSE_OK: - /* Continue processing */ - break; - - case ARGPARSE_ERROR: - /* Error exit from the function */ - return 0; - - case ARGPARSE_DONE: - /* Normal exit from the argument parsing loop */ - goto end_of_options; - } - } /* end for each argument */ - - /* If all arguments were processed, then normal exit from the loop */ - - end_of_options: - finalize_argparse(&ap, _argc, argv); - return 1; -} - -/*****************************************************************************/ -/* Other exported functions */ - -struct pb_Parameters * -pb_ReadParameters(int *_argc, char **argv) -{ - struct pb_Parameters *ret = - (struct pb_Parameters *)malloc(sizeof(struct pb_Parameters)); - - /* Initialize the parameters structure */ - ret->outFile = NULL; - ret->inpFiles = (char **)malloc(sizeof(char *)); - ret->inpFiles[0] = NULL; - ret->platform = NULL; - ret->device = NULL; - - /* Read parameters and update _argc, argv */ - if (!pb_ParseParameters(ret, _argc, argv)) { - /* Parse error */ - pb_FreeParameters(ret); - return NULL; - } - - return ret; -} - -int -pb_Parameters_CountInputs(struct pb_Parameters *p) -{ - int n; - - for (n = 0; p->inpFiles[n]; n++); - return n; -} - diff --git a/tests/opencl/cutcp/atom.h b/tests/opencl/cutcp/atom.h deleted file mode 100644 index f5a60058..00000000 --- a/tests/opencl/cutcp/atom.h +++ /dev/null @@ -1,37 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2008-2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#ifndef ATOM_H -#define ATOM_H - -#ifdef __cplusplus -extern "C" { -#endif - - typedef struct Atom_t { - float x, y, z, q; - } Atom; - - typedef struct Atoms_t { - Atom *atoms; - int size; - } Atoms; - - typedef struct Vec3_t { - float x, y, z; - } Vec3; - - Atoms *read_atom_file(const char *fname); - void free_atom(Atoms *atom); - void get_atom_extent(Vec3 *lo, Vec3 *hi, Atoms *atom); - -#ifdef __cplusplus -} -#endif - -#endif /* ATOM_H */ diff --git a/tests/opencl/cutcp/cutcpu.c b/tests/opencl/cutcp/cutcpu.c deleted file mode 100644 index 5f440752..00000000 --- a/tests/opencl/cutcp/cutcpu.c +++ /dev/null @@ -1,195 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2008-2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#include -#include -#include -#include -#include -#include "atom.h" -#include "cutoff.h" - -#undef DEBUG_PASS_RATE -#define CHECK_CYLINDER_CPU - -#define CELLEN 4.f -#define INV_CELLEN (1.f/CELLEN) - -extern int cpu_compute_cutoff_potential_lattice( - Lattice *lattice, /* the lattice */ - float cutoff, /* cutoff distance */ - Atoms *atoms /* array of atoms */ - ) -{ - int nx = lattice->dim.nx; - int ny = lattice->dim.ny; - int nz = lattice->dim.nz; - float xlo = lattice->dim.lo.x; - float ylo = lattice->dim.lo.y; - float zlo = lattice->dim.lo.z; - float gridspacing = lattice->dim.h; - int natoms = atoms->size; - Atom *atom = atoms->atoms; - - const float a2 = cutoff * cutoff; - const float inv_a2 = 1.f / a2; - float s; - const float inv_gridspacing = 1.f / gridspacing; - const int radius = (int) ceilf(cutoff * inv_gridspacing) - 1; - /* lattice point radius about each atom */ - - int n; - int i, j, k; - int ia, ib, ic; - int ja, jb, jc; - int ka, kb, kc; - int index; - int koff, jkoff; - - float x, y, z, q; - float dx, dy, dz; - float dz2, dydz2, r2; - float e; - float xstart, ystart; - - float *pg; - - int gindex; - int ncell, nxcell, nycell, nzcell; - int *first, *next; - float inv_cellen = INV_CELLEN; - Vec3 minext, maxext; /* Extent of atom bounding box */ - float xmin, ymin, zmin; - float xmax, ymax, zmax; - -#if DEBUG_PASS_RATE - unsigned long long pass_count = 0; - unsigned long long fail_count = 0; -#endif - - /* find min and max extent */ - get_atom_extent(&minext, &maxext, atoms); - - /* number of cells in each dimension */ - nxcell = (int) floorf((maxext.x-minext.x) * inv_cellen) + 1; - nycell = (int) floorf((maxext.y-minext.y) * inv_cellen) + 1; - nzcell = (int) floorf((maxext.z-minext.z) * inv_cellen) + 1; - ncell = nxcell * nycell * nzcell; - - /* allocate for cursor link list implementation */ - first = (int *) malloc(ncell * sizeof(int)); - for (gindex = 0; gindex < ncell; gindex++) { - first[gindex] = -1; - } - next = (int *) malloc(natoms * sizeof(int)); - for (n = 0; n < natoms; n++) { - next[n] = -1; - } - - /* geometric hashing */ - for (n = 0; n < natoms; n++) { - if (0==atom[n].q) continue; /* skip any non-contributing atoms */ - i = (int) floorf((atom[n].x - minext.x) * inv_cellen); - j = (int) floorf((atom[n].y - minext.y) * inv_cellen); - k = (int) floorf((atom[n].z - minext.z) * inv_cellen); - gindex = (k*nycell + j)*nxcell + i; - next[n] = first[gindex]; - first[gindex] = n; - } - - /* traverse the grid cells */ - for (gindex = 0; gindex < ncell; gindex++) { - for (n = first[gindex]; n != -1; n = next[n]) { - x = atom[n].x - xlo; - y = atom[n].y - ylo; - z = atom[n].z - zlo; - q = atom[n].q; - - /* find closest grid point with position less than or equal to atom */ - ic = (int) (x * inv_gridspacing); - jc = (int) (y * inv_gridspacing); - kc = (int) (z * inv_gridspacing); - - /* find extent of surrounding box of grid points */ - ia = ic - radius; - ib = ic + radius + 1; - ja = jc - radius; - jb = jc + radius + 1; - ka = kc - radius; - kb = kc + radius + 1; - - /* trim box edges so that they are within grid point lattice */ - if (ia < 0) ia = 0; - if (ib >= nx) ib = nx-1; - if (ja < 0) ja = 0; - if (jb >= ny) jb = ny-1; - if (ka < 0) ka = 0; - if (kb >= nz) kb = nz-1; - - /* loop over surrounding grid points */ - xstart = ia*gridspacing - x; - ystart = ja*gridspacing - y; - dz = ka*gridspacing - z; - for (k = ka; k <= kb; k++, dz += gridspacing) { - koff = k*ny; - dz2 = dz*dz; - dy = ystart; - for (j = ja; j <= jb; j++, dy += gridspacing) { - jkoff = (koff + j)*nx; - dydz2 = dy*dy + dz2; -#ifdef CHECK_CYLINDER_CPU - if (dydz2 >= a2) continue; -#endif - - dx = xstart; - index = jkoff + ia; - pg = lattice->lattice + index; - -#if defined(__INTEL_COMPILER) - for (i = ia; i <= ib; i++, pg++, dx += gridspacing) { - r2 = dx*dx + dydz2; - s = (1.f - r2 * inv_a2) * (1.f - r2 * inv_a2); - e = q * (1/sqrtf(r2)) * s; - *pg += (r2 < a2 ? e : 0); /* LOOP VECTORIZED!! */ - } -#else - for (i = ia; i <= ib; i++, pg++, dx += gridspacing) { - r2 = dx*dx + dydz2; - if (r2 >= a2) - { -#ifdef DEBUG_PASS_RATE - fail_count++; -#endif - continue; - } -#ifdef DEBUG_PASS_RATE - pass_count++; -#endif - s = (1.f - r2 * inv_a2); - e = q * (1/sqrtf(r2)) * s * s; - *pg += e; - } -#endif - } - } /* end loop over surrounding grid points */ - - } /* end loop over atoms in a gridcell */ - } /* end loop over gridcells */ - - /* free memory */ - free(next); - free(first); - - /* For debugging: print the number of times that the test passed/failed */ -#ifdef DEBUG_PASS_RATE - printf ("Pass :%lld\n", pass_count); - printf ("Fail :%lld\n", fail_count); -#endif - - return 0; -} diff --git a/tests/opencl/cutcp/cutoff.c b/tests/opencl/cutcp/cutoff.c deleted file mode 100644 index 4a52d528..00000000 --- a/tests/opencl/cutcp/cutoff.c +++ /dev/null @@ -1,508 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2008-2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -#include "atom.h" -#include "cutoff.h" -#include "macros.h" -#include "ocl.h" - -static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { - if (NULL == filename || NULL == data || 0 == size) - return CL_INVALID_VALUE; - - FILE* fp = fopen(filename, "r"); - if (NULL == fp) { - fprintf(stderr, "Failed to load kernel."); - return CL_INVALID_VALUE; - } - fseek(fp , 0 , SEEK_END); - long fsize = ftell(fp); - rewind(fp); - - *data = (uint8_t*)malloc(fsize); - *size = fread(*data, 1, fsize, fp); - - fclose(fp); - - return CL_SUCCESS; -} - -// OpenCL 1.1 support for int3 is not uniform on all implementations, so -// we use int4 instead. Only the 'x', 'y', and 'z' fields of xyz are used. -typedef cl_int4 xyz; - -//extern "C" int gpu_compute_cutoff_potential_lattice( -int gpu_compute_cutoff_potential_lattice( - struct pb_TimerSet *timers, - Lattice *lattice, /* the lattice */ - float cutoff, /* cutoff distance */ - Atoms *atoms, /* array of atoms */ - int verbose, /* print info/debug messages */ - struct pb_Parameters *parameters - ) -{ - int nx = lattice->dim.nx; - int ny = lattice->dim.ny; - int nz = lattice->dim.nz; - float xlo = lattice->dim.lo.x; - float ylo = lattice->dim.lo.y; - float zlo = lattice->dim.lo.z; - float h = lattice->dim.h; - int natoms = atoms->size; - Atom *atom = atoms->atoms; - - xyz nbrlist[NBRLIST_MAXLEN]; - int nbrlistlen = 0; - - int binHistoFull[BIN_DEPTH+1] = { 0 }; /* clear every array element */ - int binHistoCover[BIN_DEPTH+1] = { 0 }; /* clear every array element */ - int num_excluded = 0; - - int xRegionDim, yRegionDim, zRegionDim; - int xRegionIndex, yRegionIndex, zRegionIndex; - int xOffset, yOffset, zOffset; - int lnx, lny, lnz, lnall; - float *regionZeroAddr, *thisRegion; - cl_mem regionZeroCl; - int index, indexRegion; - - int c; - xyz binDim; - int nbins; - cl_float4 *binBaseAddr, *binZeroAddr; - cl_mem binBaseCl, binZeroCl; - int *bincntBaseAddr, *bincntZeroAddr; - Atoms *extra = NULL; - - cl_mem NbrListLen; - cl_mem NbrList; - - int i, j, k, n; - int sum, total; - - float avgFillFull, avgFillCover; - const float cutoff2 = cutoff * cutoff; - const float inv_cutoff2 = 1.f / cutoff2; - - size_t gridDim[3], blockDim[3]; - - // The "compute" timer should be active upon entry to this function - - /* pad lattice to be factor of 8 in each dimension */ - xRegionDim = (int) ceilf(nx/8.f); - yRegionDim = (int) ceilf(ny/8.f); - zRegionDim = (int) ceilf(nz/8.f); - - lnx = 8 * xRegionDim; - lny = 8 * yRegionDim; - lnz = 8 * zRegionDim; - lnall = lnx * lny * lnz; - - /* will receive energies from OpenCL */ - regionZeroAddr = (float *) malloc(lnall * sizeof(float)); - - /* create bins */ - c = (int) ceil(cutoff * BIN_INVLEN); /* count extra bins around lattice */ - binDim.x = (int) ceil(lnx * h * BIN_INVLEN) + 2*c; - binDim.y = (int) ceil(lny * h * BIN_INVLEN) + 2*c; - binDim.z = (int) ceil(lnz * h * BIN_INVLEN) + 2*c; - nbins = binDim.x * binDim.y * binDim.z; - binBaseAddr = (cl_float4 *) calloc(nbins * BIN_DEPTH, sizeof(cl_float4)); - binZeroAddr = binBaseAddr + ((c * binDim.y + c) * binDim.x + c) * BIN_DEPTH; - - bincntBaseAddr = (int *) calloc(nbins, sizeof(int)); - bincntZeroAddr = bincntBaseAddr + (c * binDim.y + c) * binDim.x + c; - - /* create neighbor list */ - if (ceilf(BIN_LENGTH / (8*h)) == floorf(BIN_LENGTH / (8*h))) { - float s = sqrtf(3); - float r2 = (cutoff + s*BIN_LENGTH) * (cutoff + s*BIN_LENGTH); - int cnt = 0; - /* develop neighbor list around 1 cell */ - if (2*c + 1 > NBRLIST_DIM) { - fprintf(stderr, "must have cutoff <= %f\n", - (NBRLIST_DIM-1)/2 * BIN_LENGTH); - return -1; - } - for (k = -c; k <= c; k++) { - for (j = -c; j <= c; j++) { - for (i = -c; i <= c; i++) { - if ((i*i + j*j + k*k)*BIN_LENGTH*BIN_LENGTH >= r2) continue; - nbrlist[cnt].x = i; - nbrlist[cnt].y = j; - nbrlist[cnt].z = k; - cnt++; - } - } - } - nbrlistlen = cnt; - } - else if (8*h <= 2*BIN_LENGTH) { - float s = 2.f*sqrtf(3); - float r2 = (cutoff + s*BIN_LENGTH) * (cutoff + s*BIN_LENGTH); - int cnt = 0; - /* develop neighbor list around 3-cube of cells */ - if (2*c + 3 > NBRLIST_DIM) { - fprintf(stderr, "must have cutoff <= %f\n", - (NBRLIST_DIM-3)/2 * BIN_LENGTH); - return -1; - } - for (k = -c; k <= c; k++) { - for (j = -c; j <= c; j++) { - for (i = -c; i <= c; i++) { - if ((i*i + j*j + k*k)*BIN_LENGTH*BIN_LENGTH >= r2) continue; - nbrlist[cnt].x = i; - nbrlist[cnt].y = j; - nbrlist[cnt].z = k; - cnt++; - } - } - } - nbrlistlen = cnt; - } - else { - fprintf(stderr, "must have h <= %f\n", 0.25 * BIN_LENGTH); - return -1; - } - - /* perform geometric hashing of atoms into bins */ - { - /* array of extra atoms, permit average of one extra per bin */ - Atom *extra_atoms = (Atom *) calloc(nbins, sizeof(Atom)); - int extra_len = 0; - - for (n = 0; n < natoms; n++) { - cl_float4 p; - p.x = atom[n].x - xlo; - p.y = atom[n].y - ylo; - p.z = atom[n].z - zlo; - p.w = atom[n].q; - i = (int) floorf(p.x * BIN_INVLEN); - j = (int) floorf(p.y * BIN_INVLEN); - k = (int) floorf(p.z * BIN_INVLEN); - if (i >= -c && i < binDim.x - c && - j >= -c && j < binDim.y - c && - k >= -c && k < binDim.z - c && - atom[n].q != 0) { - int index = (k * binDim.y + j) * binDim.x + i; - cl_float4 *bin = binZeroAddr + index * BIN_DEPTH; - int bindex = bincntZeroAddr[index]; - if (bindex < BIN_DEPTH) { - /* copy atom into bin and increase counter for this bin */ - bin[bindex] = p; - bincntZeroAddr[index]++; - } - else { - /* add index to array of extra atoms to be computed with CPU */ - if (extra_len >= nbins) { - fprintf(stderr, "exceeded space for storing extra atoms\n"); - return -1; - } - extra_atoms[extra_len] = atom[n]; - extra_len++; - } - } - else { - /* excluded atoms are either outside bins or neutrally charged */ - num_excluded++; - } - } - - /* Save result */ - extra = (Atoms *)malloc(sizeof(Atoms)); - extra->atoms = extra_atoms; - extra->size = extra_len; - } - - /* bin stats */ - sum = total = 0; - for (n = 0; n < nbins; n++) { - binHistoFull[ bincntBaseAddr[n] ]++; - sum += bincntBaseAddr[n]; - total += BIN_DEPTH; - } - avgFillFull = sum / (float) total; - sum = total = 0; - for (k = 0; k < binDim.z - 2*c; k++) { - for (j = 0; j < binDim.y - 2*c; j++) { - for (i = 0; i < binDim.x - 2*c; i++) { - int index = (k * binDim.y + j) * binDim.x + i; - binHistoCover[ bincntZeroAddr[index] ]++; - sum += bincntZeroAddr[index]; - total += BIN_DEPTH; - } - } - } - avgFillCover = sum / (float) total; - - if (verbose) { - /* report */ - printf("number of atoms = %d\n", natoms); - printf("lattice spacing = %g\n", h); - printf("cutoff distance = %g\n", cutoff); - printf("\n"); - printf("requested lattice dimensions = %d %d %d\n", nx, ny, nz); - printf("requested space dimensions = %g %g %g\n", nx*h, ny*h, nz*h); - printf("expanded lattice dimensions = %d %d %d\n", lnx, lny, lnz); - printf("expanded space dimensions = %g %g %g\n", lnx*h, lny*h, lnz*h); - printf("number of bytes for lattice data = %u\n", (unsigned int) (lnall*sizeof(float))); - printf("\n"); - printf("bin padding thickness = %d\n", c); - printf("bin cover dimensions = %d %d %d\n", - binDim.x - 2*c, binDim.y - 2*c, binDim.z - 2*c); - printf("bin full dimensions = %d %d %d\n", binDim.x, binDim.y, binDim.z); - printf("number of bins = %d\n", nbins); - printf("total number of atom slots = %d\n", nbins * BIN_DEPTH); - printf("%% overhead space = %g\n", - (natoms / (double) (nbins * BIN_DEPTH)) * 100); - printf("number of bytes for bin data = %u\n", - (unsigned int)(nbins * BIN_DEPTH * sizeof(cl_float4))); - printf("\n"); - printf("bin histogram with padding:\n"); - sum = 0; - for (n = 0; n <= BIN_DEPTH; n++) { - printf(" number of bins with %d atoms: %d\n", n, binHistoFull[n]); - sum += binHistoFull[n]; - } - printf(" total number of bins: %d\n", sum); - printf(" %% average fill: %g\n", avgFillFull * 100); - printf("\n"); - printf("bin histogram excluding padding:\n"); - sum = 0; - for (n = 0; n <= BIN_DEPTH; n++) { - printf(" number of bins with %d atoms: %d\n", n, binHistoCover[n]); - sum += binHistoCover[n]; - } - printf(" total number of bins: %d\n", sum); - printf(" %% average fill: %g\n", avgFillCover * 100); - printf("\n"); - printf("number of extra atoms = %d\n", extra->size); - printf("%% atoms that are extra = %g\n", (extra->size / (double) natoms) * 100); - printf("\n"); - - /* sanity check on bins */ - sum = 0; - for (n = 0; n <= BIN_DEPTH; n++) { - sum += n * binHistoFull[n]; - } - sum += extra->size + num_excluded; - printf("sanity check on bin histogram with edges: " - "sum + others = %d\n", sum); - sum = 0; - for (n = 0; n <= BIN_DEPTH; n++) { - sum += n * binHistoCover[n]; - } - sum += extra->size + num_excluded; - printf("sanity check on bin histogram excluding edges: " - "sum + others = %d\n", sum); - printf("\n"); - - /* neighbor list */ - printf("neighbor list length = %d\n", nbrlistlen); - printf("\n"); - } - - pb_Context* pb_context; - pb_context = pb_InitOpenCLContext(parameters); - if (pb_context == NULL) { - fprintf (stderr, "Error: No OpenCL platform/device can be found."); - return -1; - } - - cl_int clStatus; - cl_device_id clDevice = (cl_device_id) pb_context->clDeviceId; - cl_platform_id clPlatform = (cl_platform_id) pb_context->clPlatformId; - cl_context clContext = (cl_context) pb_context->clContext; - - cl_command_queue clCommandQueue = clCreateCommandQueue(clContext,clDevice,CL_QUEUE_PROFILING_ENABLE,&clStatus); - CHECK_ERROR("clCreateCommandQueue") - - pb_SetOpenCL(&clContext, &clCommandQueue); - - //const char* clSource[] = {readFile("src/opencl_base/kernel.cl")}; - //cl_program clProgram = clCreateProgramWithSource(clContext,1,clSource,NULL,&clStatus); - uint8_t *kernel_bin = NULL; - size_t kernel_size; - cl_int binary_status = 0; - clStatus = read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size); - CHECK_ERROR("read_kernel_file") - cl_program clProgram = clCreateProgramWithBinary( - clContext, 1, &clDevice, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &clStatus); - CHECK_ERROR("clCreateProgramWithSource") - - char clOptions[50]; - sprintf(clOptions,"-I src/opencl_base"); //-cl-nv-verbose - - clStatus = clBuildProgram(clProgram,1,&clDevice,clOptions,NULL,NULL); - if (clStatus != CL_SUCCESS) { - size_t string_size = 0; - clGetProgramBuildInfo(clProgram, clDevice, CL_PROGRAM_BUILD_LOG, - 0, NULL, &string_size); - char* string = (char*)malloc(string_size*sizeof(char)); - clGetProgramBuildInfo(clProgram, clDevice, CL_PROGRAM_BUILD_LOG, - string_size, string, NULL); - puts(string); - } - - CHECK_ERROR("clBuildProgram") - - cl_kernel clKernel = clCreateKernel(clProgram,"opencl_cutoff_potential_lattice",&clStatus); - CHECK_ERROR("clCreateKernel") - - /* setup OpenCL kernel parameters */ - blockDim[0] = 8; - blockDim[1] = 8; - blockDim[2] = 2; - gridDim[0] = 4 * xRegionDim * blockDim[0]; - gridDim[1] = yRegionDim * blockDim[1]; - gridDim[2] = 1 * blockDim[2]; - - /* allocate and initialize memory on OpenCL device */ - pb_SwitchToTimer(timers, pb_TimerID_COPY); - if (verbose) { - printf("Allocating %.2fMB on OpenCL device for potentials\n", - lnall * sizeof(float) / (double) (1024*1024)); - } - - regionZeroCl = clCreateBuffer(clContext,CL_MEM_WRITE_ONLY,lnall*sizeof(float),NULL,&clStatus); - CHECK_ERROR("clCreateBuffer") - - // clMemSet(clCommandQueue,regionZeroCl,0,lnall*sizeof(float)); - - if (verbose) { - printf("Allocating %.2fMB on OpenCL device for atom bins\n", - nbins * BIN_DEPTH * sizeof(cl_float4) / (double) (1024*1024)); - } - - binBaseCl = clCreateBuffer(clContext,CL_MEM_READ_ONLY,nbins*BIN_DEPTH*sizeof(cl_float4),NULL,&clStatus); - CHECK_ERROR("clCreateBuffer") - - clStatus = clEnqueueWriteBuffer(clCommandQueue,binBaseCl,CL_TRUE,0,nbins*BIN_DEPTH*sizeof(cl_float4),binBaseAddr,0,NULL,NULL); - CHECK_ERROR("clEnqueueWriteBuffer") - - //Sub buffers are not supported in OpenCL v1.0 - int offset = ((c * binDim.y + c) * binDim.x + c) * BIN_DEPTH; - - NbrListLen = clCreateBuffer(clContext,CL_MEM_READ_ONLY,sizeof(int),NULL,&clStatus); - CHECK_ERROR("clCreateBuffer") - clStatus = clEnqueueWriteBuffer(clCommandQueue,NbrListLen,CL_TRUE,0,sizeof(int),&nbrlistlen,0,NULL,NULL); - CHECK_ERROR("clEnqueueWriteBuffer") - - NbrList = clCreateBuffer(clContext,CL_MEM_READ_ONLY,NBRLIST_MAXLEN*sizeof(xyz),NULL,&clStatus); - CHECK_ERROR("clCreateBuffer") - clStatus = clEnqueueWriteBuffer(clCommandQueue,NbrList,CL_TRUE,0,nbrlistlen*sizeof(xyz),nbrlist,0,NULL,NULL); - CHECK_ERROR("clEnqueueWriteBuffer") - - if (verbose) - printf("\n"); - - clStatus = clSetKernelArg(clKernel,0,sizeof(int),&(binDim.x)); - clStatus = clSetKernelArg(clKernel,1,sizeof(int),&(binDim.y)); - clStatus = clSetKernelArg(clKernel,2,sizeof(cl_mem),&binBaseCl); - clStatus = clSetKernelArg(clKernel,3,sizeof(int),&offset); - clStatus = clSetKernelArg(clKernel,4,sizeof(float),&h); - clStatus = clSetKernelArg(clKernel,5,sizeof(float),&cutoff2); - clStatus = clSetKernelArg(clKernel,6,sizeof(float),&inv_cutoff2); - clStatus = clSetKernelArg(clKernel,7,sizeof(cl_mem),®ionZeroCl); - clStatus = clSetKernelArg(clKernel,9,sizeof(cl_mem),&NbrListLen); - clStatus = clSetKernelArg(clKernel,10,sizeof(cl_mem),&NbrList); - CHECK_ERROR("clSetKernelArg") - - /* loop over z-dimension, invoke OpenCL kernel for each x-y plane */ - pb_SwitchToTimer(timers, pb_TimerID_KERNEL); - printf("Invoking OpenCL kernel on %d region planes...\n", zRegionDim); - for (zRegionIndex = 0; zRegionIndex < zRegionDim; zRegionIndex++) { - printf(" computing plane %d\r", zRegionIndex); - fflush(stdout); - - clStatus = clSetKernelArg(clKernel,8,sizeof(int),&zRegionIndex); - CHECK_ERROR("clSetKernelArg") - - clStatus = clEnqueueNDRangeKernel(clCommandQueue,clKernel,3,NULL,gridDim,blockDim,0,NULL,NULL); - - CHECK_ERROR("clEnqueueNDRangeKernel") - - clStatus = clFinish(clCommandQueue); - - CHECK_ERROR("clFinish") - } - - printf("Finished OpenCL kernel calls\n"); - - /* copy result regions from OpenCL device */ - pb_SwitchToTimer(timers, pb_TimerID_COPY); - clStatus = clEnqueueReadBuffer(clCommandQueue,regionZeroCl,CL_TRUE,0,lnall*sizeof(float),regionZeroAddr,0,NULL,NULL); - CHECK_ERROR("clEnqueueReadBuffer") - - /* free OpenCL memory allocations */ - clStatus = clReleaseMemObject(regionZeroCl); - clStatus = clReleaseMemObject(binBaseCl); - clStatus = clReleaseMemObject(NbrListLen); - clStatus = clReleaseMemObject(NbrList); - CHECK_ERROR("clReleaseMemObject") - - clStatus = clReleaseKernel(clKernel); - clStatus = clReleaseProgram(clProgram); - clStatus = clReleaseCommandQueue(clCommandQueue); - clStatus = clReleaseContext(clContext); - - //free((void*)clSource[0]); - - /* transpose regions back into lattice */ - pb_SwitchToTimer(timers, pb_TimerID_COMPUTE); - for (k = 0; k < nz; k++) { - zRegionIndex = (k >> 3); - zOffset = (k & 7); - - for (j = 0; j < ny; j++) { - yRegionIndex = (j >> 3); - yOffset = (j & 7); - - for (i = 0; i < nx; i++) { - xRegionIndex = (i >> 3); - xOffset = (i & 7); - - thisRegion = regionZeroAddr - + ((zRegionIndex * yRegionDim + yRegionIndex) * xRegionDim - + xRegionIndex) * REGION_SIZE; - - indexRegion = (zOffset * 8 + yOffset) * 8 + xOffset; - index = (k * ny + j) * nx + i; - - lattice->lattice[index] = thisRegion[indexRegion]; - } - } - } - - /* handle extra atoms */ - if (extra->size > 0) { - printf("computing extra atoms on CPU\n"); - if (cpu_compute_cutoff_potential_lattice(lattice, cutoff, extra)) { - fprintf(stderr, "cpu_compute_cutoff_potential_lattice() failed " - "for extra atoms\n"); - return -1; - } - printf("\n"); - } - - /* cleanup memory allocations */ - free(regionZeroAddr); - free(binBaseAddr); - free(bincntBaseAddr); - free_atom(extra); - - return 0; -} diff --git a/tests/opencl/cutcp/cutoff.h b/tests/opencl/cutcp/cutoff.h deleted file mode 100644 index 4db688ba..00000000 --- a/tests/opencl/cutcp/cutoff.h +++ /dev/null @@ -1,72 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2008-2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#ifndef CUTOFF_H -#define CUTOFF_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define SHIFTED - - /* A structure to record how points in 3D space map to array - elements. Array element (z, y, x) - where 0 <= x < nx, 0 <= y < ny, 0 <= z < nz - maps to coordinate (xlo, ylo, zlo) + h * (x, y, z). - */ - typedef struct LatticeDim_t { - /* Number of lattice points in x, y, z dimensions */ - int nx, ny, nz; - - /* Lowest corner of lattice */ - Vec3 lo; - - /* Lattice spacing */ - float h; - } LatticeDim; - - /* An electric potential field sampled on a regular grid. The - lattice size and grid point positions are specified by 'dim'. - */ - typedef struct Lattice_t { - LatticeDim dim; - float *lattice; - } Lattice; - - LatticeDim lattice_from_bounding_box(Vec3 lo, Vec3 hi, float h); - - Lattice *create_lattice(LatticeDim dim); - void destroy_lattice(Lattice *); - - int gpu_compute_cutoff_potential_lattice( - struct pb_TimerSet *timers, - Lattice *lattice, - float cutoff, /* cutoff distance */ - Atoms *atom, /* array of atoms */ - int verbose, /* print info/debug messages */ - struct pb_Parameters *parameters - ); - - int cpu_compute_cutoff_potential_lattice( - Lattice *lattice, /* the lattice */ - float cutoff, /* cutoff distance */ - Atoms *atoms /* array of atoms */ - ); - - int remove_exclusions( - Lattice *lattice, /* the lattice */ - float exclcutoff, /* exclusion cutoff distance */ - Atoms *atom /* array of atoms */ - ); - -#ifdef __cplusplus -} -#endif - -#endif /* CUTOFF_H */ diff --git a/tests/opencl/cutcp/excl.c b/tests/opencl/cutcp/excl.c deleted file mode 100644 index 1216854a..00000000 --- a/tests/opencl/cutcp/excl.c +++ /dev/null @@ -1,157 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2008-2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#include -#include -#include -#include -#include - -#include "atom.h" -#include "cutoff.h" - -#define CELLEN 4.f -#define INV_CELLEN (1.f/CELLEN) - -extern int remove_exclusions( - Lattice *lattice, /* the lattice */ - float cutoff, /* exclusion cutoff distance */ - Atoms *atoms /* array of atoms */ - ) -{ - int nx = lattice->dim.nx; - int ny = lattice->dim.ny; - int nz = lattice->dim.nz; - float xlo = lattice->dim.lo.x; - float ylo = lattice->dim.lo.y; - float zlo = lattice->dim.lo.z; - float gridspacing = lattice->dim.h; - Atom *atom = atoms->atoms; - - const float a2 = cutoff * cutoff; - const float inv_gridspacing = 1.f / gridspacing; - const int radius = (int) ceilf(cutoff * inv_gridspacing) - 1; - /* lattice point radius about each atom */ - - int n; - int i, j, k; - int ia, ib, ic; - int ja, jb, jc; - int ka, kb, kc; - int index; - int koff, jkoff; - - float x, y, z, q; - float dx, dy, dz; - float dz2, dydz2, r2; - float e; - float xstart, ystart; - - float *pg; - - int gindex; - int ncell, nxcell, nycell, nzcell; - int *first, *next; - float inv_cellen = INV_CELLEN; - Vec3 minext, maxext; - - /* find min and max extent */ - get_atom_extent(&minext, &maxext, atoms); - - /* number of cells in each dimension */ - nxcell = (int) floorf((maxext.x-minext.x) * inv_cellen) + 1; - nycell = (int) floorf((maxext.y-minext.y) * inv_cellen) + 1; - nzcell = (int) floorf((maxext.z-minext.z) * inv_cellen) + 1; - ncell = nxcell * nycell * nzcell; - - /* allocate for cursor link list implementation */ - first = (int *) malloc(ncell * sizeof(int)); - for (gindex = 0; gindex < ncell; gindex++) { - first[gindex] = -1; - } - next = (int *) malloc(atoms->size * sizeof(int)); - for (n = 0; n < atoms->size; n++) { - next[n] = -1; - } - - /* geometric hashing */ - for (n = 0; n < atoms->size; n++) { - if (0==atom[n].q) continue; /* skip any non-contributing atoms */ - i = (int) floorf((atom[n].x - minext.x) * inv_cellen); - j = (int) floorf((atom[n].y - minext.y) * inv_cellen); - k = (int) floorf((atom[n].z - minext.z) * inv_cellen); - gindex = (k*nycell + j)*nxcell + i; - next[n] = first[gindex]; - first[gindex] = n; - } - - /* traverse the grid cells */ - for (gindex = 0; gindex < ncell; gindex++) { - for (n = first[gindex]; n != -1; n = next[n]) { - x = atom[n].x - xlo; - y = atom[n].y - ylo; - z = atom[n].z - zlo; - q = atom[n].q; - - /* find closest grid point with position less than or equal to atom */ - ic = (int) (x * inv_gridspacing); - jc = (int) (y * inv_gridspacing); - kc = (int) (z * inv_gridspacing); - - /* find extent of surrounding box of grid points */ - ia = ic - radius; - ib = ic + radius + 1; - ja = jc - radius; - jb = jc + radius + 1; - ka = kc - radius; - kb = kc + radius + 1; - - /* trim box edges so that they are within grid point lattice */ - if (ia < 0) ia = 0; - if (ib >= nx) ib = nx-1; - if (ja < 0) ja = 0; - if (jb >= ny) jb = ny-1; - if (ka < 0) ka = 0; - if (kb >= nz) kb = nz-1; - - /* loop over surrounding grid points */ - xstart = ia*gridspacing - x; - ystart = ja*gridspacing - y; - dz = ka*gridspacing - z; - for (k = ka; k <= kb; k++, dz += gridspacing) { - koff = k*ny; - dz2 = dz*dz; - - dy = ystart; - for (j = ja; j <= jb; j++, dy += gridspacing) { - jkoff = (koff + j)*nx; - dydz2 = dy*dy + dz2; - - dx = xstart; - index = jkoff + ia; - pg = lattice->lattice + index; - - for (i = ia; i <= ib; i++, pg++, dx += gridspacing) { - r2 = dx*dx + dydz2; - - /* If atom and lattice point are too close, set the lattice value - * to zero */ - if (r2 < a2) *pg = 0; - } - } - } /* end loop over surrounding grid points */ - - } /* end loop over atoms in a gridcell */ - } /* end loop over gridcells */ - - /* free memory */ - free(next); - free(first); - - return 0; -} diff --git a/tests/opencl/cutcp/gpu_info.c b/tests/opencl/cutcp/gpu_info.c deleted file mode 100644 index 4d641f81..00000000 --- a/tests/opencl/cutcp/gpu_info.c +++ /dev/null @@ -1,55 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ -//#include -#include -#include -#include -#include - -#include "gpu_info.h" - -void compute_active_thread(size_t *thread, - size_t *grid, - int task, - int pad, - int major, - int minor, - int sm) -{ - int max_thread; - int max_block=8; - if(major==1) - { - if(minor>=2) - max_thread=1024; - else - max_thread=768; - } - else if(major==2) - max_thread=1536; - else - //newer GPU //keep using 2.0 - max_thread=1536; - - int _grid; - int _thread; - - if(task*pad>sm*max_thread) - { - _thread=max_thread/max_block; - _grid = ((task*pad+_thread-1)/_thread)*_thread; - } - else - { - _thread=pad; - _grid=task*pad; - } - - thread[0]=_thread; - grid[0]=_grid; -} diff --git a/tests/opencl/cutcp/gpu_info.h b/tests/opencl/cutcp/gpu_info.h deleted file mode 100644 index 5d433968..00000000 --- a/tests/opencl/cutcp/gpu_info.h +++ /dev/null @@ -1,28 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#ifndef __GPUINFOH__ -#define __GPUINFOH__ - -#ifdef __cplusplus -extern "C" { -#endif - -void compute_active_thread(size_t *thread, - size_t *grid, - int task, - int pad, - int major, - int minor, - int sm); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tests/opencl/cutcp/kernel.cl b/tests/opencl/cutcp/kernel.cl deleted file mode 100644 index 7bbd24b8..00000000 --- a/tests/opencl/cutcp/kernel.cl +++ /dev/null @@ -1,104 +0,0 @@ -/* - * potential lattice is decomposed into size 8^3 lattice point "regions" - * - * THIS IMPLEMENTATION: one thread per lattice point - * thread block size 128 gives 4 thread blocks per region - * kernel is invoked for each x-y plane of regions, - * where gridDim.x is 4*(x region dimension) so that blockIdx.x - * can absorb the z sub-region index in its 2 lowest order bits - * - * Regions are stored contiguously in memory in row-major order - * - * The bins have to not only cover the region, but they need to surround - * the outer edges so that region sides and corners can still use - * neighbor list stencil. The binZeroAddr is actually a shifted pointer into - * the bin array (binZeroAddr = binBaseAddr + (c*binDim_y + c)*binDim_x + c) - * where c = ceil(cutoff / binsize). This allows for negative offsets to - * be added to myBinIndex. - * - * The (0,0,0) spatial origin corresponds to lower left corner of both - * regionZeroAddr and binZeroAddr. The atom coordinates are translated - * during binning to enforce this assumption. - */ - -#include "macros.h" - -// OpenCL 1.1 support for int3 is not uniform on all implementations, so -// we use int4 instead. Only the 'x', 'y', and 'z' fields of xyz are used. -typedef int4 xyz; - -__kernel void opencl_cutoff_potential_lattice( - int binDim_x, - int binDim_y, - __global float4 *binBaseAddr, - int offset, - float h, /* lattice spacing */ - float cutoff2, /* square of cutoff distance */ - float inv_cutoff2, - __global float *regionZeroAddr, /* address of lattice regions starting at origin */ - int zRegionIndex, - __constant int *NbrListLen, - __constant xyz *NbrList - ) -{ - __global float4* binZeroAddr = binBaseAddr + offset; - - __global float *myRegionAddr; - int Bx, By, Bz; - - /* thread id */ - const int tid = (get_local_id(2)*get_local_size(1) + - get_local_id(1))*get_local_size(0) + get_local_id(0); - - /* this is the start of the sub-region indexed by tid */ - myRegionAddr = regionZeroAddr + ((zRegionIndex*get_num_groups(1) - + get_group_id(1))*(get_num_groups(0)>>2) + (get_group_id(0)>>2))*REGION_SIZE - + (get_group_id(0)&3)*SUB_REGION_SIZE; - - /* spatial coordinate of this lattice point */ - float x = (8 * (get_group_id(0) >> 2) + get_local_id(0)) * h; - float y = (8 * get_group_id(1) + get_local_id(1)) * h; - float z = (8 * zRegionIndex + 2*(get_group_id(0)&3) + get_local_id(2)) * h; - - float dx; - float dy; - float dz; - float r2; - float s; - - int totalbins = 0; - - /* bin number determined by center of region */ - Bx = (int) floor((8 * (get_group_id(0) >> 2) + 4) * h * BIN_INVLEN); - By = (int) floor((8 * get_group_id(1) + 4) * h * BIN_INVLEN); - Bz = (int) floor((8 * zRegionIndex + 4) * h * BIN_INVLEN); - - float energy = 0.f; - int bincnt; - for (bincnt = 0; bincnt < *NbrListLen; bincnt++) { - int i = Bx + NbrList[bincnt].x; - int j = By + NbrList[bincnt].y; - int k = Bz + NbrList[bincnt].z; - - __global float4* p_global = binZeroAddr + - (((k*binDim_y + j)*binDim_x + i) * BIN_DEPTH); - - int m; - for (m = 0; m < BIN_DEPTH; m++) { - float aq = p_global[m].w; - if (0.f != aq) { - dx = p_global[m].x - x; - dy = p_global[m].y - y; - dz = p_global[m].z - z; - r2 = dx*dx + dy*dy + dz*dz; - if (r2 < cutoff2) { - s = (1.f - r2 * inv_cutoff2); - energy += aq * rsqrt(r2) * s * s; - } - } - } /* end loop over atoms in bin */ - } /* end loop over neighbor list */ - - /* store into global memory */ - myRegionAddr[tid+0] = energy; -} diff --git a/tests/opencl/cutcp/macros.h b/tests/opencl/cutcp/macros.h deleted file mode 100644 index fed9553c..00000000 --- a/tests/opencl/cutcp/macros.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef __MACROSH__ -#define __MACROSH__ - -#ifdef __DEVICE_EMULATION__ -#define DEBUG -/* define which grid block and which thread to examine */ -#define BX 0 -#define BY 0 -#define TX 0 -#define TY 0 -#define TZ 0 -#define EMU(code) do { \ - if (blockIdx.x==BX && blockIdx.y==BY && \ - threadIdx.x==TX && threadIdx.y==TY && threadIdx.z==TZ) { \ - code; \ - } \ -} while (0) -#define INT(n) printf("%s = %d\n", #n, n) -#define FLOAT(f) printf("%s = %g\n", #f, (double)(f)) -#define INT3(n) printf("%s = %d %d %d\n", #n, (n).x, (n).y, (n).z) -#define FLOAT4(f) printf("%s = %g %g %g %g\n", #f, (double)(f).x, \ - (double)(f).y, (double)(f).z, (double)(f).w) -#else -#define EMU(code) -#define INT(n) -#define FLOAT(f) -#define INT3(n) -#define FLOAT4(f) -#endif - -/* report error from OpenCL */ -#define CHECK_ERROR(errorMessage) \ - if(clStatus != CL_SUCCESS) \ - { \ - printf("Error: %s!\n",errorMessage); \ - printf("Line: %d\n",__LINE__); \ - exit(1); \ - } - -/* - * neighbor list: - * stored in constant memory as table of offsets - * flat index addressing is computed by kernel - * - * reserve enough memory for 11^3 stencil of grid cells - * this fits within 16K of memory - */ -#define NBRLIST_DIM 11 -#define NBRLIST_MAXLEN (NBRLIST_DIM * NBRLIST_DIM * NBRLIST_DIM) - -/* - * atom bins cached into shared memory for processing - * - * this reserves 4K of shared memory for 32 atom bins each containing 8 atoms, - * should permit scheduling of up to 3 thread blocks per SM - */ -#define BIN_DEPTH 8 /* max number of atoms per bin */ -#define BIN_SIZE 32 /* size of bin in floats */ -#define BIN_CACHE_MAXLEN 32 /* max number of atom bins to cache */ - -#define BIN_LENGTH 4.f /* spatial length in Angstroms */ -#define BIN_INVLEN (1.f / BIN_LENGTH) -/* assuming density of 1 atom / 10 A^3, expectation is 6.4 atoms per bin - * so that bin fill should be 80% (for non-empty regions of space) */ - -#define REGION_SIZE 512 /* number of floats in lattice region */ -#define SUB_REGION_SIZE 128 /* number of floats in lattice sub-region */ - -#endif diff --git a/tests/opencl/cutcp/main.cc b/tests/opencl/cutcp/main.cc deleted file mode 100644 index 72ab37f3..00000000 --- a/tests/opencl/cutcp/main.cc +++ /dev/null @@ -1,190 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2008-2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#include -#include -#include -#include -#include - -#include "atom.h" -#include "cutoff.h" -#include "output.h" - -#define ERRTOL 1e-4f - -#define NOKERNELS 0 -#define CUTOFF1 1 -#define CUTOFF6 32 -#define CUTOFF6OVERLAP 64 -#define CUTOFFCPU 16384 - - -int appenddata(const char *filename, int size, double time) { - FILE *fp; - fp=fopen(filename, "a"); - if (fp == NULL) { - printf("error appending to file %s..\n", filename); - return -1; - } - fprintf(fp, "%d %.3f\n", size, time); - fclose(fp); - return 0; -} - -LatticeDim -lattice_from_bounding_box(Vec3 lo, Vec3 hi, float h) -{ - LatticeDim ret; - - ret.nx = (int) floorf((hi.x-lo.x)/h) + 1; - ret.ny = (int) floorf((hi.y-lo.y)/h) + 1; - ret.nz = (int) floorf((hi.z-lo.z)/h) + 1; - ret.lo = lo; - ret.h = h; - - return ret; -} - -Lattice * -create_lattice(LatticeDim dim) -{ - int size; - Lattice *lat = (Lattice *)malloc(sizeof(Lattice)); - - if (lat == NULL) { - fprintf(stderr, "Out of memory\n"); - exit(1); - } - - lat->dim = dim; - - /* Round up the allocated size to a multiple of 8 */ - size = ((dim.nx * dim.ny * dim.nz) + 7) & ~7; - lat->lattice = (float *)calloc(size, sizeof(float)); - - if (lat->lattice == NULL) { - fprintf(stderr, "Out of memory\n"); - exit(1); - } - - return lat; -} - - -void -destroy_lattice(Lattice *lat) -{ - if (lat) { - free(lat->lattice); - free(lat); - } -} - -int main(int argc, char *argv[]) { - Atoms *atom; - - LatticeDim lattice_dim; - Lattice *gpu_lattice; - Vec3 min_ext, max_ext; /* Bounding box of atoms */ - Vec3 lo, hi; /* Bounding box with padding */ - - float h = 0.5f; /* Lattice spacing */ - float cutoff = 12.f; /* Cutoff radius */ - float exclcutoff = 1.f; /* Radius for exclusion */ - float padding = 0.5f; /* Bounding box padding distance */ - - int n; - - struct pb_Parameters *parameters; - struct pb_TimerSet timers; - - /* Read input parameters */ - parameters = pb_ReadParameters(&argc, argv); - if (parameters == NULL) { - exit(1); - } - - parameters->inpFiles = (char **)malloc(sizeof(char *) * 2); - parameters->inpFiles[0] = (char *)malloc(100); - parameters->inpFiles[1] = NULL; - strncpy(parameters->inpFiles[0], "watbox.sl40.pqr", 100); - - /* Expect one input file */ - if (pb_Parameters_CountInputs(parameters) != 1) { - fprintf(stderr, "Expecting one input file\n"); - exit(1); - } - - pb_InitializeTimerSet(&timers); - pb_SwitchToTimer(&timers, pb_TimerID_IO); - - { - const char *pqrfilename = parameters->inpFiles[0]; - - if (!(atom = read_atom_file(pqrfilename))) { - fprintf(stderr, "read_atom_file() failed\n"); - exit(1); - } - printf("read %d atoms from file '%s'\n", atom->size, pqrfilename); - } - - /* find extent of domain */ - pb_SwitchToTimer(&timers, pb_TimerID_COMPUTE); - get_atom_extent(&min_ext, &max_ext, atom); - printf("extent of domain is:\n"); - printf(" minimum %g %g %g\n", min_ext.x, min_ext.y, min_ext.z); - printf(" maximum %g %g %g\n", max_ext.x, max_ext.y, max_ext.z); - - printf("padding domain by %g Angstroms\n", padding); - lo = (Vec3) {min_ext.x - padding, min_ext.y - padding, min_ext.z - padding}; - hi = (Vec3) {max_ext.x + padding, max_ext.y + padding, max_ext.z + padding}; - printf("domain lengths are %g by %g by %g\n", hi.x-lo.x, hi.y-lo.y, hi.z-lo.z); - - lattice_dim = lattice_from_bounding_box(lo, hi, h); - gpu_lattice = create_lattice(lattice_dim); - printf("\n"); - - /* - * Run OpenCL kernel - * (Begin and end with COMPUTE timer active) - */ - if (gpu_compute_cutoff_potential_lattice(&timers, gpu_lattice, cutoff, atom, 0, parameters)) { - fprintf(stderr, "Computation failed\n"); - exit(1); - } - - /* - * Zero the lattice points that are too close to an atom. This is - * necessary for numerical stability. - */ - if (remove_exclusions(gpu_lattice, exclcutoff, atom)) { - fprintf(stderr, "remove_exclusions() failed for gpu lattice\n"); - exit(1); - } - - printf("\n"); - - pb_SwitchToTimer(&timers, pb_TimerID_IO); - - /* Print output */ - if (parameters->outFile) { - //write_lattice_summary(parameters->outFile, gpu_lattice); - } - pb_SwitchToTimer(&timers, pb_TimerID_COMPUTE); - - /* Cleanup */ - destroy_lattice(gpu_lattice); - free_atom(atom); - - pb_SwitchToTimer(&timers, pb_TimerID_NONE); - pb_PrintTimerSet(&timers); - pb_FreeParameters(parameters); - - return 0; -} diff --git a/tests/opencl/cutcp/ocl.c b/tests/opencl/cutcp/ocl.c deleted file mode 100644 index 7e48e7e6..00000000 --- a/tests/opencl/cutcp/ocl.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include "ocl.h" - -char* readFile(const char* fileName) -{ - FILE* fp; - fp = fopen(fileName,"r"); - if(fp == NULL) - { - printf("Error 1!\n"); - exit(1); - } - - fseek(fp,0,SEEK_END); - long size = ftell(fp); - rewind(fp); - - char* buffer = (char*)malloc(sizeof(char)*(size+1)); - if(buffer == NULL) - { - printf("Error 2!\n"); - fclose(fp); - exit(1); - } - - size_t res = fread(buffer,1,size,fp); - if(res != size) - { - printf("Error 3!\n"); - fclose(fp); - exit(1); - } - - buffer[size] = 0; - fclose(fp); - return buffer; -} - -void clMemSet(cl_command_queue clCommandQueue, cl_mem buf, int val, size_t size) -{ - cl_int clStatus; - char* temp = (char*)malloc(size); - memset(temp,val,size); - clStatus = clEnqueueWriteBuffer(clCommandQueue,buf,CL_TRUE,0,size,temp,0,NULL,NULL); - CHECK_ERROR("clEnqueueWriteBuffer") - free(temp); -} diff --git a/tests/opencl/cutcp/ocl.h b/tests/opencl/cutcp/ocl.h deleted file mode 100644 index 6de9a5ec..00000000 --- a/tests/opencl/cutcp/ocl.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef __OCLH__ -#define __OCLH__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void clMemSet(cl_command_queue, cl_mem, int, size_t); -char* readFile(const char*); - -#define CHECK_ERROR(errorMessage) \ - if(clStatus != CL_SUCCESS) \ - { \ - printf("Error: %s!\n",errorMessage); \ - printf("Line: %d\n",__LINE__); \ - exit(1); \ - } - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tests/opencl/cutcp/output.c b/tests/opencl/cutcp/output.c deleted file mode 100644 index 36ee7e2b..00000000 --- a/tests/opencl/cutcp/output.c +++ /dev/null @@ -1,67 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2008-2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#include -#include -#include -#include -#include - -#include "atom.h" -#include "cutoff.h" - -void -write_lattice_summary(const char *filename, Lattice *lattice) -{ - float *lattice_data = lattice->lattice; - int nx = lattice->dim.nx; - int ny = lattice->dim.ny; - int nz = lattice->dim.nz; - - /* Open output file */ - FILE *outfile = fopen(filename, "w"); - - if (outfile == NULL) { - fprintf(stderr, "Cannot open output file\n"); - exit(1); - } - - /* Write the sum of the the absolute values of all lattice potentials */ - { - double abspotential = 0.0; - float tmp; - int i; - - for (i = 0; i < nx * ny * nz; i++) - abspotential += fabs((double) lattice_data[i]); - - tmp = (float) abspotential; - - fwrite(&tmp, 1, sizeof(float), outfile); - } - - /* Write the size of a lattice plane */ - { - uint32_t tmp; - - tmp = (uint32_t) (lattice->dim.nx * lattice->dim.ny); - fwrite(&tmp, 1, sizeof(uint32_t), outfile); - } - - /* Write the plane of lattice data at z=0 and z = nz-1 */ - { - int plane_size = nx * ny; - - fwrite(lattice_data, plane_size, sizeof(float), outfile); - fwrite(lattice_data + (nz-1) * plane_size, plane_size, sizeof(float), - outfile); - } - - /* Cleanup */ - fclose(outfile); -} diff --git a/tests/opencl/cutcp/output.h b/tests/opencl/cutcp/output.h deleted file mode 100644 index 13022cd9..00000000 --- a/tests/opencl/cutcp/output.h +++ /dev/null @@ -1,25 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2008-2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#ifndef OUTPUT_H -#define OUTPUT_H - -#include "cutoff.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void -write_lattice_summary(const char *filename, Lattice *lattice); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tests/opencl/cutcp/parboil.h b/tests/opencl/cutcp/parboil.h deleted file mode 100644 index 4c9a8b5e..00000000 --- a/tests/opencl/cutcp/parboil.h +++ /dev/null @@ -1,348 +0,0 @@ -/* - * (c) 2010 The Board of Trustees of the University of Illinois. - */ -#ifndef PARBOIL_HEADER -#define PARBOIL_HEADER - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* A platform as specified by the user on the command line */ -struct pb_PlatformParam { - char *name; /* The platform name. This string is owned. */ - char *version; /* The platform version; may be NULL. - * This string is owned. */ -}; - -/* Create a PlatformParam from the given strings. - * 'name' must not be NULL. 'version' may be NULL. - * If not NULL, the strings should have been allocated by malloc(), - * and they will be owned by the returned object. - */ -struct pb_PlatformParam * -pb_PlatformParam(char *name, char *version); - -void -pb_FreePlatformParam(struct pb_PlatformParam *); - -/* A criterion for how to select a device */ -enum pb_DeviceSelectionCriterion { - pb_Device_INDEX, /* Enumerate the devices and select one - * by its number */ - pb_Device_CPU, /* Select a CPU device */ - pb_Device_GPU, /* Select a GPU device */ - pb_Device_ACCELERATOR, /* Select an accelerator device */ - pb_Device_NAME /* Select a device by name */ -}; - -/* A device as specified by the user on the command line */ -struct pb_DeviceParam { - enum pb_DeviceSelectionCriterion criterion; - union { - int index; /* If criterion == pb_Device_INDEX, - * the index of the device */ - char *name; /* If criterion == pb_Device_NAME, - * the name of the device. - * This string is owned. */ - }; -}; - -struct pb_DeviceParam * -pb_DeviceParam_index(int index); - -struct pb_DeviceParam * -pb_DeviceParam_cpu(void); - -struct pb_DeviceParam * -pb_DeviceParam_gpu(void); - -struct pb_DeviceParam * -pb_DeviceParam_accelerator(void); - -/* Create a by-name device selection criterion. - * The string should have been allocated by malloc(), and it will will be - * owned by the returned object. - */ -struct pb_DeviceParam * -pb_DeviceParam_name(char *name); - -void -pb_FreeDeviceParam(struct pb_DeviceParam *); - -/* Command line parameters for benchmarks */ -struct pb_Parameters { - char *outFile; /* If not NULL, the raw output of the - * computation should be saved to this - * file. The string is owned. */ - char **inpFiles; /* A NULL-terminated array of strings - * holding the input file(s) for the - * computation. The array and strings - * are owned. */ - struct pb_PlatformParam *platform; /* If not NULL, the platform - * specified on the command line. */ - struct pb_DeviceParam *device; /* If not NULL, the device - * specified on the command line. */ -}; - -/* Read command-line parameters. - * - * The argc and argv parameters to main are read, and any parameters - * interpreted by this function are removed from the argument list. - * - * A new instance of struct pb_Parameters is returned. - * If there is an error, then an error message is printed on stderr - * and NULL is returned. - */ -struct pb_Parameters * -pb_ReadParameters(int *_argc, char **argv); - -/* Free an instance of struct pb_Parameters. - */ -void -pb_FreeParameters(struct pb_Parameters *p); - -void -pb_FreeStringArray(char **); - -/* Count the number of input files in a pb_Parameters instance. - */ -int -pb_Parameters_CountInputs(struct pb_Parameters *p); - -/* A time or duration. */ -//#if _POSIX_VERSION >= 200112L -typedef unsigned long long pb_Timestamp; /* time in microseconds */ -//#else -//# error "Timestamps not implemented" -//#endif - -enum pb_TimerState { - pb_Timer_STOPPED, - pb_Timer_RUNNING, -}; - -struct pb_Timer { - enum pb_TimerState state; - pb_Timestamp elapsed; /* Amount of time elapsed so far */ - pb_Timestamp init; /* Beginning of the current time interval, - * if state is RUNNING. End of the last - * recorded time interfal otherwise. */ -}; - -/* Reset a timer. - * Use this to initialize a timer or to clear - * its elapsed time. The reset timer is stopped. - */ -void -pb_ResetTimer(struct pb_Timer *timer); - -/* Start a timer. The timer is set to RUNNING mode and - * time elapsed while the timer is running is added to - * the timer. - * The timer should not already be running. - */ -void -pb_StartTimer(struct pb_Timer *timer); - -/* Stop a timer. - * This stops adding elapsed time to the timer. - * The timer should not already be stopped. - */ -void -pb_StopTimer(struct pb_Timer *timer); - -/* Get the elapsed time in seconds. */ -double -pb_GetElapsedTime(struct pb_Timer *timer); - -/* Execution time is assigned to one of these categories. */ -enum pb_TimerID { - pb_TimerID_NONE = 0, - pb_TimerID_IO, /* Time spent in input/output */ - pb_TimerID_KERNEL, /* Time spent computing on the device, - * recorded asynchronously */ - pb_TimerID_COPY, /* Time spent synchronously moving data - * to/from device and allocating/freeing - * memory on the device */ - pb_TimerID_DRIVER, /* Time spent in the host interacting with the - * driver, primarily for recording the time - * spent queueing asynchronous operations */ - pb_TimerID_COPY_ASYNC, /* Time spent in asynchronous transfers */ - pb_TimerID_COMPUTE, /* Time for all program execution other - * than parsing command line arguments, - * I/O, kernel, and copy */ - pb_TimerID_OVERLAP, /* Time double-counted in asynchronous and - * host activity: automatically filled in, - * not intended for direct usage */ - pb_TimerID_LAST /* Number of timer IDs */ -}; - -/* Dynamic list of asynchronously tracked times between events */ -struct pb_async_time_marker_list { - char *label; // actually just a pointer to a string - enum pb_TimerID timerID; /* The ID to which the interval beginning - * with this marker should be attributed */ - void * marker; - //cudaEvent_t marker; /* The driver event for this marker */ - struct pb_async_time_marker_list *next; -}; - -struct pb_SubTimer { - char *label; - struct pb_Timer timer; - struct pb_SubTimer *next; -}; - -struct pb_SubTimerList { - struct pb_SubTimer *current; - struct pb_SubTimer *subtimer_list; -}; - -/* A set of timers for recording execution times. */ -struct pb_TimerSet { - enum pb_TimerID current; - struct pb_async_time_marker_list* async_markers; - pb_Timestamp async_begin; - pb_Timestamp wall_begin; - struct pb_Timer timers[pb_TimerID_LAST]; - struct pb_SubTimerList *sub_timer_list[pb_TimerID_LAST]; -}; - -/* Reset all timers in the set. */ -void -pb_InitializeTimerSet(struct pb_TimerSet *timers); - -void -pb_AddSubTimer(struct pb_TimerSet *timers, char *label, enum pb_TimerID pb_Category); - -/* Select which timer the next interval of time should be accounted - * to. The selected timer is started and other timers are stopped. - * Using pb_TimerID_NONE stops all timers. */ -void -pb_SwitchToTimer(struct pb_TimerSet *timers, enum pb_TimerID timer); - -void -pb_SwitchToSubTimer(struct pb_TimerSet *timers, char *label, enum pb_TimerID category); - -/* Print timer values to standard output. */ -void -pb_PrintTimerSet(struct pb_TimerSet *timers); - -/* Release timer resources */ -void -pb_DestroyTimerSet(struct pb_TimerSet * timers); - -void -pb_SetOpenCL(void *clContextPtr, void *clCommandQueuePtr); - - -typedef struct pb_Device_tag { - char* name; - void* clDevice; - int id; - unsigned int in_use; - unsigned int available; -} pb_Device; - -struct pb_Context_tag; -typedef struct pb_Context_tag pb_Context; - -typedef struct pb_Platform_tag { - char* name; - char* version; - void* clPlatform; - unsigned int in_use; - pb_Context** contexts; - pb_Device** devices; -} pb_Platform; - -struct pb_Context_tag { - void* clPlatformId; - void* clContext; - void* clDeviceId; - pb_Platform* pb_platform; - pb_Device* pb_device; -}; - -// verbosely print out list of platforms and their devices to the console. -pb_Platform** -pb_GetPlatforms(); - -// Choose a platform according to the given platform specification -pb_Platform* -pb_GetPlatform(struct pb_PlatformParam *platform); - -// choose a platform: by name, name & version -pb_Platform* -pb_GetPlatformByName(const char* name); - -pb_Platform* -pb_GetPlatformByNameAndVersion(const char* name, const char* version); - -// Choose a device according to the given device specification -pb_Device* -pb_GetDevice(pb_Platform* pb_platform, struct pb_DeviceParam *device); - -pb_Device** -pb_GetDevices(pb_Platform* pb_platform); - -// choose a device by name. -pb_Device* -pb_GetDeviceByName(pb_Platform* pb_platform, const char* name); - -pb_Platform* -pb_GetPlatformByEnvVars(); - -pb_Context* -pb_InitOpenCLContext(struct pb_Parameters* parameters); - -void -pb_ReleasePlatforms(); - -void -pb_ReleaseContext(pb_Context* c); - -void -pb_PrintPlatformInfo(pb_Context* c); - -void -perf_init(); - -//#define MEASURE_KERNEL_TIME - -#include - -#ifdef MEASURE_KERNEL_TIME -#define clEnqueueNDRangeKernel(q,k,d,o,dg,db,a,b,c) pb_clEnqueueNDRangeKernel((q), (k), (d), (o), (dg), (db), (a), (b), (c)) -cl_int -pb_clEnqueueNDRangeKernel(cl_command_queue /* command_queue */, - cl_kernel /* kernel */, - cl_uint /* work_dim */, - const size_t * /* global_work_offset */, - const size_t * /* global_work_size */, - const size_t * /* local_work_size */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */); -#endif - -enum { T_FLOAT, T_DOUBLE, T_SHORT, T_INT, T_UCHAR }; -void pb_sig_float(char*, float*, int); -void pb_sig_double(char*, double*, int); -void pb_sig_short(char*, short*, int); -void pb_sig_int(char*, int*, int); -void pb_sig_uchar(char*, unsigned char*, unsigned int); -void pb_sig_clmem(char*, cl_command_queue, cl_mem, int); - -#ifdef __cplusplus -} -#endif - -#endif //PARBOIL_HEADER - diff --git a/tests/opencl/cutcp/parboil_opencl.c b/tests/opencl/cutcp/parboil_opencl.c deleted file mode 100644 index a4db1680..00000000 --- a/tests/opencl/cutcp/parboil_opencl.c +++ /dev/null @@ -1,1394 +0,0 @@ -/* - * (c) 2007 The Board of Trustees of the University of Illinois. - */ - -#include -#include -#include -#include -#include -#include - -#if _POSIX_VERSION >= 200112L -# include -#endif - -//#include "perfmon.h" - -cl_context *clContextPtr; -cl_command_queue *clCommandQueuePtr; - -// #define DISABLE_PARBOIL_TIMER - -/*****************************************************************************/ -/* Timer routines */ - -static int is_async(enum pb_TimerID timer) -{ - return (timer == pb_TimerID_KERNEL) || - (timer == pb_TimerID_COPY_ASYNC); -} - -static int is_blocking(enum pb_TimerID timer) -{ - return (timer == pb_TimerID_COPY) || (timer == pb_TimerID_NONE); -} - -#define INVALID_TIMERID pb_TimerID_LAST - -static int asyncs_outstanding(struct pb_TimerSet* timers) -{ - return (timers->async_markers != NULL) && - (timers->async_markers->timerID != INVALID_TIMERID); -} - -static struct pb_async_time_marker_list * -get_last_async(struct pb_TimerSet* timers) -{ - /* Find the last event recorded thus far */ - struct pb_async_time_marker_list * last_event = timers->async_markers; - if(last_event != NULL && last_event->timerID != INVALID_TIMERID) { - while(last_event->next != NULL && - last_event->next->timerID != INVALID_TIMERID) - last_event = last_event->next; - return last_event; - } else - return NULL; -} - -static void insert_marker(struct pb_TimerSet* tset, enum pb_TimerID timer) -{ - cl_int ciErrNum = CL_SUCCESS; - struct pb_async_time_marker_list ** new_event = &(tset->async_markers); - - while(*new_event != NULL && (*new_event)->timerID != INVALID_TIMERID) { - new_event = &((*new_event)->next); - } - - if(*new_event == NULL) { - *new_event = (struct pb_async_time_marker_list *) - malloc(sizeof(struct pb_async_time_marker_list)); - (*new_event)->marker = calloc(1, sizeof(cl_event)); - /* - // I don't think this is needed at all. I believe clEnqueueMarker 'creates' the event -#if ( __OPENCL_VERSION__ >= CL_VERSION_1_1 ) -fprintf(stderr, "Creating Marker [%d]\n", timer); - *((cl_event *)((*new_event)->marker)) = clCreateUserEvent(*clContextPtr, &ciErrNum); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Creating User Event Object!\n"); - } - ciErrNum = clSetUserEventStatus(*((cl_event *)((*new_event)->marker)), CL_QUEUED); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Setting User Event Status!\n"); - } -#endif -*/ - (*new_event)->next = NULL; - } - - /* valid event handle now aquired: insert the event record */ - (*new_event)->label = NULL; - (*new_event)->timerID = timer; - ciErrNum = clEnqueueMarker(*clCommandQueuePtr, (cl_event *)(*new_event)->marker); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Enqueueing Marker!\n"); - } - -} - -static void insert_submarker(struct pb_TimerSet* tset, char *label, enum pb_TimerID timer) -{ - cl_int ciErrNum = CL_SUCCESS; - struct pb_async_time_marker_list ** new_event = &(tset->async_markers); - - while(*new_event != NULL && (*new_event)->timerID != INVALID_TIMERID) { - new_event = &((*new_event)->next); - } - - if(*new_event == NULL) { - *new_event = (struct pb_async_time_marker_list *) - malloc(sizeof(struct pb_async_time_marker_list)); - (*new_event)->marker = calloc(1, sizeof(cl_event)); - /* -#if ( __OPENCL_VERSION__ >= CL_VERSION_1_1 ) -fprintf(stderr, "Creating SubMarker %s[%d]\n", label, timer); - *((cl_event *)((*new_event)->marker)) = clCreateUserEvent(*clContextPtr, &ciErrNum); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Creating User Event Object!\n"); - } - ciErrNum = clSetUserEventStatus(*((cl_event *)((*new_event)->marker)), CL_QUEUED); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Setting User Event Status!\n"); - } -#endif -*/ - (*new_event)->next = NULL; - } - - /* valid event handle now aquired: insert the event record */ - (*new_event)->label = label; - (*new_event)->timerID = timer; - ciErrNum = clEnqueueMarker(*clCommandQueuePtr, (cl_event *)(*new_event)->marker); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Enqueueing Marker!\n"); - } - -} - - -/* Assumes that all recorded events have completed */ -static pb_Timestamp record_async_times(struct pb_TimerSet* tset) -{ - struct pb_async_time_marker_list * next_interval = NULL; - struct pb_async_time_marker_list * last_marker = get_last_async(tset); - pb_Timestamp total_async_time = 0; - enum pb_TimerID timer; - - for(next_interval = tset->async_markers; next_interval != last_marker; - next_interval = next_interval->next) { - cl_ulong command_start=0, command_end=0; - cl_int ciErrNum = CL_SUCCESS; - - ciErrNum = clGetEventProfilingInfo(*((cl_event *)next_interval->marker), CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &command_start, NULL); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error getting first EventProfilingInfo: %d\n", ciErrNum); - } - - ciErrNum = clGetEventProfilingInfo(*((cl_event *)next_interval->next->marker), CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &command_end, NULL); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error getting second EventProfilingInfo: %d\n", ciErrNum); - } - - pb_Timestamp interval = (pb_Timestamp) (((double)(command_end - command_start)) / 1e3); - tset->timers[next_interval->timerID].elapsed += interval; - if (next_interval->label != NULL) { - struct pb_SubTimer *subtimer = tset->sub_timer_list[next_interval->timerID]->subtimer_list; - while (subtimer != NULL) { - if ( strcmp(subtimer->label, next_interval->label) == 0) { - subtimer->timer.elapsed += interval; - break; - } - subtimer = subtimer->next; - } - } - total_async_time += interval; - next_interval->timerID = INVALID_TIMERID; - } - - if(next_interval != NULL) - next_interval->timerID = INVALID_TIMERID; - - return total_async_time; -} - -static void -accumulate_time(pb_Timestamp *accum, - pb_Timestamp start, - pb_Timestamp end) -{ -//#if _POSIX_VERSION >= 200112L - *accum += end - start; -//#else -//# error "Timestamps not implemented for this system" -//#endif -} - -//#if _POSIX_VERSION >= 200112L -static pb_Timestamp get_time() -{ - //struct timeval tv; - //gettimeofday(&tv, NULL); - //return (pb_Timestamp) (tv.tv_sec * 1000000LL + tv.tv_usec); - return 0; -} -//#else -//# error "no supported time libraries are available on this platform" -//#endif - -void -pb_ResetTimer(struct pb_Timer *timer) -{ -//#ifndef DISABLE_PARBOIL_TIMER - timer->state = pb_Timer_STOPPED; - -//#if _POSIX_VERSION >= 200112L - timer->elapsed = 0; -//#else -//# error "pb_ResetTimer: not implemented for this system" -//#endif -//#endif -} - -void -pb_StartTimer(struct pb_Timer *timer) -{ -/*#ifndef DISABLE_PARBOIL_TIMER - if (timer->state != pb_Timer_STOPPED) { - fputs("Ignoring attempt to start a running timer\n", stderr); - return; - } - - timer->state = pb_Timer_RUNNING; - -#if _POSIX_VERSION >= 200112L - { - struct timeval tv; - gettimeofday(&tv, NULL); - timer->init = tv.tv_sec * 1000000LL + tv.tv_usec; - } -#else -# error "pb_StartTimer: not implemented for this system" -#endif -#endif*/ -} - -void -pb_StartTimerAndSubTimer(struct pb_Timer *timer, struct pb_Timer *subtimer) -{ -/*#ifndef DISABLE_PARBOIL_TIMER - - unsigned int numNotStopped = 0x3; // 11 - if (timer->state != pb_Timer_STOPPED) { - fputs("Warning: Timer was not stopped\n", stderr); - numNotStopped &= 0x1; // Zero out 2^1 - } - if (subtimer->state != pb_Timer_STOPPED) { - fputs("Warning: Subtimer was not stopped\n", stderr); - numNotStopped &= 0x2; // Zero out 2^0 - } - if (numNotStopped == 0x0) { - fputs("Ignoring attempt to start running timer and subtimer\n", stderr); - return; - } - - timer->state = pb_Timer_RUNNING; - subtimer->state = pb_Timer_RUNNING; - -#if _POSIX_VERSION >= 200112L - { - struct timeval tv; - gettimeofday(&tv, NULL); - - if (numNotStopped & 0x2) { - timer->init = tv.tv_sec * 1000000LL + tv.tv_usec; - } - - if (numNotStopped & 0x1) { - subtimer->init = tv.tv_sec * 1000000LL + tv.tv_usec; - } - } -#else -# error "pb_StartTimer: not implemented for this system" -#endif - -#endif*/ -} - -void -pb_StopTimer(struct pb_Timer *timer) -{ -/*#ifndef DISABLE_PARBOIL_TIMER - - pb_Timestamp fini; - - if (timer->state != pb_Timer_RUNNING) { - fputs("Ignoring attempt to stop a stopped timer\n", stderr); - return; - } - - timer->state = pb_Timer_STOPPED; - -#if _POSIX_VERSION >= 200112L - { - struct timeval tv; - gettimeofday(&tv, NULL); - fini = tv.tv_sec * 1000000LL + tv.tv_usec; - } -#else -# error "pb_StopTimer: not implemented for this system" -#endif - - accumulate_time(&timer->elapsed, timer->init, fini); - timer->init = fini; - -#endif*/ -} - -void pb_StopTimerAndSubTimer(struct pb_Timer *timer, struct pb_Timer *subtimer) { -/*#ifndef DISABLE_PARBOIL_TIMER - - pb_Timestamp fini; - - unsigned int numNotRunning = 0x3; // 11 - if (timer->state != pb_Timer_RUNNING) { - fputs("Warning: Timer was not running\n", stderr); - numNotRunning &= 0x1; // Zero out 2^1 - } - if (subtimer->state != pb_Timer_RUNNING) { - fputs("Warning: Subtimer was not running\n", stderr); - numNotRunning &= 0x2; // Zero out 2^0 - } - if (numNotRunning == 0x0) { - fputs("Ignoring attempt to stop stopped timer and subtimer\n", stderr); - return; - } - - - timer->state = pb_Timer_STOPPED; - subtimer->state = pb_Timer_STOPPED; - -#if _POSIX_VERSION >= 200112L - { - struct timeval tv; - gettimeofday(&tv, NULL); - fini = tv.tv_sec * 1000000LL + tv.tv_usec; - } -#else -# error "pb_StopTimer: not implemented for this system" -#endif - - if (numNotRunning & 0x2) { - accumulate_time(&timer->elapsed, timer->init, fini); - timer->init = fini; - } - - if (numNotRunning & 0x1) { - accumulate_time(&subtimer->elapsed, subtimer->init, fini); - subtimer->init = fini; - } - -#endif*/ -} - -/* Get the elapsed time in seconds. */ -double -pb_GetElapsedTime(struct pb_Timer *timer) -{ - /*double ret; -#ifndef DISABLE_PARBOIL_TIMER - - if (timer->state != pb_Timer_STOPPED) { - fputs("Elapsed time from a running timer is inaccurate\n", stderr); - } - -#if _POSIX_VERSION >= 200112L - ret = timer->elapsed / 1e6; -#else -# error "pb_GetElapsedTime: not implemented for this system" -#endif -#endif - return ret;*/ - return 0; -} - -void -pb_InitializeTimerSet(struct pb_TimerSet *timers) -{ -/*#ifndef DISABLE_PARBOIL_TIMER - int n; - - timers->wall_begin = 0; //get_time(); - timers->current = pb_TimerID_NONE; - - timers->async_markers = NULL; - - for (n = 0; n < pb_TimerID_LAST; n++) { - pb_ResetTimer(&timers->timers[n]); - timers->sub_timer_list[n] = NULL; - } -#endif*/ -} - -void pb_SetOpenCL(void *p_clContextPtr, void *p_clCommandQueuePtr) { - clContextPtr = ((cl_context *)p_clContextPtr); - clCommandQueuePtr = ((cl_command_queue *)p_clCommandQueuePtr); -} - -void -pb_AddSubTimer(struct pb_TimerSet *timers, char *label, enum pb_TimerID pb_Category) { -/*#ifndef DISABLE_PARBOIL_TIMER - - struct pb_SubTimer *subtimer = (struct pb_SubTimer *) malloc - (sizeof(struct pb_SubTimer)); - - int len = strlen(label); - - subtimer->label = (char *) malloc (sizeof(char)*(len+1)); - sprintf(subtimer->label, "%s\0", label); - - pb_ResetTimer(&subtimer->timer); - subtimer->next = NULL; - - struct pb_SubTimerList *subtimerlist = timers->sub_timer_list[pb_Category]; - if (subtimerlist == NULL) { - subtimerlist = (struct pb_SubTimerList *) calloc - (1, sizeof(struct pb_SubTimerList)); - subtimerlist->subtimer_list = subtimer; - timers->sub_timer_list[pb_Category] = subtimerlist; - } else { - // Append to list - struct pb_SubTimer *element = subtimerlist->subtimer_list; - while (element->next != NULL) { - element = element->next; - } - element->next = subtimer; - } - -#endif*/ -} - -void -pb_SwitchToTimer(struct pb_TimerSet *timers, enum pb_TimerID timer) -{ -#if 0 -#ifndef DISABLE_PARBOIL_TIMER - - /* Stop the currently running timer */ - if (timers->current != pb_TimerID_NONE) { - struct pb_SubTimerList *subtimerlist = timers->sub_timer_list[timers->current]; - struct pb_SubTimer *currSubTimer = (subtimerlist != NULL) ? subtimerlist->current : NULL; - - if (!is_async(timers->current) ) { - if (timers->current != timer) { - if (currSubTimer != NULL) { - pb_StopTimerAndSubTimer(&timers->timers[timers->current], &currSubTimer->timer); - } else { - pb_StopTimer(&timers->timers[timers->current]); - } - } else { - if (currSubTimer != NULL) { - pb_StopTimer(&currSubTimer->timer); - } - } - } else { - insert_marker(timers, timer); - if (!is_async(timer)) { // if switching to async too, keep driver going - pb_StopTimer(&timers->timers[pb_TimerID_DRIVER]); - } - } - } - - pb_Timestamp currentTime = 0; //get_time(); - - /* The only cases we check for asynchronous task completion is - * when an overlapping CPU operation completes, or the next - * segment blocks on completion of previous async operations */ - if( asyncs_outstanding(timers) && - (!is_async(timers->current) || is_blocking(timer) ) ) { - - struct pb_async_time_marker_list * last_event = get_last_async(timers); - /* CL_COMPLETE if completed */ - - cl_int ciErrNum = CL_SUCCESS; - cl_int async_done = CL_COMPLETE; - - ciErrNum = clGetEventInfo(*((cl_event *)last_event->marker), CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(cl_int), &async_done, NULL); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Querying EventInfo!\n"); - } - - - if(is_blocking(timer)) { - /* Async operations completed after previous CPU operations: - * overlapped time is the total CPU time since this set of async - * operations were first issued */ - - // timer to switch to is COPY or NONE - if(async_done != CL_COMPLETE) { - accumulate_time(&(timers->timers[pb_TimerID_OVERLAP].elapsed), - timers->async_begin,currentTime); - } - - /* Wait on async operation completion */ - ciErrNum = clWaitForEvents(1, (cl_event *)last_event->marker); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Waiting for Events!\n"); - } - - pb_Timestamp total_async_time = record_async_times(timers); - - /* Async operations completed before previous CPU operations: - * overlapped time is the total async time */ - if(async_done == CL_COMPLETE) { - //fprintf(stderr, "Async_done: total_async_type = %lld\n", total_async_time); - timers->timers[pb_TimerID_OVERLAP].elapsed += total_async_time; - } - - } else - /* implies (!is_async(timers->current) && asyncs_outstanding(timers)) */ - // i.e. Current Not Async (not KERNEL/COPY_ASYNC) but there are outstanding - // so something is deeper in stack - if(async_done == CL_COMPLETE ) { - /* Async operations completed before previous CPU operations: - * overlapped time is the total async time */ - timers->timers[pb_TimerID_OVERLAP].elapsed += record_async_times(timers); - } - } - - /* Start the new timer */ - if (timer != pb_TimerID_NONE) { - if(!is_async(timer)) { - pb_StartTimer(&timers->timers[timer]); - } else { - // toSwitchTo Is Async (KERNEL/COPY_ASYNC) - if (!asyncs_outstanding(timers)) { - /* No asyncs outstanding, insert a fresh async marker */ - - insert_marker(timers, timer); - timers->async_begin = currentTime; - } else if(!is_async(timers->current)) { - /* Previous asyncs still in flight, but a previous SwitchTo - * already marked the end of the most recent async operation, - * so we can rename that marker as the beginning of this async - * operation */ - - struct pb_async_time_marker_list * last_event = get_last_async(timers); - last_event->label = NULL; - last_event->timerID = timer; - } - if (!is_async(timers->current)) { - pb_StartTimer(&timers->timers[pb_TimerID_DRIVER]); - } - } - } - timers->current = timer; - -#endif -#endif -} - -void -pb_SwitchToSubTimer(struct pb_TimerSet *timers, char *label, enum pb_TimerID category) -{ -#if 0 -#ifndef DISABLE_PARBOIL_TIMER - struct pb_SubTimerList *subtimerlist = timers->sub_timer_list[timers->current]; - struct pb_SubTimer *curr = (subtimerlist != NULL) ? subtimerlist->current : NULL; - - if (timers->current != pb_TimerID_NONE) { - if (!is_async(timers->current) ) { - if (timers->current != category) { - if (curr != NULL) { - pb_StopTimerAndSubTimer(&timers->timers[timers->current], &curr->timer); - } else { - pb_StopTimer(&timers->timers[timers->current]); - } - } else { - if (curr != NULL) { - pb_StopTimer(&curr->timer); - } - } - } else { - insert_submarker(timers, label, category); - if (!is_async(category)) { // if switching to async too, keep driver going - pb_StopTimer(&timers->timers[pb_TimerID_DRIVER]); - } - } - } - - pb_Timestamp currentTime = 0; //get_time(); - - /* The only cases we check for asynchronous task completion is - * when an overlapping CPU operation completes, or the next - * segment blocks on completion of previous async operations */ - if( asyncs_outstanding(timers) && - (!is_async(timers->current) || is_blocking(category) ) ) { - - struct pb_async_time_marker_list * last_event = get_last_async(timers); - /* CL_COMPLETE if completed */ - - cl_int ciErrNum = CL_SUCCESS; - cl_int async_done = CL_COMPLETE; - - ciErrNum = clGetEventInfo(*((cl_event *)last_event->marker), CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(cl_int), &async_done, NULL); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Querying EventInfo!\n"); - } - - if(is_blocking(category)) { - /* Async operations completed after previous CPU operations: - * overlapped time is the total CPU time since this set of async - * operations were first issued */ - - // timer to switch to is COPY or NONE - // if it hasn't already finished, then just take now and use that as the elapsed time in OVERLAP - // anything happening after now isn't OVERLAP because everything is being stopped to wait for synchronization - // it seems that the extra sync wall time isn't being recorded anywhere - if(async_done != CL_COMPLETE) - accumulate_time(&(timers->timers[pb_TimerID_OVERLAP].elapsed), - timers->async_begin,currentTime); - - /* Wait on async operation completion */ - ciErrNum = clWaitForEvents(1, (cl_event *)last_event->marker); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Waiting for Events!\n"); - } - pb_Timestamp total_async_time = record_async_times(timers); - - /* Async operations completed before previous CPU operations: - * overlapped time is the total async time */ - // If it did finish, then accumulate all the async time that did happen into OVERLAP - // the immediately preceding EventSynchronize theoretically didn't have any effect since it was already completed. - if(async_done == CL_COMPLETE /*cudaSuccess*/) - timers->timers[pb_TimerID_OVERLAP].elapsed += total_async_time; - - } else - /* implies (!is_async(timers->current) && asyncs_outstanding(timers)) */ - // i.e. Current Not Async (not KERNEL/COPY_ASYNC) but there are outstanding - // so something is deeper in stack - if(async_done == CL_COMPLETE /*cudaSuccess*/) { - /* Async operations completed before previous CPU operations: - * overlapped time is the total async time */ - timers->timers[pb_TimerID_OVERLAP].elapsed += record_async_times(timers); - } - // else, this isn't blocking, so just check the next time around - } - - subtimerlist = timers->sub_timer_list[category]; - struct pb_SubTimer *subtimer = NULL; - - if (label != NULL) { - subtimer = subtimerlist->subtimer_list; - while (subtimer != NULL) { - if (strcmp(subtimer->label, label) == 0) { - break; - } else { - subtimer = subtimer->next; - } - } - } - - /* Start the new timer */ - if (category != pb_TimerID_NONE) { - if(!is_async(category)) { - if (subtimerlist != NULL) { - subtimerlist->current = subtimer; - } - - if (category != timers->current && subtimer != NULL) { - pb_StartTimerAndSubTimer(&timers->timers[category], &subtimer->timer); - } else if (subtimer != NULL) { - pb_StartTimer(&subtimer->timer); - } else { - pb_StartTimer(&timers->timers[category]); - } - } else { - if (subtimerlist != NULL) { - subtimerlist->current = subtimer; - } - - // toSwitchTo Is Async (KERNEL/COPY_ASYNC) - if (!asyncs_outstanding(timers)) { - /* No asyncs outstanding, insert a fresh async marker */ - insert_submarker(timers, label, category); - timers->async_begin = currentTime; - } else if(!is_async(timers->current)) { - /* Previous asyncs still in flight, but a previous SwitchTo - * already marked the end of the most recent async operation, - * so we can rename that marker as the beginning of this async - * operation */ - - struct pb_async_time_marker_list * last_event = get_last_async(timers); - last_event->timerID = category; - last_event->label = label; - } // else, marker for switchToThis was already inserted - - //toSwitchto is already asynchronous, but if current/prev state is async too, then DRIVER is already running - if (!is_async(timers->current)) { - pb_StartTimer(&timers->timers[pb_TimerID_DRIVER]); - } - } - } - - timers->current = category; -#endif -#endif -} - -void -pb_PrintTimerSet(struct pb_TimerSet *timers) -{ -#if 0 -#ifndef DISABLE_PARBOIL_TIMER - pb_Timestamp wall_end = 0; //get_time(); - - struct pb_Timer *t = timers->timers; - struct pb_SubTimer* sub = NULL; - - int maxSubLength; - - const char *categories[] = { - "IO", "Kernel", "Copy", "Driver", "Copy Async", "Compute" - }; - - const int maxCategoryLength = 10; - - int i; - for(i = 1; i < pb_TimerID_LAST-1; ++i) { // exclude NONE and OVRELAP from this format - if(pb_GetElapsedTime(&t[i]) != 0) { - - // Print Category Timer - printf("%-*s: %f\n", maxCategoryLength, categories[i-1], pb_GetElapsedTime(&t[i])); - - if (timers->sub_timer_list[i] != NULL) { - sub = timers->sub_timer_list[i]->subtimer_list; - maxSubLength = 0; - while (sub != NULL) { - // Find longest SubTimer label - if (strlen(sub->label) > maxSubLength) { - maxSubLength = strlen(sub->label); - } - sub = sub->next; - } - - // Fit to Categories - if (maxSubLength <= maxCategoryLength) { - maxSubLength = maxCategoryLength; - } - - sub = timers->sub_timer_list[i]->subtimer_list; - - // Print SubTimers - while (sub != NULL) { - printf(" -%-*s: %f\n", maxSubLength, sub->label, pb_GetElapsedTime(&sub->timer)); - sub = sub->next; - } - } - } - } - - if(pb_GetElapsedTime(&t[pb_TimerID_OVERLAP]) != 0) - printf("CPU/Kernel Overlap: %f\n", pb_GetElapsedTime(&t[pb_TimerID_OVERLAP])); - - float walltime = (wall_end - timers->wall_begin)/ 1e6; - printf("Timer Wall Time: %f\n", walltime); - -#endif -#endif -} - -void pb_DestroyTimerSet(struct pb_TimerSet * timers) -{ -#ifndef DISABLE_PARBOIL_TIMER - /* clean up all of the async event markers */ - struct pb_async_time_marker_list* event = timers->async_markers; - while(event != NULL) { - - cl_int ciErrNum = CL_SUCCESS; - ciErrNum = clWaitForEvents(1, (cl_event *)(event)->marker); - if (ciErrNum != CL_SUCCESS) { - //fprintf(stderr, "Error Waiting for Events!\n"); - } - - ciErrNum = clReleaseEvent( *((cl_event *)(event)->marker) ); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Release Events!\n"); - } - - free((event)->marker); - struct pb_async_time_marker_list* next = ((event)->next); - - free(event); - - // (*event) = NULL; - event = next; - } - - int i = 0; - for(i = 0; i < pb_TimerID_LAST; ++i) { - if (timers->sub_timer_list[i] != NULL) { - struct pb_SubTimer *subtimer = timers->sub_timer_list[i]->subtimer_list; - struct pb_SubTimer *prev = NULL; - while (subtimer != NULL) { - free(subtimer->label); - prev = subtimer; - subtimer = subtimer->next; - free(prev); - } - free(timers->sub_timer_list[i]); - } - } -#endif -} - -static pb_Platform** ptr = NULL; - -// verbosely print out list of platforms and their devices to the console. -pb_Platform** -pb_GetPlatforms() { - if (ptr == NULL) { - cl_uint num_platforms; - clGetPlatformIDs(0, NULL, &num_platforms); - if (num_platforms == 0) return NULL; - - ptr = (pb_Platform **) malloc(sizeof(pb_Platform *) * (num_platforms + 1)); - cl_platform_id* ids = (cl_platform_id *) malloc(num_platforms * sizeof(cl_platform_id)); - clGetPlatformIDs(num_platforms, ids, NULL); - - unsigned int i; - for (i = 0; i < num_platforms; i++) { - ptr[i] = (pb_Platform *) malloc(sizeof(pb_Platform)); - ptr[i]->clPlatform = ids[i]; - ptr[i]->contexts = NULL; - ptr[i]->in_use = 0; - ptr[i]->devices = NULL; - - size_t sz; - clGetPlatformInfo(ids[i], CL_PLATFORM_NAME, 0, NULL, &sz); - char* name = (char *) malloc(sz + 1); - clGetPlatformInfo(ids[i], CL_PLATFORM_NAME, sz, name, NULL); - name[sz] = '\0'; - ptr[i]->name = name; - - clGetPlatformInfo(ids[i], CL_PLATFORM_VERSION, 0, NULL, &sz); - char* version = (char *) malloc(sz + 1); - clGetPlatformInfo(ids[i], CL_PLATFORM_VERSION, sz, version, NULL); - version[sz] = '\0'; - ptr[i]->version = version; - } - ptr[i] = NULL; - - free(ids); - } - - return (pb_Platform**) ptr; -} - -pb_Context* -createContext(pb_Platform* pb_platform, pb_Device* pb_device) { - pb_Context* c = (pb_Context*) malloc(sizeof(pb_Context)); - cl_int clStatus; - cl_context_properties clCps[3] = { - CL_CONTEXT_PLATFORM, (cl_context_properties)(pb_platform->clPlatform), 0 - }; - c->clContext = - clCreateContext(clCps, 1, (cl_device_id*)&pb_device->clDevice, NULL, NULL, &clStatus); - c->clPlatformId = pb_platform->clPlatform; - c->clDeviceId = pb_device->clDevice; - c->pb_platform = pb_platform; - c->pb_device = pb_device; - pb_platform->in_use = 1; - pb_device->in_use = 1; - unsigned int i = 0; - if (pb_platform->contexts == NULL) { - pb_platform->contexts = (pb_Context**) malloc(2*sizeof(pb_Context*)); - } else { - for (i = 0; pb_platform->contexts[i] != NULL; i++) {}; - pb_platform->contexts = (pb_Context**) realloc(pb_platform->contexts, - (i+1)*sizeof(pb_Context*)); - } - pb_platform->contexts[i+1] = NULL; - pb_platform->contexts[i] = c; - return c; -} - -// choose a platform by name. -pb_Platform* -pb_GetPlatformByName(const char* name) { - pb_Platform** ps = (pb_Platform **) pb_GetPlatforms(); - if (ps == NULL) return NULL; - if (name == NULL) { - return *ps; - } - - while (*ps) { - if (strstr((*ps)->name, name)) break; - ps++; - } - return (pb_Platform*) *ps; -} - -pb_Device** -pb_GetDevices(pb_Platform* pb_platform) { - if (pb_platform->devices == NULL) { - cl_uint num_devs; - cl_device_id* dev_ids; - clGetDeviceIDs((cl_platform_id) pb_platform->clPlatform, - CL_DEVICE_TYPE_ALL, 0, NULL, &num_devs); - if (num_devs == 0) return NULL; - - pb_platform->devices = - (pb_Device **) malloc((num_devs + 1) * sizeof(pb_Device *)); - dev_ids = (cl_device_id *) malloc(sizeof(cl_device_id) * num_devs); - clGetDeviceIDs((cl_platform_id) pb_platform->clPlatform, - CL_DEVICE_TYPE_ALL, num_devs, dev_ids, NULL); - - unsigned int i; - for (i = 0; i < num_devs; i++) { - pb_platform->devices[i] = (pb_Device *) malloc(sizeof(pb_Device)); - - pb_platform->devices[i]->clDevice = dev_ids[i]; - pb_platform->devices[i]->id = i; - - size_t sz; - clGetDeviceInfo(dev_ids[i], CL_DEVICE_NAME, 0, NULL, &sz); - char* name = (char *) malloc(sz + 1); - clGetDeviceInfo(dev_ids[i], CL_DEVICE_NAME, sz, name, NULL); - name[sz] = '\0'; - pb_platform->devices[i]->name = (char *) name; - - cl_bool available; - clGetDeviceInfo(dev_ids[i], CL_DEVICE_AVAILABLE, sizeof(cl_bool), &available, NULL); - pb_platform->devices[i]->available = (int) available; - - pb_platform->devices[i]->in_use = 0; - } - pb_platform->devices[i] = NULL; - } - return (pb_Device **) pb_platform->devices; -} - -// choose a device by name. -static pb_Device* -pb_SelectDeviceByName(pb_Device **ds, const char* name) { - if (ds == NULL) return NULL; - if (name == NULL) return *ds; - while (*ds) { - if (strstr((*ds)->name, name)) break; - ds++; - } - - return *ds; -} - -// choose a device by name and set the device's 'in_use' flag. -pb_Device* -pb_GetDeviceByName(pb_Platform* pb_platform, const char* name) { - pb_Device** ds = (pb_Device **) pb_GetDevices(pb_platform); - pb_Device *d = pb_SelectDeviceByName(ds, name); - - if (d) d->in_use = 1; - - return d; -} - -void -pb_ReleasePlatforms() { - if (!ptr) return; - pb_Platform** cur_ptr = ptr; - while (*cur_ptr) { - pb_Platform* pfptr = *cur_ptr++; - if (pfptr->devices) { - pb_Device** dvptr = pfptr->devices; - while (*dvptr) { - pb_Device* d = *dvptr++; - free(d->name); - free(d); - } - free(pfptr->devices); - } - if (pfptr->contexts) { - pb_Context** cptr = pfptr->contexts; - while (*cptr) { - free(*cptr++); - } - free(pfptr->contexts); - } - free(pfptr->name); - free(pfptr); - } - free(ptr); - ptr = NULL; -} - -pb_Platform* -pb_GetPlatformByNameAndVersion(const char* name, const char* version) { - pb_Platform** ps = (pb_Platform **) pb_GetPlatforms(); - if (ps == NULL) return NULL; - if (name == NULL) return *ps; - while (*ps) { - if (strstr((*ps)->name, name) && strstr((*ps)->version, version)) break; - ps++; - } - return (pb_Platform*) *ps; -} - -/* Return a pointer to the device at the specified index, or NULL. - * Used by pb_GetDevice. */ -static pb_Device * -select_device_by_index(pb_Device** ds, int id) -{ - int i = 0; - pb_Device** p = ds; - while (*p && (i < id)) { p++; i++; } - return *p; -} - -/* Return a pointer to the device with the specified type, or NULL. - * Used by pb_GetDevice. */ -static pb_Device * -select_device_by_type(pb_Device** ds, - enum pb_DeviceSelectionCriterion criterion) -{ - cl_device_type sought_type; - - /* Determine the OpenCL device type to search for */ - switch(criterion) { - case pb_Device_CPU: - sought_type = CL_DEVICE_TYPE_CPU; - break; - case pb_Device_GPU: - sought_type = CL_DEVICE_TYPE_GPU; - break; - case pb_Device_ACCELERATOR: - sought_type = CL_DEVICE_TYPE_ACCELERATOR; - break; - default: - fprintf(stderr, "pb_GetDevice: Invalid device type"); - exit(-1); - } - - /* Find the device */ - { - pb_Device** p = ds; - cl_device_type type; - while (*p) { - clGetDeviceInfo(((cl_device_id) ((*p)->clDevice)), CL_DEVICE_TYPE, - sizeof(cl_device_type), &type, NULL); - if (type == sought_type) break; - } - - return *p; - } -} - -pb_Device* -pb_GetDevice(pb_Platform* pb_platform, struct pb_DeviceParam *device) -{ - pb_Device** ds = (pb_Device **) pb_GetDevices(pb_platform); - - // The list of devices must be nonempty - if (ds == NULL || *ds == NULL) { - fprintf(stderr, "Error: No device is found in platform: name = %s, version = %s\n.", pb_platform->name, pb_platform->version); - exit(-1); - } - - pb_Device *selected_device = NULL; - - if (device != NULL) { - /* Use 'device' to select and return a device. - * If unable to select a device, fall - * back on the default selection mechanism. */ - switch(device->criterion) { - case pb_Device_INDEX: - selected_device = select_device_by_index(ds, device->index); - break; - case pb_Device_GPU: - case pb_Device_CPU: - case pb_Device_ACCELERATOR: - selected_device = select_device_by_type(ds, device->criterion); - break; - case pb_Device_NAME: - selected_device = pb_SelectDeviceByName(ds, device->name); - break; - default: - fprintf(stderr, "pb_GetDevice: Invalid argument"); - exit(-1); - } - } - - /* By default or if user-specified selection failed, - * select the first device */ - if (selected_device == NULL) - selected_device = *ds; - - /* Set the in_use flag */ - selected_device->in_use = 1; - - return selected_device; -} - -pb_Device* -pb_GetDeviceByEnvVars(pb_Platform* pb_platform) { - - /* Convert environment variables to a 'pb_DeviceParam' */ - struct pb_DeviceParam *param = NULL; - - char* device_num = getenv("PARBOIL_DEVICE_NUMBER"); - if (device_num && strcmp(device_num, "")) { - int id = atoi(device_num); - param = pb_DeviceParam_index(id); - } - else { - char* device_name = getenv("PARBOIL_DEVICE_NAME"); - if (device_name && strcmp(device_name, "")) { - param = pb_DeviceParam_name(strdup(device_name)); - } - else { - char* device_type = getenv("PARBOIL_DEVICE_TYPE"); - if (device_type && strcmp(device_type, "")) { - if (strcmp(device_type, "CPU") == 0) - param = pb_DeviceParam_cpu(); - else if (strcmp(device_type, "GPU") == 0) - param = pb_DeviceParam_gpu(); - else if (strcmp(device_type, "ACCELERATOR") == 0) - param = pb_DeviceParam_accelerator(); - } - } - } - - /* Get a device */ - pb_Device *d = pb_GetDevice(pb_platform, param); - pb_FreeDeviceParam(param); - - return d; -} - -pb_Platform* -pb_GetPlatformByEnvVars() { - char* name = getenv("PARBOIL_PLATFORM_NAME"); - char* version = getenv("PARBOIL_PLATFORM_VERSION"); - - /* Create a pb_PlatformParam object (or NULL) representing the data from the - * environment variables */ - struct pb_PlatformParam *platform; - - if (name) { - if (version) { - platform = pb_PlatformParam(strdup(name), strdup(version)); - } - else { - platform = pb_PlatformParam(strdup(name), NULL); - } - } - else { - platform = NULL; - } - - /* Convert to a platform */ - pb_Platform *p = pb_GetPlatform(platform); - pb_FreePlatformParam(platform); - - return p; -} - -/* Choose an OpenCL platform based on the given command-line parameters. - * If NULL, use the default OpenCL platform. */ -pb_Platform* -pb_GetPlatform(struct pb_PlatformParam *platform) { - if (platform != NULL) { - /* Try to use command-line parameters to choose platform */ - char *name = platform->name; - char *version = platform->version; - - if (!name) { - fprintf(stderr, "Internal error: NULL pointer"); - exit(-1); - } - - if (version) { - pb_Platform* p = pb_GetPlatformByNameAndVersion(name, version); - if (p) return p; - } - - pb_Platform* p = pb_GetPlatformByName(name); - if (p) return p; - } - - pb_Platform* p = pb_GetPlatformByName(NULL); - if (p == NULL) { - fprintf(stderr, "Error: No OpenCL platform in this system. Exiting."); - exit(-1); - } - return p; -} - -//extern void perf_init(); -//extern void mxpa_scheduler_init(); - -pb_Context* -pb_InitOpenCLContext(struct pb_Parameters* parameters) { -#if 0 - pb_Platform* ps = pb_GetPlatform(parameters->platform); - if (!ps) return NULL; - pb_Device* ds = pb_GetDevice(ps, parameters->device); - if (!ds) return NULL; - - /* HERE INITIALIZE TIMER */ - //perf_init(); - //mxpa_scheduler_init(); - - pb_Context* c = createContext(ps, ds); - pb_PrintPlatformInfo(c); - return c; -#endif - cl_int _err; - cl_platform_id platform_id; - cl_device_id device_id; - cl_context context; - clGetPlatformIDs(1, &platform_id, NULL); - clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL); - context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &_err); - - pb_Context* c = (pb_Context*)malloc(sizeof(pb_Context)); - c->clContext = context; - c->clDeviceId = device_id; - c->clPlatformId = platform_id; - c->pb_platform = (pb_Platform*)malloc(sizeof(pb_Platform)); - c->pb_device = (pb_Device*)malloc(sizeof(pb_Device)); - c->pb_platform->devices = (pb_Device**)malloc(sizeof(pb_Device*) * 2); - c->pb_platform->devices[0] = c->pb_device; - c->pb_platform->devices[1] = NULL; - c->pb_platform->contexts = (pb_Context**)malloc(sizeof(pb_Context*) * 2); - c->pb_platform->contexts[0] = c; - c->pb_platform->contexts[1] = NULL; - c->pb_platform->in_use = 1; - c->pb_device->in_use = 1; - return c; -} - -void -pb_ReleaseOpenCLContext(pb_Context* c) { - pb_ReleasePlatforms(); -} - -void -pb_PrintPlatformInfo(pb_Context* c) { - /*pb_Platform** ps = pb_GetPlatforms(); - if (!ps) { - fprintf (stderr, "No platform found"); - return; - } - - printf ("********************************************************\n"); - printf ("DETECTED OPENCL PLATFORMS AND DEVICES:\n"); - printf ("--------------------------------------------------------\n"); - - while (*ps) { - printf ("PLATFORM = %s, %s", (*ps)->name, (*ps)->version); - if (c->pb_platform == *ps) printf (" (SELECTED)"); - printf ("\n"); - - pb_Device** ds = (pb_Device **) pb_GetDevices((*ps)); - if (ds == NULL) { - printf (" + (No devices)\n"); - } else { - while (*ds) { - printf (" + %d: %s", (*ds)->id, (*ds)->name); - if (c->pb_device == *ds) printf (" (SELECTED)"); - printf ("\n"); - ds++; - } - } - - ps++; - } - printf ("********************************************************\n");*/ -} - -#ifdef MEASURE_KERNEL_TIME - -#undef clEnqueueNDRangeKernel - -//extern void pin_trace_enable(char*); -//extern void pin_trace_disable(char*); - -cl_int -pb_clEnqueueNDRangeKernel(cl_command_queue q/* command_queue */, - cl_kernel k/* kernel */, - cl_uint d/* work_dim */, - const size_t * o/* global_work_offset */, - const size_t * gws/* global_work_size */, - const size_t * lws/* local_work_size */, - cl_uint n/* num_events_in_wait_list */, - const cl_event * w/* event_wait_list */, - cl_event * e/* event */) { - - char buf[128]; - struct timeval begin, end; - clGetKernelInfo(k, CL_KERNEL_FUNCTION_NAME, 128, buf, NULL); - -#if 0 - int i; - for (i = 0; i < d; i++) { - printf ("%s: %d: %d / %d\n", buf, i, gws[i], (lws == NULL ? 0 : lws[i])); - } -#endif - - clFinish(q); clFlush(q); - //pin_trace_enable(buf); - //gettimeofday(&begin, NULL); - cl_int result = clEnqueueNDRangeKernel(q, k, d, o, gws, lws, n, w, e); - clFinish(q); clFlush(q); - //gettimeofday(&end, NULL); - //pin_trace_disable(buf); - //float t = (float)(end.tv_sec - begin.tv_sec) + (end.tv_usec - begin.tv_usec) / 1000000.0f; - fflush(stdout); - fflush(stderr); - //printf ("PBTIMER: %s: %f\n", buf, t); - return result; -} - -#endif - -void -pb_sig_float(char* c, float* p, int sz) { - int i; - double s = 0.0; - for (i = 0; i < sz; i++) s += p[i] * (float)(i+1); - printf ("[Signature] %s = %lf\n", c, s); -} - -void -pb_sig_double(char* c, double* p, int sz) { - int i; - double s = 0.0; - for (i = 0; i < sz; i++) s += p[i]; - printf ("[Signature] %s = %lf\n", c, s); -} - -void -pb_sig_short(char* c, short* p, int sz) { - int i; - long long int s = 0; - for (i = 0; i < sz; i++) s += p[i]; - printf ("[Signature] %s = %lld\n", c, s); -} - -void -pb_sig_int(char* c, int* p, int sz) { - int i; - long long int s = 0; - for (i = 0; i < sz; i++) s += p[i]; - printf ("[Signature] %s = %lld\n", c, s); -} - -void -pb_sig_uchar(char* c, unsigned char* p, unsigned int sz) { - int i; - unsigned long long int s = 0; - for (i = 0; i < sz; i++) s += p[i]; - printf ("[Signature] %s = %lld\n", c, s); -} - -void pb_sig_clmem(char* s, cl_command_queue command_queue, cl_mem memobj, int ty) { - size_t sz; - if (clGetMemObjectInfo(memobj, CL_MEM_SIZE, sizeof(size_t), &sz, NULL) != CL_SUCCESS) { - printf ("Something wrong.\n"); - assert(0); - } else { - printf ("size = %d\n", sz); - } - char* hp; // = (char*) malloc(sz); - //posix_memalign((void**)&hp, 64, sz); - hp = (char*)malloc(sz); - - clEnqueueReadBuffer (command_queue, - memobj, - CL_TRUE, - 0, - sz, - hp, - 0, - NULL, - NULL); - - if (ty == T_FLOAT) pb_sig_float(s, (float*)hp, sz/sizeof(float)); - if (ty == T_DOUBLE) pb_sig_double(s, (double*)hp, sz/sizeof(double)); - if (ty == T_INT) pb_sig_int(s, (int*)hp, sz/sizeof(int)); - if (ty == T_SHORT) pb_sig_short(s, (short*)hp, sz/sizeof(short)); - if (ty == T_UCHAR) pb_sig_uchar(s, (unsigned char*)hp, sz/sizeof(char)); - - free(hp); -} - diff --git a/tests/opencl/cutcp/readatom.c b/tests/opencl/cutcp/readatom.c deleted file mode 100644 index 8fc89ff3..00000000 --- a/tests/opencl/cutcp/readatom.c +++ /dev/null @@ -1,139 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2008-2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#include -#include -#include -#include -#include "atom.h" - - -#define LINELEN 96 -#define INITLEN 20 - - -Atoms *read_atom_file(const char *fname) -{ - FILE *file; - char line[LINELEN]; - - Atom *atom; /* Atom array */ - int len = INITLEN; /* Size of atom array */ - int cnt = 0; /* Number of atoms read */ - - /* allocate initial atom array */ - atom = (Atom *) malloc(len * sizeof(Atom)); - if (NULL==atom) { - fprintf(stderr, "can't allocate memory\n"); - return NULL; - } - - int i; - for (i = 0; i < len; ++i) { - atom[i].x = i+0; - atom[i].y = i+1; - atom[i].z = i+2; - atom[i].q = 1; - } - -#if 0 - /* open atom "pqr" file */ - file = fopen(fname, "r"); - if (NULL==file) { - fprintf(stderr, "can't open file \"%s\" for reading\n", fname); - return NULL; - } - - /* loop to read pqr file line by line */ - while (fgets(line, LINELEN, file) != NULL) { - - if (strncmp(line, "ATOM ", 6) != 0 && strncmp(line, "HETATM", 6) != 0) { - continue; /* skip anything that isn't an atom record */ - } - - if (cnt==len) { /* extend atom array */ - void *tmp = realloc(atom, 2*len*sizeof(Atom)); - if (NULL==tmp) { - fprintf(stderr, "can't allocate more memory\n"); - return NULL; - } - atom = (Atom *) tmp; - len *= 2; - } - - /* read position coordinates and charge from atom record */ - if (sscanf(line, "%*s %*d %*s %*s %*d %f %f %f %f", &(atom[cnt].x), - &(atom[cnt].y), &(atom[cnt].z), &(atom[cnt].q)) != 4) { - fprintf(stderr, "atom record %d does not have expected format\n", cnt+1); - return NULL; - } - - cnt++; /* count atoms as we store them */ - } - - /* verify EOF and close file */ - if ( !feof(file) ) { - fprintf(stderr, "did not find EOF\n"); - return NULL; - } - if (fclose(file)) { - fprintf(stderr, "can't close file\n"); - return NULL; - } -#endif - - /* Build the output data structure */ - { - Atoms *out = (Atoms *)malloc(sizeof(Atoms)); - - if (NULL == out) { - fprintf(stderr, "can't allocate memory\n"); - return NULL; - } - - out->size = cnt; - out->atoms = atom; - - return out; - } -} - - -void free_atom(Atoms *atom) -{ - if (atom) { - free(atom->atoms); - free(atom); - } -} - -void -get_atom_extent(Vec3 *out_lo, Vec3 *out_hi, Atoms *atom) -{ - Atom *atoms = atom->atoms; - int natoms = atom->size; - Vec3 lo; - Vec3 hi; - int n; - - hi.x = lo.x = atoms[0].x; - hi.y = lo.y = atoms[0].y; - hi.z = lo.z = atoms[0].z; - - for (n = 1; n < natoms; n++) { - lo.x = fminf(lo.x, atoms[n].x); - hi.x = fmaxf(hi.x, atoms[n].x); - lo.y = fminf(lo.y, atoms[n].y); - hi.y = fmaxf(hi.y, atoms[n].y); - lo.z = fminf(lo.z, atoms[n].z); - hi.z = fmaxf(hi.z, atoms[n].z); - } - - *out_lo = lo; - *out_hi = hi; -} diff --git a/tests/opencl/cutcp/watbox.sl40.pqr b/tests/opencl/cutcp/watbox.sl40.pqr deleted file mode 100755 index 917c3faa..00000000 --- a/tests/opencl/cutcp/watbox.sl40.pqr +++ /dev/null @@ -1,5945 +0,0 @@ -CRYST1 0.000 0.000 0.000 90.00 90.00 90.00 P 1 1 -ATOM 1 OH2 TIP3 5 -16.332 -9.918 -4.096 -0.834 1.520 -ATOM 2 H1 TIP3 5 -16.776 -9.549 -4.899 0.417 1.000 -ATOM 3 H2 TIP3 5 -16.908 -9.621 -3.373 0.417 1.000 -ATOM 4 OH2 TIP3 7 -13.967 -15.124 0.891 -0.834 1.520 -ATOM 5 H1 TIP3 7 -13.922 -14.776 1.798 0.417 1.000 -ATOM 6 H2 TIP3 7 -13.408 -15.912 0.961 0.417 1.000 -ATOM 7 OH2 TIP3 8 -15.431 -16.040 9.887 -0.834 1.520 -ATOM 8 H1 TIP3 8 -16.041 -16.840 9.980 0.417 1.000 -ATOM 9 H2 TIP3 8 -16.005 -15.345 9.422 0.417 1.000 -ATOM 10 OH2 TIP3 15 -19.025 -5.993 18.567 -0.834 1.520 -ATOM 11 H1 TIP3 15 -18.863 -6.737 17.966 0.417 1.000 -ATOM 12 H2 TIP3 15 -19.381 -6.461 19.360 0.417 1.000 -ATOM 13 OH2 TIP3 21 -14.814 -3.304 -7.928 -0.834 1.520 -ATOM 14 H1 TIP3 21 -13.917 -3.021 -8.184 0.417 1.000 -ATOM 15 H2 TIP3 21 -14.663 -4.168 -7.510 0.417 1.000 -ATOM 16 OH2 TIP3 26 -5.563 -14.206 10.556 -0.834 1.520 -ATOM 17 H1 TIP3 26 -6.476 -14.681 10.532 0.417 1.000 -ATOM 18 H2 TIP3 26 -5.016 -14.887 10.973 0.417 1.000 -ATOM 19 OH2 TIP3 29 -11.676 -6.189 1.332 -0.834 1.520 -ATOM 20 H1 TIP3 29 -11.367 -6.652 2.112 0.417 1.000 -ATOM 21 H2 TIP3 29 -11.494 -6.884 0.645 0.417 1.000 -ATOM 22 OH2 TIP3 30 -8.538 6.026 11.373 -0.834 1.520 -ATOM 23 H1 TIP3 30 -8.614 6.695 12.076 0.417 1.000 -ATOM 24 H2 TIP3 30 -9.381 6.080 10.936 0.417 1.000 -ATOM 25 OH2 TIP3 44 -16.214 -3.682 -18.690 -0.834 1.520 -ATOM 26 H1 TIP3 44 -16.219 -4.612 -18.804 0.417 1.000 -ATOM 27 H2 TIP3 44 -15.472 -3.420 -19.219 0.417 1.000 -ATOM 28 OH2 TIP3 46 -13.795 -13.009 -1.558 -0.834 1.520 -ATOM 29 H1 TIP3 46 -13.218 -12.653 -0.848 0.417 1.000 -ATOM 30 H2 TIP3 46 -14.691 -12.938 -1.200 0.417 1.000 -ATOM 31 OH2 TIP3 47 -3.874 -5.299 -15.423 -0.834 1.520 -ATOM 32 H1 TIP3 47 -3.930 -5.728 -16.274 0.417 1.000 -ATOM 33 H2 TIP3 47 -3.195 -4.546 -15.555 0.417 1.000 -ATOM 34 OH2 TIP3 48 -17.250 -11.156 -10.371 -0.834 1.520 -ATOM 35 H1 TIP3 48 -17.890 -11.710 -10.002 0.417 1.000 -ATOM 36 H2 TIP3 48 -17.836 -10.755 -11.038 0.417 1.000 -ATOM 37 OH2 TIP3 52 -16.065 -3.805 2.109 -0.834 1.520 -ATOM 38 H1 TIP3 52 -15.130 -3.966 1.985 0.417 1.000 -ATOM 39 H2 TIP3 52 -16.345 -4.633 2.581 0.417 1.000 -ATOM 40 OH2 TIP3 53 -17.009 -8.838 7.860 -0.834 1.520 -ATOM 41 H1 TIP3 53 -16.406 -9.032 7.129 0.417 1.000 -ATOM 42 H2 TIP3 53 -17.586 -8.225 7.430 0.417 1.000 -ATOM 43 OH2 TIP3 55 -15.760 -12.963 7.081 -0.834 1.520 -ATOM 44 H1 TIP3 55 -15.344 -12.169 6.658 0.417 1.000 -ATOM 45 H2 TIP3 55 -16.214 -12.572 7.812 0.417 1.000 -ATOM 46 OH2 TIP3 56 -12.828 -13.001 18.581 -0.834 1.520 -ATOM 47 H1 TIP3 56 -12.960 -12.450 19.327 0.417 1.000 -ATOM 48 H2 TIP3 56 -13.756 -13.244 18.263 0.417 1.000 -ATOM 49 OH2 TIP3 64 -9.326 -11.091 -15.014 -0.834 1.520 -ATOM 50 H1 TIP3 64 -9.002 -11.129 -14.068 0.417 1.000 -ATOM 51 H2 TIP3 64 -10.252 -10.730 -14.925 0.417 1.000 -ATOM 52 OH2 TIP3 67 -19.998 -14.333 -5.409 -0.834 1.520 -ATOM 53 H1 TIP3 67 -19.517 -14.010 -6.170 0.417 1.000 -ATOM 54 H2 TIP3 67 -19.392 -14.219 -4.653 0.417 1.000 -ATOM 55 OH2 TIP3 68 -10.118 -10.844 -5.084 -0.834 1.520 -ATOM 56 H1 TIP3 68 -10.426 -10.247 -4.403 0.417 1.000 -ATOM 57 H2 TIP3 68 -9.979 -11.736 -4.711 0.417 1.000 -ATOM 58 OH2 TIP3 71 -12.036 -13.893 9.453 -0.834 1.520 -ATOM 59 H1 TIP3 71 -11.758 -14.794 9.599 0.417 1.000 -ATOM 60 H2 TIP3 71 -11.578 -13.455 10.237 0.417 1.000 -ATOM 61 OH2 TIP3 75 4.177 -5.729 18.126 -0.834 1.520 -ATOM 62 H1 TIP3 75 3.534 -6.058 17.459 0.417 1.000 -ATOM 63 H2 TIP3 75 5.062 -5.918 17.682 0.417 1.000 -ATOM 64 OH2 TIP3 76 -13.684 -14.712 7.495 -0.834 1.520 -ATOM 65 H1 TIP3 76 -13.360 -14.369 8.363 0.417 1.000 -ATOM 66 H2 TIP3 76 -14.437 -14.148 7.280 0.417 1.000 -ATOM 67 OH2 TIP3 86 -7.111 9.660 -10.913 -0.834 1.520 -ATOM 68 H1 TIP3 86 -7.422 9.796 -10.025 0.417 1.000 -ATOM 69 H2 TIP3 86 -6.236 9.337 -10.788 0.417 1.000 -ATOM 70 OH2 TIP3 87 -18.339 -13.319 -18.057 -0.834 1.520 -ATOM 71 H1 TIP3 87 -18.057 -14.261 -18.019 0.417 1.000 -ATOM 72 H2 TIP3 87 -19.222 -13.401 -18.517 0.417 1.000 -ATOM 73 OH2 TIP3 88 -15.179 0.603 -8.761 -0.834 1.520 -ATOM 74 H1 TIP3 88 -14.534 0.782 -8.037 0.417 1.000 -ATOM 75 H2 TIP3 88 -14.616 0.914 -9.544 0.417 1.000 -ATOM 76 OH2 TIP3 90 -4.978 0.855 -7.169 -0.834 1.520 -ATOM 77 H1 TIP3 90 -5.778 0.809 -6.708 0.417 1.000 -ATOM 78 H2 TIP3 90 -5.327 1.057 -8.082 0.417 1.000 -ATOM 79 OH2 TIP3 94 -18.661 -16.218 2.814 -0.834 1.520 -ATOM 80 H1 TIP3 94 -19.161 -16.575 2.087 0.417 1.000 -ATOM 81 H2 TIP3 94 -18.225 -16.923 3.138 0.417 1.000 -ATOM 82 OH2 TIP3 95 -19.515 -4.863 2.476 -0.834 1.520 -ATOM 83 H1 TIP3 95 -19.356 -4.575 3.349 0.417 1.000 -ATOM 84 H2 TIP3 95 -19.688 -4.039 1.975 0.417 1.000 -ATOM 85 OH2 TIP3 97 -6.857 -6.205 13.479 -0.834 1.520 -ATOM 86 H1 TIP3 97 -7.069 -6.447 14.356 0.417 1.000 -ATOM 87 H2 TIP3 97 -6.477 -5.338 13.519 0.417 1.000 -ATOM 88 OH2 TIP3 98 -7.579 0.595 11.343 -0.834 1.520 -ATOM 89 H1 TIP3 98 -7.670 0.621 12.303 0.417 1.000 -ATOM 90 H2 TIP3 98 -7.719 1.526 11.063 0.417 1.000 -ATOM 91 OH2 TIP3 108 -14.392 3.918 -7.041 -0.834 1.520 -ATOM 92 H1 TIP3 108 -15.160 3.622 -7.455 0.417 1.000 -ATOM 93 H2 TIP3 108 -13.963 4.336 -7.792 0.417 1.000 -ATOM 94 OH2 TIP3 111 -9.574 -12.396 -17.596 -0.834 1.520 -ATOM 95 H1 TIP3 111 -9.239 -11.599 -18.006 0.417 1.000 -ATOM 96 H2 TIP3 111 -9.752 -12.111 -16.692 0.417 1.000 -ATOM 97 OH2 TIP3 112 -11.431 5.684 -7.789 -0.834 1.520 -ATOM 98 H1 TIP3 112 -10.877 5.542 -6.985 0.417 1.000 -ATOM 99 H2 TIP3 112 -11.195 6.595 -8.073 0.417 1.000 -ATOM 100 OH2 TIP3 113 -15.731 2.752 -3.735 -0.834 1.520 -ATOM 101 H1 TIP3 113 -15.851 3.680 -4.112 0.417 1.000 -ATOM 102 H2 TIP3 113 -14.939 2.796 -3.224 0.417 1.000 -ATOM 103 OH2 TIP3 115 -16.401 -6.311 3.583 -0.834 1.520 -ATOM 104 H1 TIP3 115 -16.570 -7.124 4.062 0.417 1.000 -ATOM 105 H2 TIP3 115 -15.439 -6.231 3.661 0.417 1.000 -ATOM 106 OH2 TIP3 116 -0.048 -18.039 6.164 -0.834 1.520 -ATOM 107 H1 TIP3 116 0.414 -18.921 6.079 0.417 1.000 -ATOM 108 H2 TIP3 116 0.667 -17.347 6.013 0.417 1.000 -ATOM 109 OH2 TIP3 125 2.572 -13.758 -16.522 -0.834 1.520 -ATOM 110 H1 TIP3 125 1.705 -14.155 -16.170 0.417 1.000 -ATOM 111 H2 TIP3 125 2.951 -14.341 -17.142 0.417 1.000 -ATOM 112 OH2 TIP3 129 -12.218 8.346 0.641 -0.834 1.520 -ATOM 113 H1 TIP3 129 -11.345 8.234 1.114 0.417 1.000 -ATOM 114 H2 TIP3 129 -12.331 9.295 0.444 0.417 1.000 -ATOM 115 OH2 TIP3 130 -9.074 -14.635 -18.982 -0.834 1.520 -ATOM 116 H1 TIP3 130 -8.862 -15.231 -18.246 0.417 1.000 -ATOM 117 H2 TIP3 130 -9.343 -13.788 -18.507 0.417 1.000 -ATOM 118 OH2 TIP3 131 18.680 4.645 5.756 -0.834 1.520 -ATOM 119 H1 TIP3 131 18.621 5.384 5.135 0.417 1.000 -ATOM 120 H2 TIP3 131 19.060 4.974 6.580 0.417 1.000 -ATOM 121 OH2 TIP3 133 -11.353 -15.686 -0.722 -0.834 1.520 -ATOM 122 H1 TIP3 133 -12.036 -16.389 -0.674 0.417 1.000 -ATOM 123 H2 TIP3 133 -11.957 -14.936 -0.847 0.417 1.000 -ATOM 124 OH2 TIP3 134 -11.619 -2.681 3.275 -0.834 1.520 -ATOM 125 H1 TIP3 134 -12.484 -2.660 3.695 0.417 1.000 -ATOM 126 H2 TIP3 134 -11.569 -1.737 3.009 0.417 1.000 -ATOM 127 OH2 TIP3 135 -15.658 -8.612 5.271 -0.834 1.520 -ATOM 128 H1 TIP3 135 -15.158 -9.303 5.678 0.417 1.000 -ATOM 129 H2 TIP3 135 -15.097 -7.852 5.578 0.417 1.000 -ATOM 130 OH2 TIP3 137 -18.330 -4.325 9.166 -0.834 1.520 -ATOM 131 H1 TIP3 137 -17.880 -4.050 9.974 0.417 1.000 -ATOM 132 H2 TIP3 137 -19.237 -4.483 9.468 0.417 1.000 -ATOM 133 OH2 TIP3 145 -3.530 8.089 -17.819 -0.834 1.520 -ATOM 134 H1 TIP3 145 -3.146 7.230 -17.501 0.417 1.000 -ATOM 135 H2 TIP3 145 -4.467 7.856 -17.912 0.417 1.000 -ATOM 136 OH2 TIP3 146 -11.624 12.914 -11.264 -0.834 1.520 -ATOM 137 H1 TIP3 146 -10.900 12.283 -11.266 0.417 1.000 -ATOM 138 H2 TIP3 146 -11.193 13.795 -11.432 0.417 1.000 -ATOM 139 OH2 TIP3 149 -19.198 5.084 -14.477 -0.834 1.520 -ATOM 140 H1 TIP3 149 -19.421 6.065 -14.495 0.417 1.000 -ATOM 141 H2 TIP3 149 -18.205 5.163 -14.555 0.417 1.000 -ATOM 142 OH2 TIP3 150 -15.701 -2.226 -12.831 -0.834 1.520 -ATOM 143 H1 TIP3 150 -16.697 -2.197 -12.678 0.417 1.000 -ATOM 144 H2 TIP3 150 -15.467 -1.245 -13.076 0.417 1.000 -ATOM 145 OH2 TIP3 152 -11.108 -7.023 -14.679 -0.834 1.520 -ATOM 146 H1 TIP3 152 -11.881 -7.522 -14.557 0.417 1.000 -ATOM 147 H2 TIP3 152 -10.658 -7.443 -15.464 0.417 1.000 -ATOM 148 OH2 TIP3 153 -17.292 0.969 4.504 -0.834 1.520 -ATOM 149 H1 TIP3 153 -17.411 0.945 3.556 0.417 1.000 -ATOM 150 H2 TIP3 153 -16.877 1.835 4.549 0.417 1.000 -ATOM 151 OH2 TIP3 155 -17.572 -7.269 10.487 -0.834 1.520 -ATOM 152 H1 TIP3 155 -17.281 -7.927 9.830 0.417 1.000 -ATOM 153 H2 TIP3 155 -17.418 -6.458 10.008 0.417 1.000 -ATOM 154 OH2 TIP3 156 -8.719 11.586 4.226 -0.834 1.520 -ATOM 155 H1 TIP3 156 -8.853 10.638 4.048 0.417 1.000 -ATOM 156 H2 TIP3 156 -7.869 11.561 4.702 0.417 1.000 -ATOM 157 OH2 TIP3 167 -17.826 -1.532 -17.788 -0.834 1.520 -ATOM 158 H1 TIP3 167 -17.368 -2.372 -17.797 0.417 1.000 -ATOM 159 H2 TIP3 167 -17.069 -0.880 -17.719 0.417 1.000 -ATOM 160 OH2 TIP3 177 -14.952 -10.954 16.578 -0.834 1.520 -ATOM 161 H1 TIP3 177 -14.936 -10.111 17.059 0.417 1.000 -ATOM 162 H2 TIP3 177 -15.378 -10.776 15.743 0.417 1.000 -ATOM 163 OH2 TIP3 178 -15.182 16.858 -2.213 -0.834 1.520 -ATOM 164 H1 TIP3 178 -15.854 16.220 -2.533 0.417 1.000 -ATOM 165 H2 TIP3 178 -15.016 16.600 -1.315 0.417 1.000 -ATOM 166 OH2 TIP3 179 -10.414 15.305 16.263 -0.834 1.520 -ATOM 167 H1 TIP3 179 -10.047 15.826 17.009 0.417 1.000 -ATOM 168 H2 TIP3 179 -9.737 15.511 15.531 0.417 1.000 -ATOM 169 OH2 TIP3 180 -7.610 7.307 17.360 -0.834 1.520 -ATOM 170 H1 TIP3 180 -8.155 8.113 17.293 0.417 1.000 -ATOM 171 H2 TIP3 180 -7.955 6.920 18.175 0.417 1.000 -ATOM 172 OH2 TIP3 191 -18.669 16.142 -17.299 -0.834 1.520 -ATOM 173 H1 TIP3 191 -19.635 16.131 -17.037 0.417 1.000 -ATOM 174 H2 TIP3 191 -18.328 15.284 -16.967 0.417 1.000 -ATOM 175 OH2 TIP3 195 -17.084 11.913 -11.022 -0.834 1.520 -ATOM 176 H1 TIP3 195 -16.227 12.387 -10.984 0.417 1.000 -ATOM 177 H2 TIP3 195 -17.775 12.579 -10.972 0.417 1.000 -ATOM 178 OH2 TIP3 197 -1.130 1.460 8.971 -0.834 1.520 -ATOM 179 H1 TIP3 197 -2.097 1.288 8.721 0.417 1.000 -ATOM 180 H2 TIP3 197 -0.926 0.691 9.591 0.417 1.000 -ATOM 181 OH2 TIP3 198 -13.921 13.356 5.597 -0.834 1.520 -ATOM 182 H1 TIP3 198 -13.517 13.937 6.265 0.417 1.000 -ATOM 183 H2 TIP3 198 -14.818 13.791 5.496 0.417 1.000 -ATOM 184 OH2 TIP3 201 -16.478 9.694 7.275 -0.834 1.520 -ATOM 185 H1 TIP3 201 -17.021 9.239 8.035 0.417 1.000 -ATOM 186 H2 TIP3 201 -17.110 10.250 6.887 0.417 1.000 -ATOM 187 OH2 TIP3 202 -4.656 14.738 12.731 -0.834 1.520 -ATOM 188 H1 TIP3 202 -4.474 15.545 13.160 0.417 1.000 -ATOM 189 H2 TIP3 202 -5.087 15.025 11.884 0.417 1.000 -ATOM 190 OH2 TIP3 212 -10.936 10.446 -2.304 -0.834 1.520 -ATOM 191 H1 TIP3 212 -10.104 10.192 -1.919 0.417 1.000 -ATOM 192 H2 TIP3 212 -11.502 10.631 -1.509 0.417 1.000 -ATOM 193 OH2 TIP3 218 -1.580 12.007 2.329 -0.834 1.520 -ATOM 194 H1 TIP3 218 -2.087 11.810 3.089 0.417 1.000 -ATOM 195 H2 TIP3 218 -0.655 12.190 2.662 0.417 1.000 -ATOM 196 OH2 TIP3 222 -5.630 16.170 16.010 -0.834 1.520 -ATOM 197 H1 TIP3 222 -5.210 16.753 15.304 0.417 1.000 -ATOM 198 H2 TIP3 222 -4.931 15.483 16.044 0.417 1.000 -ATOM 199 OH2 TIP3 237 -19.435 9.252 -18.417 -0.834 1.520 -ATOM 200 H1 TIP3 237 -18.537 9.562 -18.264 0.417 1.000 -ATOM 201 H2 TIP3 237 -19.414 8.335 -18.212 0.417 1.000 -ATOM 202 OH2 TIP3 238 -6.261 13.516 17.538 -0.834 1.520 -ATOM 203 H1 TIP3 238 -6.658 13.364 16.663 0.417 1.000 -ATOM 204 H2 TIP3 238 -6.871 12.963 18.063 0.417 1.000 -ATOM 205 OH2 TIP3 239 -6.388 -2.320 -1.378 -0.834 1.520 -ATOM 206 H1 TIP3 239 -6.256 -2.586 -0.492 0.417 1.000 -ATOM 207 H2 TIP3 239 -5.474 -2.169 -1.653 0.417 1.000 -ATOM 208 OH2 TIP3 252 -10.142 18.394 -14.444 -0.834 1.520 -ATOM 209 H1 TIP3 252 -10.914 18.132 -14.008 0.417 1.000 -ATOM 210 H2 TIP3 252 -9.715 19.003 -13.917 0.417 1.000 -ATOM 211 OH2 TIP3 253 -9.918 14.674 -8.066 -0.834 1.520 -ATOM 212 H1 TIP3 253 -9.792 15.123 -7.205 0.417 1.000 -ATOM 213 H2 TIP3 253 -10.552 15.288 -8.455 0.417 1.000 -ATOM 214 OH2 TIP3 257 -14.115 15.212 -12.437 -0.834 1.520 -ATOM 215 H1 TIP3 257 -14.491 15.849 -13.109 0.417 1.000 -ATOM 216 H2 TIP3 257 -13.198 15.079 -12.688 0.417 1.000 -ATOM 217 OH2 TIP3 261 -18.713 4.132 3.737 -0.834 1.520 -ATOM 218 H1 TIP3 261 -18.765 3.924 4.731 0.417 1.000 -ATOM 219 H2 TIP3 261 -17.912 4.709 3.639 0.417 1.000 -ATOM 220 OH2 TIP3 281 -13.418 17.780 7.400 -0.834 1.520 -ATOM 221 H1 TIP3 281 -13.160 16.904 7.215 0.417 1.000 -ATOM 222 H2 TIP3 281 -12.817 18.042 8.140 0.417 1.000 -ATOM 223 OH2 TIP3 295 -11.916 12.876 -4.176 -0.834 1.520 -ATOM 224 H1 TIP3 295 -12.857 12.955 -4.219 0.417 1.000 -ATOM 225 H2 TIP3 295 -11.723 12.234 -3.503 0.417 1.000 -ATOM 226 OH2 TIP3 365 -13.635 -17.326 8.059 -0.834 1.520 -ATOM 227 H1 TIP3 365 -14.201 -16.563 7.849 0.417 1.000 -ATOM 228 H2 TIP3 365 -12.825 -16.945 8.403 0.417 1.000 -ATOM 229 OH2 TIP3 411 -10.661 -13.262 11.901 -0.834 1.520 -ATOM 230 H1 TIP3 411 -11.096 -12.764 12.634 0.417 1.000 -ATOM 231 H2 TIP3 411 -10.596 -14.162 12.222 0.417 1.000 -ATOM 232 OH2 TIP3 424 -4.586 -13.431 -17.499 -0.834 1.520 -ATOM 233 H1 TIP3 424 -3.776 -13.142 -17.872 0.417 1.000 -ATOM 234 H2 TIP3 424 -5.192 -13.300 -18.329 0.417 1.000 -ATOM 235 OH2 TIP3 432 -12.429 -16.202 14.095 -0.834 1.520 -ATOM 236 H1 TIP3 432 -13.034 -15.596 13.494 0.417 1.000 -ATOM 237 H2 TIP3 432 -12.554 -15.905 15.028 0.417 1.000 -ATOM 238 OH2 TIP3 443 -10.065 -7.124 -9.809 -0.834 1.520 -ATOM 239 H1 TIP3 443 -10.291 -7.902 -10.366 0.417 1.000 -ATOM 240 H2 TIP3 443 -10.528 -7.234 -8.982 0.417 1.000 -ATOM 241 OH2 TIP3 450 -12.940 -17.926 -0.170 -0.834 1.520 -ATOM 242 H1 TIP3 450 -12.350 -18.381 0.528 0.417 1.000 -ATOM 243 H2 TIP3 450 -13.852 -18.204 0.035 0.417 1.000 -ATOM 244 OH2 TIP3 452 -9.105 -0.675 19.064 -0.834 1.520 -ATOM 245 H1 TIP3 452 -9.633 -1.232 19.669 0.417 1.000 -ATOM 246 H2 TIP3 452 -8.214 -1.042 19.229 0.417 1.000 -ATOM 247 OH2 TIP3 465 -6.109 -18.081 -17.008 -0.834 1.520 -ATOM 248 H1 TIP3 465 -5.802 -17.319 -16.578 0.417 1.000 -ATOM 249 H2 TIP3 465 -6.788 -18.423 -16.422 0.417 1.000 -ATOM 250 OH2 TIP3 466 -11.177 -9.419 -11.173 -0.834 1.520 -ATOM 251 H1 TIP3 466 -11.817 -9.247 -11.852 0.417 1.000 -ATOM 252 H2 TIP3 466 -11.611 -9.939 -10.466 0.417 1.000 -ATOM 253 OH2 TIP3 469 -10.922 -8.033 -7.266 -0.834 1.520 -ATOM 254 H1 TIP3 469 -11.772 -8.439 -7.007 0.417 1.000 -ATOM 255 H2 TIP3 469 -10.488 -7.806 -6.440 0.417 1.000 -ATOM 256 OH2 TIP3 484 -9.718 -19.360 -17.947 -0.834 1.520 -ATOM 257 H1 TIP3 484 -9.633 -19.041 -16.984 0.417 1.000 -ATOM 258 H2 TIP3 484 -10.257 -18.677 -18.333 0.417 1.000 -ATOM 259 OH2 TIP3 485 -15.382 -11.875 -12.223 -0.834 1.520 -ATOM 260 H1 TIP3 485 -14.595 -12.081 -11.686 0.417 1.000 -ATOM 261 H2 TIP3 485 -15.998 -11.542 -11.578 0.417 1.000 -ATOM 262 OH2 TIP3 486 -16.597 -15.313 -10.185 -0.834 1.520 -ATOM 263 H1 TIP3 486 -16.891 -14.728 -10.903 0.417 1.000 -ATOM 264 H2 TIP3 486 -16.183 -16.027 -10.673 0.417 1.000 -ATOM 265 OH2 TIP3 489 -16.724 -12.535 -0.675 -0.834 1.520 -ATOM 266 H1 TIP3 489 -17.228 -13.009 -0.036 0.417 1.000 -ATOM 267 H2 TIP3 489 -16.396 -11.712 -0.247 0.417 1.000 -ATOM 268 OH2 TIP3 490 -17.109 -14.956 12.613 -0.834 1.520 -ATOM 269 H1 TIP3 490 -17.740 -15.480 13.150 0.417 1.000 -ATOM 270 H2 TIP3 490 -17.697 -14.490 12.020 0.417 1.000 -ATOM 271 OH2 TIP3 491 -18.160 -11.735 8.662 -0.834 1.520 -ATOM 272 H1 TIP3 491 -18.320 -11.956 7.747 0.417 1.000 -ATOM 273 H2 TIP3 491 -18.166 -10.789 8.733 0.417 1.000 -ATOM 274 OH2 TIP3 494 -19.263 -2.098 17.090 -0.834 1.520 -ATOM 275 H1 TIP3 494 -19.541 -1.208 17.352 0.417 1.000 -ATOM 276 H2 TIP3 494 -19.134 -2.051 16.147 0.417 1.000 -ATOM 277 OH2 TIP3 495 -10.022 -12.125 4.948 -0.834 1.520 -ATOM 278 H1 TIP3 495 -10.411 -12.374 5.845 0.417 1.000 -ATOM 279 H2 TIP3 495 -9.564 -11.344 5.187 0.417 1.000 -ATOM 280 OH2 TIP3 498 -10.073 -15.815 12.805 -0.834 1.520 -ATOM 281 H1 TIP3 498 -10.944 -16.065 13.202 0.417 1.000 -ATOM 282 H2 TIP3 498 -9.640 -16.675 12.665 0.417 1.000 -ATOM 283 OH2 TIP3 503 -16.881 -9.675 -6.842 -0.834 1.520 -ATOM 284 H1 TIP3 503 -16.402 -9.100 -7.488 0.417 1.000 -ATOM 285 H2 TIP3 503 -16.560 -10.570 -7.038 0.417 1.000 -ATOM 286 OH2 TIP3 506 -17.622 -14.194 -3.747 -0.834 1.520 -ATOM 287 H1 TIP3 506 -17.843 -13.839 -2.901 0.417 1.000 -ATOM 288 H2 TIP3 506 -16.699 -13.968 -3.874 0.417 1.000 -ATOM 289 OH2 TIP3 507 -13.618 2.271 -17.681 -0.834 1.520 -ATOM 290 H1 TIP3 507 -14.450 2.035 -18.153 0.417 1.000 -ATOM 291 H2 TIP3 507 -13.141 1.472 -17.808 0.417 1.000 -ATOM 292 OH2 TIP3 508 11.804 -7.244 -12.948 -0.834 1.520 -ATOM 293 H1 TIP3 508 11.543 -6.358 -13.269 0.417 1.000 -ATOM 294 H2 TIP3 508 12.291 -7.070 -12.133 0.417 1.000 -ATOM 295 OH2 TIP3 509 -15.983 -16.095 -0.582 -0.834 1.520 -ATOM 296 H1 TIP3 509 -16.858 -15.958 -0.868 0.417 1.000 -ATOM 297 H2 TIP3 509 -15.418 -15.273 -0.705 0.417 1.000 -ATOM 298 OH2 TIP3 511 -17.656 0.472 1.631 -0.834 1.520 -ATOM 299 H1 TIP3 511 -17.068 0.821 0.945 0.417 1.000 -ATOM 300 H2 TIP3 511 -18.533 0.548 1.138 0.417 1.000 -ATOM 301 OH2 TIP3 512 0.613 -6.384 -8.934 -0.834 1.520 -ATOM 302 H1 TIP3 512 0.739 -6.041 -9.782 0.417 1.000 -ATOM 303 H2 TIP3 512 -0.381 -6.184 -8.750 0.417 1.000 -ATOM 304 OH2 TIP3 514 -8.508 -14.452 14.846 -0.834 1.520 -ATOM 305 H1 TIP3 514 -8.837 -14.796 14.040 0.417 1.000 -ATOM 306 H2 TIP3 514 -8.614 -13.521 14.859 0.417 1.000 -ATOM 307 OH2 TIP3 515 -18.213 -10.482 4.515 -0.834 1.520 -ATOM 308 H1 TIP3 515 -17.868 -10.425 3.646 0.417 1.000 -ATOM 309 H2 TIP3 515 -18.140 -9.594 4.787 0.417 1.000 -ATOM 310 OH2 TIP3 516 -15.873 -18.130 12.761 -0.834 1.520 -ATOM 311 H1 TIP3 516 -16.170 -17.728 11.989 0.417 1.000 -ATOM 312 H2 TIP3 516 -15.270 -17.438 13.098 0.417 1.000 -ATOM 313 OH2 TIP3 517 -5.474 -9.468 0.137 -0.834 1.520 -ATOM 314 H1 TIP3 517 -5.838 -10.267 0.503 0.417 1.000 -ATOM 315 H2 TIP3 517 -5.534 -9.580 -0.806 0.417 1.000 -ATOM 316 OH2 TIP3 528 6.124 -3.406 -3.193 -0.834 1.520 -ATOM 317 H1 TIP3 528 6.948 -3.136 -2.756 0.417 1.000 -ATOM 318 H2 TIP3 528 6.137 -2.952 -4.100 0.417 1.000 -ATOM 319 OH2 TIP3 529 -11.124 8.437 -14.421 -0.834 1.520 -ATOM 320 H1 TIP3 529 -10.773 7.577 -14.642 0.417 1.000 -ATOM 321 H2 TIP3 529 -11.210 8.398 -13.467 0.417 1.000 -ATOM 322 OH2 TIP3 533 -14.427 -5.196 -0.910 -0.834 1.520 -ATOM 323 H1 TIP3 533 -14.041 -4.661 -0.192 0.417 1.000 -ATOM 324 H2 TIP3 533 -14.131 -4.587 -1.669 0.417 1.000 -ATOM 325 OH2 TIP3 534 -3.717 -12.646 2.781 -0.834 1.520 -ATOM 326 H1 TIP3 534 -4.360 -11.942 2.449 0.417 1.000 -ATOM 327 H2 TIP3 534 -4.027 -13.440 2.379 0.417 1.000 -ATOM 328 OH2 TIP3 535 2.872 -1.559 -3.212 -0.834 1.520 -ATOM 329 H1 TIP3 535 2.201 -2.136 -3.621 0.417 1.000 -ATOM 330 H2 TIP3 535 2.335 -1.019 -2.575 0.417 1.000 -ATOM 331 OH2 TIP3 538 -9.895 -19.159 19.111 -0.834 1.520 -ATOM 332 H1 TIP3 538 -10.512 -18.550 18.631 0.417 1.000 -ATOM 333 H2 TIP3 538 -9.368 -18.582 19.705 0.417 1.000 -ATOM 334 OH2 TIP3 540 -19.258 0.647 17.424 -0.834 1.520 -ATOM 335 H1 TIP3 540 -19.837 1.202 16.855 0.417 1.000 -ATOM 336 H2 TIP3 540 -18.468 0.410 16.837 0.417 1.000 -ATOM 337 OH2 TIP3 543 -14.542 -6.903 -15.411 -0.834 1.520 -ATOM 338 H1 TIP3 543 -14.327 -6.981 -16.388 0.417 1.000 -ATOM 339 H2 TIP3 543 -15.101 -6.106 -15.343 0.417 1.000 -ATOM 340 OH2 TIP3 549 7.849 -10.132 -0.827 -0.834 1.520 -ATOM 341 H1 TIP3 549 7.170 -10.280 -0.137 0.417 1.000 -ATOM 342 H2 TIP3 549 7.403 -9.581 -1.511 0.417 1.000 -ATOM 343 OH2 TIP3 550 -15.448 -18.630 0.330 -0.834 1.520 -ATOM 344 H1 TIP3 550 -15.726 -17.806 -0.047 0.417 1.000 -ATOM 345 H2 TIP3 550 -15.765 -19.199 -0.429 0.417 1.000 -ATOM 346 OH2 TIP3 551 -15.406 5.266 -4.800 -0.834 1.520 -ATOM 347 H1 TIP3 551 -16.362 5.500 -4.804 0.417 1.000 -ATOM 348 H2 TIP3 551 -15.242 4.897 -5.688 0.417 1.000 -ATOM 349 OH2 TIP3 552 -9.034 -19.513 7.664 -0.834 1.520 -ATOM 350 H1 TIP3 552 -9.165 -18.577 7.475 0.417 1.000 -ATOM 351 H2 TIP3 552 -9.442 -19.908 6.883 0.417 1.000 -ATOM 352 OH2 TIP3 553 -13.420 -7.008 9.691 -0.834 1.520 -ATOM 353 H1 TIP3 553 -13.570 -6.114 9.972 0.417 1.000 -ATOM 354 H2 TIP3 553 -13.571 -7.501 10.481 0.417 1.000 -ATOM 355 OH2 TIP3 554 -14.840 -6.256 -12.046 -0.834 1.520 -ATOM 356 H1 TIP3 554 -13.952 -6.578 -11.793 0.417 1.000 -ATOM 357 H2 TIP3 554 -14.992 -5.507 -11.472 0.417 1.000 -ATOM 358 OH2 TIP3 555 -18.512 -12.246 11.838 -0.834 1.520 -ATOM 359 H1 TIP3 555 -19.222 -11.677 12.195 0.417 1.000 -ATOM 360 H2 TIP3 555 -18.457 -11.957 10.921 0.417 1.000 -ATOM 361 OH2 TIP3 558 -9.610 -13.614 -1.172 -0.834 1.520 -ATOM 362 H1 TIP3 558 -9.312 -13.516 -0.269 0.417 1.000 -ATOM 363 H2 TIP3 558 -10.156 -14.411 -1.079 0.417 1.000 -ATOM 364 OH2 TIP3 562 -18.322 1.942 -18.965 -0.834 1.520 -ATOM 365 H1 TIP3 562 -18.728 1.280 -18.408 0.417 1.000 -ATOM 366 H2 TIP3 562 -18.502 2.809 -18.507 0.417 1.000 -ATOM 367 OH2 TIP3 568 -10.370 1.547 -17.000 -0.834 1.520 -ATOM 368 H1 TIP3 568 -10.399 2.471 -17.357 0.417 1.000 -ATOM 369 H2 TIP3 568 -10.713 0.954 -17.688 0.417 1.000 -ATOM 370 OH2 TIP3 570 -19.245 14.044 -7.077 -0.834 1.520 -ATOM 371 H1 TIP3 570 -18.622 14.200 -6.344 0.417 1.000 -ATOM 372 H2 TIP3 570 -19.669 13.221 -6.771 0.417 1.000 -ATOM 373 OH2 TIP3 573 -15.609 9.423 1.120 -0.834 1.520 -ATOM 374 H1 TIP3 573 -16.237 8.799 1.511 0.417 1.000 -ATOM 375 H2 TIP3 573 -15.406 9.044 0.208 0.417 1.000 -ATOM 376 OH2 TIP3 575 -17.656 -9.429 -17.376 -0.834 1.520 -ATOM 377 H1 TIP3 575 -17.878 -9.247 -16.447 0.417 1.000 -ATOM 378 H2 TIP3 575 -17.053 -10.209 -17.383 0.417 1.000 -ATOM 379 OH2 TIP3 576 -17.418 7.635 2.063 -0.834 1.520 -ATOM 380 H1 TIP3 576 -18.174 7.334 2.610 0.417 1.000 -ATOM 381 H2 TIP3 576 -17.859 7.873 1.227 0.417 1.000 -ATOM 382 OH2 TIP3 578 -17.381 8.047 17.820 -0.834 1.520 -ATOM 383 H1 TIP3 578 -17.531 8.994 17.611 0.417 1.000 -ATOM 384 H2 TIP3 578 -18.029 7.756 18.500 0.417 1.000 -ATOM 385 OH2 TIP3 579 -11.877 -12.110 14.105 -0.834 1.520 -ATOM 386 H1 TIP3 579 -11.717 -12.461 15.039 0.417 1.000 -ATOM 387 H2 TIP3 579 -11.271 -11.366 14.000 0.417 1.000 -ATOM 388 OH2 TIP3 580 -6.615 -10.231 9.453 -0.834 1.520 -ATOM 389 H1 TIP3 580 -6.144 -9.609 10.062 0.417 1.000 -ATOM 390 H2 TIP3 580 -7.401 -10.487 9.965 0.417 1.000 -ATOM 391 OH2 TIP3 584 -19.177 3.668 -17.112 -0.834 1.520 -ATOM 392 H1 TIP3 584 -18.364 3.316 -16.660 0.417 1.000 -ATOM 393 H2 TIP3 584 -19.747 3.978 -16.360 0.417 1.000 -ATOM 394 OH2 TIP3 591 -17.917 8.332 -12.674 -0.834 1.520 -ATOM 395 H1 TIP3 591 -18.442 8.514 -11.885 0.417 1.000 -ATOM 396 H2 TIP3 591 -18.504 7.737 -13.189 0.417 1.000 -ATOM 397 OH2 TIP3 592 -6.780 4.494 -6.908 -0.834 1.520 -ATOM 398 H1 TIP3 592 -7.109 5.383 -6.713 0.417 1.000 -ATOM 399 H2 TIP3 592 -6.944 3.918 -6.147 0.417 1.000 -ATOM 400 OH2 TIP3 593 -19.005 8.021 -9.985 -0.834 1.520 -ATOM 401 H1 TIP3 593 -19.987 7.981 -9.957 0.417 1.000 -ATOM 402 H2 TIP3 593 -18.702 7.119 -9.737 0.417 1.000 -ATOM 403 OH2 TIP3 594 -17.290 -13.815 -12.460 -0.834 1.520 -ATOM 404 H1 TIP3 594 -17.533 -13.764 -13.439 0.417 1.000 -ATOM 405 H2 TIP3 594 -16.590 -13.145 -12.420 0.417 1.000 -ATOM 406 OH2 TIP3 595 -13.089 -0.542 -2.665 -0.834 1.520 -ATOM 407 H1 TIP3 595 -12.483 0.118 -3.043 0.417 1.000 -ATOM 408 H2 TIP3 595 -13.685 -0.864 -3.412 0.417 1.000 -ATOM 409 OH2 TIP3 598 -6.664 4.461 16.785 -0.834 1.520 -ATOM 410 H1 TIP3 598 -6.761 5.164 17.434 0.417 1.000 -ATOM 411 H2 TIP3 598 -6.307 3.713 17.244 0.417 1.000 -ATOM 412 OH2 TIP3 599 -17.166 -4.957 14.374 -0.834 1.520 -ATOM 413 H1 TIP3 599 -17.721 -5.193 15.123 0.417 1.000 -ATOM 414 H2 TIP3 599 -16.393 -5.451 14.503 0.417 1.000 -ATOM 415 OH2 TIP3 602 -14.821 0.890 7.387 -0.834 1.520 -ATOM 416 H1 TIP3 602 -15.382 1.606 7.646 0.417 1.000 -ATOM 417 H2 TIP3 602 -14.804 0.211 8.107 0.417 1.000 -ATOM 418 OH2 TIP3 611 -10.661 18.413 -1.977 -0.834 1.520 -ATOM 419 H1 TIP3 611 -10.709 17.725 -1.291 0.417 1.000 -ATOM 420 H2 TIP3 611 -9.895 18.114 -2.489 0.417 1.000 -ATOM 421 OH2 TIP3 612 -3.808 2.403 -16.218 -0.834 1.520 -ATOM 422 H1 TIP3 612 -3.637 2.881 -15.378 0.417 1.000 -ATOM 423 H2 TIP3 612 -3.573 3.065 -16.914 0.417 1.000 -ATOM 424 OH2 TIP3 613 -6.460 2.220 -17.252 -0.834 1.520 -ATOM 425 H1 TIP3 613 -7.035 2.475 -16.538 0.417 1.000 -ATOM 426 H2 TIP3 613 -5.572 2.404 -16.926 0.417 1.000 -ATOM 427 OH2 TIP3 615 -10.475 8.541 10.151 -0.834 1.520 -ATOM 428 H1 TIP3 615 -9.585 8.418 9.686 0.417 1.000 -ATOM 429 H2 TIP3 615 -10.803 7.671 10.239 0.417 1.000 -ATOM 430 OH2 TIP3 616 -16.995 13.969 -5.251 -0.834 1.520 -ATOM 431 H1 TIP3 616 -16.251 14.208 -5.841 0.417 1.000 -ATOM 432 H2 TIP3 616 -16.897 13.042 -5.075 0.417 1.000 -ATOM 433 OH2 TIP3 618 -11.611 -1.835 10.992 -0.834 1.520 -ATOM 434 H1 TIP3 618 -12.032 -2.230 10.210 0.417 1.000 -ATOM 435 H2 TIP3 618 -11.583 -2.549 11.641 0.417 1.000 -ATOM 436 OH2 TIP3 619 -14.803 17.740 0.512 -0.834 1.520 -ATOM 437 H1 TIP3 619 -14.483 18.488 0.028 0.417 1.000 -ATOM 438 H2 TIP3 619 -15.762 17.952 0.773 0.417 1.000 -ATOM 439 OH2 TIP3 624 -4.674 6.968 11.402 -0.834 1.520 -ATOM 440 H1 TIP3 624 -5.547 6.736 10.928 0.417 1.000 -ATOM 441 H2 TIP3 624 -4.932 7.620 12.033 0.417 1.000 -ATOM 442 OH2 TIP3 632 -11.819 3.465 -12.363 -0.834 1.520 -ATOM 443 H1 TIP3 632 -10.993 3.937 -12.297 0.417 1.000 -ATOM 444 H2 TIP3 632 -12.483 4.117 -12.688 0.417 1.000 -ATOM 445 OH2 TIP3 634 -9.071 -5.250 -14.282 -0.834 1.520 -ATOM 446 H1 TIP3 634 -9.950 -5.459 -14.592 0.417 1.000 -ATOM 447 H2 TIP3 634 -8.599 -6.121 -14.283 0.417 1.000 -ATOM 448 OH2 TIP3 635 -0.341 5.552 -2.551 -0.834 1.520 -ATOM 449 H1 TIP3 635 0.182 6.346 -2.501 0.417 1.000 -ATOM 450 H2 TIP3 635 -1.266 5.858 -2.619 0.417 1.000 -ATOM 451 OH2 TIP3 636 -13.016 14.157 3.048 -0.834 1.520 -ATOM 452 H1 TIP3 636 -13.782 14.085 2.457 0.417 1.000 -ATOM 453 H2 TIP3 636 -13.284 13.608 3.800 0.417 1.000 -ATOM 454 OH2 TIP3 637 -13.003 14.755 15.342 -0.834 1.520 -ATOM 455 H1 TIP3 637 -12.400 14.991 15.995 0.417 1.000 -ATOM 456 H2 TIP3 637 -13.065 13.804 15.464 0.417 1.000 -ATOM 457 OH2 TIP3 638 -17.914 5.452 -1.806 -0.834 1.520 -ATOM 458 H1 TIP3 638 -17.826 5.923 -2.606 0.417 1.000 -ATOM 459 H2 TIP3 638 -18.728 5.869 -1.396 0.417 1.000 -ATOM 460 OH2 TIP3 639 -18.317 5.667 6.332 -0.834 1.520 -ATOM 461 H1 TIP3 639 -17.420 5.907 6.426 0.417 1.000 -ATOM 462 H2 TIP3 639 -18.515 5.227 7.126 0.417 1.000 -ATOM 463 OH2 TIP3 640 3.331 1.619 -1.931 -0.834 1.520 -ATOM 464 H1 TIP3 640 3.137 2.516 -1.544 0.417 1.000 -ATOM 465 H2 TIP3 640 2.663 0.985 -1.550 0.417 1.000 -ATOM 466 OH2 TIP3 642 -18.246 14.617 14.408 -0.834 1.520 -ATOM 467 H1 TIP3 642 -18.209 14.662 15.420 0.417 1.000 -ATOM 468 H2 TIP3 642 -17.432 15.011 14.179 0.417 1.000 -ATOM 469 OH2 TIP3 643 -5.300 9.177 13.075 -0.834 1.520 -ATOM 470 H1 TIP3 643 -5.425 8.887 13.996 0.417 1.000 -ATOM 471 H2 TIP3 643 -6.231 9.183 12.748 0.417 1.000 -ATOM 472 OH2 TIP3 657 -10.914 17.628 -9.139 -0.834 1.520 -ATOM 473 H1 TIP3 657 -11.399 18.463 -9.333 0.417 1.000 -ATOM 474 H2 TIP3 657 -10.805 17.683 -8.136 0.417 1.000 -ATOM 475 OH2 TIP3 659 -3.493 -2.830 1.006 -0.834 1.520 -ATOM 476 H1 TIP3 659 -2.774 -2.994 0.295 0.417 1.000 -ATOM 477 H2 TIP3 659 -3.970 -3.703 1.082 0.417 1.000 -ATOM 478 OH2 TIP3 661 -8.069 16.535 12.386 -0.834 1.520 -ATOM 479 H1 TIP3 661 -8.561 16.173 13.148 0.417 1.000 -ATOM 480 H2 TIP3 661 -7.757 15.723 11.845 0.417 1.000 -ATOM 481 OH2 TIP3 662 -16.210 3.318 6.067 -0.834 1.520 -ATOM 482 H1 TIP3 662 -15.889 3.684 6.901 0.417 1.000 -ATOM 483 H2 TIP3 662 -17.165 3.196 6.248 0.417 1.000 -ATOM 484 OH2 TIP3 666 -18.375 10.100 16.358 -0.834 1.520 -ATOM 485 H1 TIP3 666 -18.272 10.712 15.618 0.417 1.000 -ATOM 486 H2 TIP3 666 -19.088 10.549 16.843 0.417 1.000 -ATOM 487 OH2 TIP3 674 -14.786 15.728 -18.104 -0.834 1.520 -ATOM 488 H1 TIP3 674 -14.253 15.733 -18.902 0.417 1.000 -ATOM 489 H2 TIP3 674 -15.411 16.462 -18.332 0.417 1.000 -ATOM 490 OH2 TIP3 676 1.955 12.145 -7.880 -0.834 1.520 -ATOM 491 H1 TIP3 676 2.028 12.757 -7.174 0.417 1.000 -ATOM 492 H2 TIP3 676 2.702 12.400 -8.501 0.417 1.000 -ATOM 493 OH2 TIP3 679 -12.514 9.742 11.971 -0.834 1.520 -ATOM 494 H1 TIP3 679 -11.884 9.155 11.492 0.417 1.000 -ATOM 495 H2 TIP3 679 -13.222 9.096 12.064 0.417 1.000 -ATOM 496 OH2 TIP3 682 -12.565 11.116 0.100 -0.834 1.520 -ATOM 497 H1 TIP3 682 -13.422 11.264 -0.334 0.417 1.000 -ATOM 498 H2 TIP3 682 -12.686 11.542 1.014 0.417 1.000 -ATOM 499 OH2 TIP3 684 -17.843 16.500 5.355 -0.834 1.520 -ATOM 500 H1 TIP3 684 -17.109 16.045 4.935 0.417 1.000 -ATOM 501 H2 TIP3 684 -17.597 17.436 5.199 0.417 1.000 -ATOM 502 OH2 TIP3 686 -10.854 18.558 18.491 -0.834 1.520 -ATOM 503 H1 TIP3 686 -10.109 17.964 18.496 0.417 1.000 -ATOM 504 H2 TIP3 686 -10.518 19.356 18.944 0.417 1.000 -ATOM 505 OH2 TIP3 699 -8.563 13.795 -0.051 -0.834 1.520 -ATOM 506 H1 TIP3 699 -9.108 13.629 -0.834 0.417 1.000 -ATOM 507 H2 TIP3 699 -9.124 13.721 0.759 0.417 1.000 -ATOM 508 OH2 TIP3 700 -8.050 15.322 14.900 -0.834 1.520 -ATOM 509 H1 TIP3 700 -7.928 14.397 14.787 0.417 1.000 -ATOM 510 H2 TIP3 700 -7.182 15.651 15.219 0.417 1.000 -ATOM 511 OH2 TIP3 701 -13.200 17.116 2.652 -0.834 1.520 -ATOM 512 H1 TIP3 701 -13.097 16.138 2.827 0.417 1.000 -ATOM 513 H2 TIP3 701 -13.771 17.169 1.908 0.417 1.000 -ATOM 514 OH2 TIP3 703 -1.363 15.088 5.879 -0.834 1.520 -ATOM 515 H1 TIP3 703 -1.313 15.420 4.981 0.417 1.000 -ATOM 516 H2 TIP3 703 -1.991 15.716 6.359 0.417 1.000 -ATOM 517 OH2 TIP3 707 -13.869 15.299 19.590 -0.834 1.520 -ATOM 518 H1 TIP3 707 -14.501 15.415 18.908 0.417 1.000 -ATOM 519 H2 TIP3 707 -13.638 14.387 19.519 0.417 1.000 -ATOM 520 OH2 TIP3 708 -3.990 17.713 11.203 -0.834 1.520 -ATOM 521 H1 TIP3 708 -3.036 17.525 10.948 0.417 1.000 -ATOM 522 H2 TIP3 708 -4.293 18.267 10.432 0.417 1.000 -ATOM 523 OH2 TIP3 710 -13.960 16.974 14.283 -0.834 1.520 -ATOM 524 H1 TIP3 710 -13.562 17.353 15.061 0.417 1.000 -ATOM 525 H2 TIP3 710 -13.197 16.869 13.683 0.417 1.000 -ATOM 526 OH2 TIP3 721 -16.049 12.492 0.099 -0.834 1.520 -ATOM 527 H1 TIP3 721 -16.045 11.770 -0.607 0.417 1.000 -ATOM 528 H2 TIP3 721 -16.883 12.282 0.546 0.417 1.000 -ATOM 529 OH2 TIP3 737 -13.666 12.822 10.600 -0.834 1.520 -ATOM 530 H1 TIP3 737 -12.807 12.842 11.097 0.417 1.000 -ATOM 531 H2 TIP3 737 -13.370 12.523 9.704 0.417 1.000 -ATOM 532 OH2 TIP3 738 -15.938 13.760 -14.358 -0.834 1.520 -ATOM 533 H1 TIP3 738 -16.316 14.308 -13.637 0.417 1.000 -ATOM 534 H2 TIP3 738 -16.706 13.253 -14.618 0.417 1.000 -ATOM 535 OH2 TIP3 741 -8.387 14.832 -4.054 -0.834 1.520 -ATOM 536 H1 TIP3 741 -8.331 13.875 -3.795 0.417 1.000 -ATOM 537 H2 TIP3 741 -9.152 15.107 -3.614 0.417 1.000 -ATOM 538 OH2 TIP3 747 -0.600 19.416 11.031 -0.834 1.520 -ATOM 539 H1 TIP3 747 -0.618 18.448 11.348 0.417 1.000 -ATOM 540 H2 TIP3 747 -0.105 19.358 10.220 0.417 1.000 -ATOM 541 OH2 TIP3 759 -13.397 17.068 -6.343 -0.834 1.520 -ATOM 542 H1 TIP3 759 -13.152 16.670 -5.550 0.417 1.000 -ATOM 543 H2 TIP3 759 -13.286 18.036 -6.135 0.417 1.000 -ATOM 544 OH2 TIP3 778 -18.235 19.532 -12.241 -0.834 1.520 -ATOM 545 H1 TIP3 778 -19.239 19.599 -12.280 0.417 1.000 -ATOM 546 H2 TIP3 778 -18.064 18.964 -11.458 0.417 1.000 -ATOM 547 OH2 TIP3 787 0.759 17.628 5.956 -0.834 1.520 -ATOM 548 H1 TIP3 787 0.104 17.147 5.343 0.417 1.000 -ATOM 549 H2 TIP3 787 1.278 18.219 5.409 0.417 1.000 -ATOM 550 OH2 TIP3 822 -19.253 -15.531 -9.421 -0.834 1.520 -ATOM 551 H1 TIP3 822 -19.574 -16.432 -9.661 0.417 1.000 -ATOM 552 H2 TIP3 822 -18.495 -15.415 -10.010 0.417 1.000 -ATOM 553 OH2 TIP3 849 -14.644 -14.612 -3.954 -0.834 1.520 -ATOM 554 H1 TIP3 849 -14.116 -13.936 -3.539 0.417 1.000 -ATOM 555 H2 TIP3 849 -14.408 -15.378 -3.463 0.417 1.000 -ATOM 556 OH2 TIP3 852 -18.111 -14.415 9.541 -0.834 1.520 -ATOM 557 H1 TIP3 852 -18.062 -13.498 9.263 0.417 1.000 -ATOM 558 H2 TIP3 852 -18.985 -14.688 9.145 0.417 1.000 -ATOM 559 OH2 TIP3 867 -9.296 -13.279 -4.117 -0.834 1.520 -ATOM 560 H1 TIP3 867 -9.099 -13.088 -3.164 0.417 1.000 -ATOM 561 H2 TIP3 867 -9.873 -14.028 -4.002 0.417 1.000 -ATOM 562 OH2 TIP3 887 6.897 -7.906 -19.321 -0.834 1.520 -ATOM 563 H1 TIP3 887 6.514 -8.720 -19.696 0.417 1.000 -ATOM 564 H2 TIP3 887 7.875 -8.073 -19.447 0.417 1.000 -ATOM 565 OH2 TIP3 889 -17.811 -18.294 4.878 -0.834 1.520 -ATOM 566 H1 TIP3 889 -18.536 -18.909 4.710 0.417 1.000 -ATOM 567 H2 TIP3 889 -17.875 -18.195 5.900 0.417 1.000 -ATOM 568 OH2 TIP3 891 -8.237 -0.386 -10.042 -0.834 1.520 -ATOM 569 H1 TIP3 891 -7.721 0.405 -10.134 0.417 1.000 -ATOM 570 H2 TIP3 891 -7.565 -1.095 -10.099 0.417 1.000 -ATOM 571 OH2 TIP3 894 -12.136 -9.397 8.950 -0.834 1.520 -ATOM 572 H1 TIP3 894 -12.531 -8.725 9.507 0.417 1.000 -ATOM 573 H2 TIP3 894 -12.846 -10.008 8.783 0.417 1.000 -ATOM 574 OH2 TIP3 895 -15.353 -13.368 17.534 -0.834 1.520 -ATOM 575 H1 TIP3 895 -16.158 -13.824 17.198 0.417 1.000 -ATOM 576 H2 TIP3 895 -15.370 -12.514 17.090 0.417 1.000 -ATOM 577 OH2 TIP3 897 -9.107 -11.584 10.315 -0.834 1.520 -ATOM 578 H1 TIP3 897 -9.261 -12.213 9.538 0.417 1.000 -ATOM 579 H2 TIP3 897 -9.639 -12.029 10.974 0.417 1.000 -ATOM 580 OH2 TIP3 906 -12.973 -17.776 -6.589 -0.834 1.520 -ATOM 581 H1 TIP3 906 -13.815 -17.199 -6.465 0.417 1.000 -ATOM 582 H2 TIP3 906 -13.308 -18.597 -6.258 0.417 1.000 -ATOM 583 OH2 TIP3 907 -2.188 -14.229 -14.124 -0.834 1.520 -ATOM 584 H1 TIP3 907 -2.780 -13.684 -14.620 0.417 1.000 -ATOM 585 H2 TIP3 907 -2.449 -15.131 -14.331 0.417 1.000 -ATOM 586 OH2 TIP3 908 -15.972 -12.301 -7.224 -0.834 1.520 -ATOM 587 H1 TIP3 908 -15.423 -12.807 -7.862 0.417 1.000 -ATOM 588 H2 TIP3 908 -16.829 -12.680 -7.456 0.417 1.000 -ATOM 589 OH2 TIP3 911 -8.951 -10.120 6.882 -0.834 1.520 -ATOM 590 H1 TIP3 911 -8.605 -10.519 7.655 0.417 1.000 -ATOM 591 H2 TIP3 911 -8.095 -9.905 6.383 0.417 1.000 -ATOM 592 OH2 TIP3 912 2.133 -17.114 -0.157 -0.834 1.520 -ATOM 593 H1 TIP3 912 2.929 -17.404 0.262 0.417 1.000 -ATOM 594 H2 TIP3 912 1.486 -17.172 0.561 0.417 1.000 -ATOM 595 OH2 TIP3 916 0.975 -12.700 10.576 -0.834 1.520 -ATOM 596 H1 TIP3 916 1.781 -13.270 10.419 0.417 1.000 -ATOM 597 H2 TIP3 916 1.289 -12.181 11.305 0.417 1.000 -ATOM 598 OH2 TIP3 924 -7.507 -10.549 -17.785 -0.834 1.520 -ATOM 599 H1 TIP3 924 -7.092 -10.160 -17.013 0.417 1.000 -ATOM 600 H2 TIP3 924 -7.018 -11.359 -17.961 0.417 1.000 -ATOM 601 OH2 TIP3 927 -8.823 -10.390 -12.072 -0.834 1.520 -ATOM 602 H1 TIP3 927 -9.557 -9.828 -11.947 0.417 1.000 -ATOM 603 H2 TIP3 927 -9.134 -11.212 -11.702 0.417 1.000 -ATOM 604 OH2 TIP3 928 -18.162 -16.794 -4.602 -0.834 1.520 -ATOM 605 H1 TIP3 928 -17.799 -15.919 -4.455 0.417 1.000 -ATOM 606 H2 TIP3 928 -17.883 -17.001 -5.578 0.417 1.000 -ATOM 607 OH2 TIP3 929 -3.867 -7.407 -3.092 -0.834 1.520 -ATOM 608 H1 TIP3 929 -4.648 -7.231 -3.609 0.417 1.000 -ATOM 609 H2 TIP3 929 -4.113 -8.124 -2.489 0.417 1.000 -ATOM 610 OH2 TIP3 930 -18.101 -8.376 -2.107 -0.834 1.520 -ATOM 611 H1 TIP3 930 -18.861 -8.322 -2.695 0.417 1.000 -ATOM 612 H2 TIP3 930 -17.742 -7.465 -2.145 0.417 1.000 -ATOM 613 OH2 TIP3 932 -10.780 -6.096 -2.660 -0.834 1.520 -ATOM 614 H1 TIP3 932 -9.938 -5.802 -2.262 0.417 1.000 -ATOM 615 H2 TIP3 932 -10.606 -7.001 -2.898 0.417 1.000 -ATOM 616 OH2 TIP3 933 -16.542 -10.132 2.419 -0.834 1.520 -ATOM 617 H1 TIP3 933 -15.602 -9.984 2.654 0.417 1.000 -ATOM 618 H2 TIP3 933 -16.552 -9.811 1.495 0.417 1.000 -ATOM 619 OH2 TIP3 936 -17.076 -15.857 6.959 -0.834 1.520 -ATOM 620 H1 TIP3 936 -16.442 -15.454 6.376 0.417 1.000 -ATOM 621 H2 TIP3 936 -17.335 -15.170 7.592 0.417 1.000 -ATOM 622 OH2 TIP3 940 -19.250 -17.062 13.461 -0.834 1.520 -ATOM 623 H1 TIP3 940 -19.256 -17.491 14.315 0.417 1.000 -ATOM 624 H2 TIP3 940 -19.609 -16.191 13.743 0.417 1.000 -ATOM 625 OH2 TIP3 941 -9.333 -7.566 15.503 -0.834 1.520 -ATOM 626 H1 TIP3 941 -10.126 -7.052 15.227 0.417 1.000 -ATOM 627 H2 TIP3 941 -9.061 -7.055 16.214 0.417 1.000 -ATOM 628 OH2 TIP3 942 -1.559 -3.866 -16.160 -0.834 1.520 -ATOM 629 H1 TIP3 942 -1.390 -3.512 -17.032 0.417 1.000 -ATOM 630 H2 TIP3 942 -0.887 -4.593 -16.039 0.417 1.000 -ATOM 631 OH2 TIP3 947 -4.570 -16.726 -12.593 -0.834 1.520 -ATOM 632 H1 TIP3 947 -4.542 -17.259 -11.843 0.417 1.000 -ATOM 633 H2 TIP3 947 -4.067 -17.260 -13.230 0.417 1.000 -ATOM 634 OH2 TIP3 948 -6.866 -15.465 -13.441 -0.834 1.520 -ATOM 635 H1 TIP3 948 -7.566 -16.068 -13.062 0.417 1.000 -ATOM 636 H2 TIP3 948 -6.041 -15.838 -13.035 0.417 1.000 -ATOM 637 OH2 TIP3 949 -14.292 -15.574 4.418 -0.834 1.520 -ATOM 638 H1 TIP3 949 -13.998 -15.297 5.300 0.417 1.000 -ATOM 639 H2 TIP3 949 -14.843 -14.832 4.144 0.417 1.000 -ATOM 640 OH2 TIP3 950 -3.679 -0.505 -4.130 -0.834 1.520 -ATOM 641 H1 TIP3 950 -3.040 -0.841 -4.808 0.417 1.000 -ATOM 642 H2 TIP3 950 -3.146 0.132 -3.612 0.417 1.000 -ATOM 643 OH2 TIP3 951 -9.705 -5.934 -5.680 -0.834 1.520 -ATOM 644 H1 TIP3 951 -9.408 -5.933 -4.774 0.417 1.000 -ATOM 645 H2 TIP3 951 -10.678 -5.774 -5.650 0.417 1.000 -ATOM 646 OH2 TIP3 952 -3.992 -2.203 -8.590 -0.834 1.520 -ATOM 647 H1 TIP3 952 -3.305 -2.298 -9.316 0.417 1.000 -ATOM 648 H2 TIP3 952 -4.814 -2.479 -9.058 0.417 1.000 -ATOM 649 OH2 TIP3 953 -4.602 -18.448 -1.754 -0.834 1.520 -ATOM 650 H1 TIP3 953 -3.984 -18.049 -2.434 0.417 1.000 -ATOM 651 H2 TIP3 953 -5.426 -17.989 -1.891 0.417 1.000 -ATOM 652 OH2 TIP3 964 -12.170 -0.249 -18.005 -0.834 1.520 -ATOM 653 H1 TIP3 964 -12.743 -0.130 -18.753 0.417 1.000 -ATOM 654 H2 TIP3 964 -11.671 -1.077 -18.115 0.417 1.000 -ATOM 655 OH2 TIP3 970 -6.337 6.432 -13.471 -0.834 1.520 -ATOM 656 H1 TIP3 970 -6.149 6.261 -12.518 0.417 1.000 -ATOM 657 H2 TIP3 970 -6.645 7.375 -13.468 0.417 1.000 -ATOM 658 OH2 TIP3 972 -4.973 -8.751 -10.194 -0.834 1.520 -ATOM 659 H1 TIP3 972 -4.364 -9.047 -10.896 0.417 1.000 -ATOM 660 H2 TIP3 972 -5.071 -7.806 -10.455 0.417 1.000 -ATOM 661 OH2 TIP3 973 -0.470 -0.187 4.413 -0.834 1.520 -ATOM 662 H1 TIP3 973 0.399 0.251 4.331 0.417 1.000 -ATOM 663 H2 TIP3 973 -0.245 -1.124 4.418 0.417 1.000 -ATOM 664 OH2 TIP3 974 -9.726 -8.552 0.959 -0.834 1.520 -ATOM 665 H1 TIP3 974 -9.107 -8.927 1.654 0.417 1.000 -ATOM 666 H2 TIP3 974 -9.656 -9.109 0.238 0.417 1.000 -ATOM 667 OH2 TIP3 975 -8.527 -13.925 1.702 -0.834 1.520 -ATOM 668 H1 TIP3 975 -7.954 -14.333 2.431 0.417 1.000 -ATOM 669 H2 TIP3 975 -9.446 -14.061 2.100 0.417 1.000 -ATOM 670 OH2 TIP3 977 -11.682 -4.716 5.150 -0.834 1.520 -ATOM 671 H1 TIP3 977 -11.010 -4.921 5.736 0.417 1.000 -ATOM 672 H2 TIP3 977 -11.264 -4.047 4.564 0.417 1.000 -ATOM 673 OH2 TIP3 985 10.868 8.734 -17.269 -0.834 1.520 -ATOM 674 H1 TIP3 985 10.991 9.422 -17.981 0.417 1.000 -ATOM 675 H2 TIP3 985 11.515 8.043 -17.516 0.417 1.000 -ATOM 676 OH2 TIP3 988 -6.088 6.462 -17.714 -0.834 1.520 -ATOM 677 H1 TIP3 988 -6.333 7.388 -17.461 0.417 1.000 -ATOM 678 H2 TIP3 988 -6.512 5.916 -17.000 0.417 1.000 -ATOM 679 OH2 TIP3 989 -8.835 12.860 -18.664 -0.834 1.520 -ATOM 680 H1 TIP3 989 -8.617 12.035 -19.026 0.417 1.000 -ATOM 681 H2 TIP3 989 -9.094 12.669 -17.759 0.417 1.000 -ATOM 682 OH2 TIP3 990 4.449 16.400 -12.116 -0.834 1.520 -ATOM 683 H1 TIP3 990 5.434 16.551 -12.143 0.417 1.000 -ATOM 684 H2 TIP3 990 4.142 16.332 -13.058 0.417 1.000 -ATOM 685 OH2 TIP3 991 -5.665 14.997 -4.341 -0.834 1.520 -ATOM 686 H1 TIP3 991 -6.636 14.868 -4.261 0.417 1.000 -ATOM 687 H2 TIP3 991 -5.590 15.230 -5.279 0.417 1.000 -ATOM 688 OH2 TIP3 992 1.008 -16.730 -4.827 -0.834 1.520 -ATOM 689 H1 TIP3 992 0.390 -15.964 -4.916 0.417 1.000 -ATOM 690 H2 TIP3 992 1.768 -16.408 -5.251 0.417 1.000 -ATOM 691 OH2 TIP3 994 -2.690 -7.275 10.317 -0.834 1.520 -ATOM 692 H1 TIP3 994 -3.519 -6.839 10.591 0.417 1.000 -ATOM 693 H2 TIP3 994 -2.943 -8.144 9.939 0.417 1.000 -ATOM 694 OH2 TIP3 995 -13.200 -3.341 -2.816 -0.834 1.520 -ATOM 695 H1 TIP3 995 -12.857 -3.351 -3.673 0.417 1.000 -ATOM 696 H2 TIP3 995 -12.891 -2.498 -2.432 0.417 1.000 -ATOM 697 OH2 TIP3 996 -14.220 -2.484 4.024 -0.834 1.520 -ATOM 698 H1 TIP3 996 -14.894 -2.674 3.341 0.417 1.000 -ATOM 699 H2 TIP3 996 -14.250 -1.515 4.094 0.417 1.000 -ATOM 700 OH2 TIP3 998 4.714 1.300 8.954 -0.834 1.520 -ATOM 701 H1 TIP3 998 4.446 1.591 8.048 0.417 1.000 -ATOM 702 H2 TIP3 998 5.209 2.035 9.317 0.417 1.000 -ATOM 703 OH2 TIP3 1007 -5.397 -1.890 -16.787 -0.834 1.520 -ATOM 704 H1 TIP3 1007 -5.725 -2.345 -16.037 0.417 1.000 -ATOM 705 H2 TIP3 1007 -6.158 -1.394 -17.122 0.417 1.000 -ATOM 706 OH2 TIP3 1011 -15.247 0.139 -14.525 -0.834 1.520 -ATOM 707 H1 TIP3 1011 -15.231 1.053 -14.154 0.417 1.000 -ATOM 708 H2 TIP3 1011 -14.337 0.031 -14.799 0.417 1.000 -ATOM 709 OH2 TIP3 1012 -10.750 2.403 8.404 -0.834 1.520 -ATOM 710 H1 TIP3 1012 -11.576 2.852 8.305 0.417 1.000 -ATOM 711 H2 TIP3 1012 -10.857 1.926 9.253 0.417 1.000 -ATOM 712 OH2 TIP3 1013 -18.385 -2.645 -5.645 -0.834 1.520 -ATOM 713 H1 TIP3 1013 -18.775 -3.520 -5.580 0.417 1.000 -ATOM 714 H2 TIP3 1013 -19.141 -2.016 -5.949 0.417 1.000 -ATOM 715 OH2 TIP3 1014 -8.913 -4.213 0.150 -0.834 1.520 -ATOM 716 H1 TIP3 1014 -8.779 -5.123 -0.302 0.417 1.000 -ATOM 717 H2 TIP3 1014 -8.064 -4.060 0.591 0.417 1.000 -ATOM 718 OH2 TIP3 1015 2.578 3.665 3.229 -0.834 1.520 -ATOM 719 H1 TIP3 1015 3.396 3.499 2.734 0.417 1.000 -ATOM 720 H2 TIP3 1015 1.920 3.775 2.561 0.417 1.000 -ATOM 721 OH2 TIP3 1017 -10.216 -1.940 -3.561 -0.834 1.520 -ATOM 722 H1 TIP3 1017 -9.424 -1.834 -4.078 0.417 1.000 -ATOM 723 H2 TIP3 1017 -10.059 -1.416 -2.766 0.417 1.000 -ATOM 724 OH2 TIP3 1018 -17.631 -0.380 -9.162 -0.834 1.520 -ATOM 725 H1 TIP3 1018 -17.949 -0.575 -8.299 0.417 1.000 -ATOM 726 H2 TIP3 1018 -16.653 -0.283 -9.077 0.417 1.000 -ATOM 727 OH2 TIP3 1020 -7.801 -8.646 11.965 -0.834 1.520 -ATOM 728 H1 TIP3 1020 -7.720 -7.730 12.149 0.417 1.000 -ATOM 729 H2 TIP3 1020 -8.615 -8.646 11.486 0.417 1.000 -ATOM 730 OH2 TIP3 1023 -13.013 5.343 12.803 -0.834 1.520 -ATOM 731 H1 TIP3 1023 -13.938 5.093 13.100 0.417 1.000 -ATOM 732 H2 TIP3 1023 -12.532 4.995 13.508 0.417 1.000 -ATOM 733 OH2 TIP3 1027 -4.842 -4.782 -18.547 -0.834 1.520 -ATOM 734 H1 TIP3 1027 -4.714 -3.877 -18.840 0.417 1.000 -ATOM 735 H2 TIP3 1027 -5.825 -4.781 -18.413 0.417 1.000 -ATOM 736 OH2 TIP3 1032 -12.071 -10.399 -15.678 -0.834 1.520 -ATOM 737 H1 TIP3 1032 -12.636 -9.660 -16.088 0.417 1.000 -ATOM 738 H2 TIP3 1032 -12.682 -10.989 -15.180 0.417 1.000 -ATOM 739 OH2 TIP3 1033 -9.791 6.935 -18.027 -0.834 1.520 -ATOM 740 H1 TIP3 1033 -10.603 7.288 -18.480 0.417 1.000 -ATOM 741 H2 TIP3 1033 -9.477 7.672 -17.376 0.417 1.000 -ATOM 742 OH2 TIP3 1039 -10.941 13.382 11.598 -0.834 1.520 -ATOM 743 H1 TIP3 1039 -10.702 12.548 11.121 0.417 1.000 -ATOM 744 H2 TIP3 1039 -10.814 13.114 12.523 0.417 1.000 -ATOM 745 OH2 TIP3 1040 -12.875 6.008 -3.795 -0.834 1.520 -ATOM 746 H1 TIP3 1040 -12.695 6.912 -4.006 0.417 1.000 -ATOM 747 H2 TIP3 1040 -13.715 5.889 -4.266 0.417 1.000 -ATOM 748 OH2 TIP3 1053 -8.415 3.121 -0.545 -0.834 1.520 -ATOM 749 H1 TIP3 1053 -7.587 3.205 -0.018 0.417 1.000 -ATOM 750 H2 TIP3 1053 -9.184 3.266 0.095 0.417 1.000 -ATOM 751 OH2 TIP3 1054 1.033 7.960 -2.407 -0.834 1.520 -ATOM 752 H1 TIP3 1054 1.033 8.956 -2.379 0.417 1.000 -ATOM 753 H2 TIP3 1054 1.925 7.777 -2.825 0.417 1.000 -ATOM 754 OH2 TIP3 1055 -11.543 11.011 -19.140 -0.834 1.520 -ATOM 755 H1 TIP3 1055 -11.756 11.664 -18.486 0.417 1.000 -ATOM 756 H2 TIP3 1055 -12.191 10.305 -18.933 0.417 1.000 -ATOM 757 OH2 TIP3 1056 -0.599 16.861 3.848 -0.834 1.520 -ATOM 758 H1 TIP3 1056 -0.612 17.833 3.651 0.417 1.000 -ATOM 759 H2 TIP3 1056 -1.025 16.454 3.026 0.417 1.000 -ATOM 760 OH2 TIP3 1057 -10.077 18.910 2.513 -0.834 1.520 -ATOM 761 H1 TIP3 1057 -10.245 18.506 3.457 0.417 1.000 -ATOM 762 H2 TIP3 1057 -10.853 18.717 1.948 0.417 1.000 -ATOM 763 OH2 TIP3 1058 -13.751 7.735 -6.332 -0.834 1.520 -ATOM 764 H1 TIP3 1058 -13.537 8.358 -7.002 0.417 1.000 -ATOM 765 H2 TIP3 1058 -12.910 7.243 -6.152 0.417 1.000 -ATOM 766 OH2 TIP3 1059 -6.245 5.794 -10.480 -0.834 1.520 -ATOM 767 H1 TIP3 1059 -7.174 5.669 -10.233 0.417 1.000 -ATOM 768 H2 TIP3 1059 -5.852 5.751 -9.626 0.417 1.000 -ATOM 769 OH2 TIP3 1060 -8.580 0.031 14.330 -0.834 1.520 -ATOM 770 H1 TIP3 1060 -9.257 0.735 14.495 0.417 1.000 -ATOM 771 H2 TIP3 1060 -8.817 -0.665 14.947 0.417 1.000 -ATOM 772 OH2 TIP3 1061 -16.604 -0.006 16.503 -0.834 1.520 -ATOM 773 H1 TIP3 1061 -16.646 -0.905 16.141 0.417 1.000 -ATOM 774 H2 TIP3 1061 -16.475 0.554 15.622 0.417 1.000 -ATOM 775 OH2 TIP3 1062 -4.502 6.311 17.716 -0.834 1.520 -ATOM 776 H1 TIP3 1062 -4.891 7.146 17.683 0.417 1.000 -ATOM 777 H2 TIP3 1062 -4.551 5.975 16.834 0.417 1.000 -ATOM 778 OH2 TIP3 1063 -6.374 10.844 16.012 -0.834 1.520 -ATOM 779 H1 TIP3 1063 -7.039 10.601 16.641 0.417 1.000 -ATOM 780 H2 TIP3 1063 -5.591 10.739 16.544 0.417 1.000 -ATOM 781 OH2 TIP3 1065 -3.665 18.240 18.854 -0.834 1.520 -ATOM 782 H1 TIP3 1065 -3.807 17.407 19.375 0.417 1.000 -ATOM 783 H2 TIP3 1065 -4.496 18.528 18.513 0.417 1.000 -ATOM 784 OH2 TIP3 1066 -16.259 13.268 11.520 -0.834 1.520 -ATOM 785 H1 TIP3 1066 -15.303 13.107 11.390 0.417 1.000 -ATOM 786 H2 TIP3 1066 -16.330 13.920 12.193 0.417 1.000 -ATOM 787 OH2 TIP3 1076 -17.480 10.670 -13.743 -0.834 1.520 -ATOM 788 H1 TIP3 1076 -17.328 9.751 -13.563 0.417 1.000 -ATOM 789 H2 TIP3 1076 -17.584 11.150 -12.855 0.417 1.000 -ATOM 790 OH2 TIP3 1079 3.653 5.472 10.275 -0.834 1.520 -ATOM 791 H1 TIP3 1079 2.816 5.942 10.562 0.417 1.000 -ATOM 792 H2 TIP3 1079 3.255 4.843 9.700 0.417 1.000 -ATOM 793 OH2 TIP3 1080 -14.020 7.548 3.471 -0.834 1.520 -ATOM 794 H1 TIP3 1080 -13.723 8.300 3.032 0.417 1.000 -ATOM 795 H2 TIP3 1080 -14.003 7.744 4.375 0.417 1.000 -ATOM 796 OH2 TIP3 1081 -12.309 14.925 7.136 -0.834 1.520 -ATOM 797 H1 TIP3 1081 -11.552 14.853 6.499 0.417 1.000 -ATOM 798 H2 TIP3 1081 -11.810 15.003 7.987 0.417 1.000 -ATOM 799 OH2 TIP3 1082 -0.176 3.862 17.888 -0.834 1.520 -ATOM 800 H1 TIP3 1082 0.398 3.217 17.384 0.417 1.000 -ATOM 801 H2 TIP3 1082 0.523 4.255 18.430 0.417 1.000 -ATOM 802 OH2 TIP3 1096 -0.168 9.792 -14.480 -0.834 1.520 -ATOM 803 H1 TIP3 1096 0.273 10.362 -13.807 0.417 1.000 -ATOM 804 H2 TIP3 1096 -0.633 9.183 -13.951 0.417 1.000 -ATOM 805 OH2 TIP3 1097 -10.265 12.833 14.356 -0.834 1.520 -ATOM 806 H1 TIP3 1097 -9.333 12.961 14.414 0.417 1.000 -ATOM 807 H2 TIP3 1097 -10.520 12.294 15.174 0.417 1.000 -ATOM 808 OH2 TIP3 1098 -16.741 9.755 -9.522 -0.834 1.520 -ATOM 809 H1 TIP3 1098 -16.623 10.314 -10.277 0.417 1.000 -ATOM 810 H2 TIP3 1098 -17.502 9.224 -9.857 0.417 1.000 -ATOM 811 OH2 TIP3 1099 -7.151 15.375 6.653 -0.834 1.520 -ATOM 812 H1 TIP3 1099 -6.424 14.867 6.350 0.417 1.000 -ATOM 813 H2 TIP3 1099 -7.757 14.708 7.004 0.417 1.000 -ATOM 814 OH2 TIP3 1100 -13.262 3.712 6.178 -0.834 1.520 -ATOM 815 H1 TIP3 1100 -12.917 4.220 5.441 0.417 1.000 -ATOM 816 H2 TIP3 1100 -14.093 3.381 5.843 0.417 1.000 -ATOM 817 OH2 TIP3 1101 -8.171 17.598 1.309 -0.834 1.520 -ATOM 818 H1 TIP3 1101 -8.803 17.629 2.074 0.417 1.000 -ATOM 819 H2 TIP3 1101 -8.386 18.399 0.840 0.417 1.000 -ATOM 820 OH2 TIP3 1104 -18.622 11.718 11.127 -0.834 1.520 -ATOM 821 H1 TIP3 1104 -17.850 12.172 11.554 0.417 1.000 -ATOM 822 H2 TIP3 1104 -18.943 11.061 11.774 0.417 1.000 -ATOM 823 OH2 TIP3 1105 -10.120 19.166 15.174 -0.834 1.520 -ATOM 824 H1 TIP3 1105 -10.720 18.846 15.891 0.417 1.000 -ATOM 825 H2 TIP3 1105 -9.266 19.097 15.577 0.417 1.000 -ATOM 826 OH2 TIP3 1107 -13.117 6.827 15.132 -0.834 1.520 -ATOM 827 H1 TIP3 1107 -13.335 6.501 14.198 0.417 1.000 -ATOM 828 H2 TIP3 1107 -13.990 6.720 15.589 0.417 1.000 -ATOM 829 OH2 TIP3 1112 -13.297 6.593 -15.152 -0.834 1.520 -ATOM 830 H1 TIP3 1112 -12.593 7.207 -15.239 0.417 1.000 -ATOM 831 H2 TIP3 1112 -13.284 6.068 -15.987 0.417 1.000 -ATOM 832 OH2 TIP3 1115 1.371 -2.115 -14.125 -0.834 1.520 -ATOM 833 H1 TIP3 1115 0.731 -2.810 -13.799 0.417 1.000 -ATOM 834 H2 TIP3 1115 2.157 -2.229 -13.621 0.417 1.000 -ATOM 835 OH2 TIP3 1117 1.052 -5.510 -15.708 -0.834 1.520 -ATOM 836 H1 TIP3 1117 0.664 -5.975 -14.991 0.417 1.000 -ATOM 837 H2 TIP3 1117 1.791 -4.994 -15.253 0.417 1.000 -ATOM 838 OH2 TIP3 1118 -8.935 8.816 4.528 -0.834 1.520 -ATOM 839 H1 TIP3 1118 -9.687 8.525 5.001 0.417 1.000 -ATOM 840 H2 TIP3 1118 -8.280 8.079 4.603 0.417 1.000 -ATOM 841 OH2 TIP3 1120 -11.893 9.357 5.179 -0.834 1.520 -ATOM 842 H1 TIP3 1120 -12.419 9.729 5.895 0.417 1.000 -ATOM 843 H2 TIP3 1120 -11.572 8.414 5.546 0.417 1.000 -ATOM 844 OH2 TIP3 1121 -8.926 17.222 7.267 -0.834 1.520 -ATOM 845 H1 TIP3 1121 -8.769 17.549 8.221 0.417 1.000 -ATOM 846 H2 TIP3 1121 -8.247 16.451 7.072 0.417 1.000 -ATOM 847 OH2 TIP3 1122 -18.269 11.479 1.005 -0.834 1.520 -ATOM 848 H1 TIP3 1122 -18.118 10.862 0.348 0.417 1.000 -ATOM 849 H2 TIP3 1122 -18.239 10.976 1.853 0.417 1.000 -ATOM 850 OH2 TIP3 1145 2.643 9.951 12.565 -0.834 1.520 -ATOM 851 H1 TIP3 1145 1.799 9.493 12.514 0.417 1.000 -ATOM 852 H2 TIP3 1145 3.225 9.166 12.828 0.417 1.000 -ATOM 853 OH2 TIP3 1147 -5.856 7.712 15.317 -0.834 1.520 -ATOM 854 H1 TIP3 1147 -6.487 7.643 16.062 0.417 1.000 -ATOM 855 H2 TIP3 1147 -6.061 7.011 14.727 0.417 1.000 -ATOM 856 OH2 TIP3 1148 -12.910 2.613 17.614 -0.834 1.520 -ATOM 857 H1 TIP3 1148 -13.894 2.435 17.632 0.417 1.000 -ATOM 858 H2 TIP3 1148 -12.600 1.991 18.307 0.417 1.000 -ATOM 859 OH2 TIP3 1158 -12.889 17.051 -3.520 -0.834 1.520 -ATOM 860 H1 TIP3 1158 -13.741 16.733 -3.249 0.417 1.000 -ATOM 861 H2 TIP3 1158 -12.803 17.960 -3.232 0.417 1.000 -ATOM 862 OH2 TIP3 1164 -4.220 1.074 14.906 -0.834 1.520 -ATOM 863 H1 TIP3 1164 -4.321 0.862 15.797 0.417 1.000 -ATOM 864 H2 TIP3 1164 -3.250 1.309 14.791 0.417 1.000 -ATOM 865 OH2 TIP3 1178 -11.767 18.772 -16.664 -0.834 1.520 -ATOM 866 H1 TIP3 1178 -11.201 18.275 -16.113 0.417 1.000 -ATOM 867 H2 TIP3 1178 -12.082 19.471 -16.044 0.417 1.000 -ATOM 868 OH2 TIP3 1182 -15.666 19.078 8.966 -0.834 1.520 -ATOM 869 H1 TIP3 1182 -14.895 19.164 8.467 0.417 1.000 -ATOM 870 H2 TIP3 1182 -16.080 18.301 8.580 0.417 1.000 -ATOM 871 OH2 TIP3 1183 -13.849 16.124 -8.843 -0.834 1.520 -ATOM 872 H1 TIP3 1183 -13.748 16.551 -7.967 0.417 1.000 -ATOM 873 H2 TIP3 1183 -13.363 16.696 -9.489 0.417 1.000 -ATOM 874 OH2 TIP3 1186 -14.056 10.005 17.555 -0.834 1.520 -ATOM 875 H1 TIP3 1186 -14.565 9.721 18.312 0.417 1.000 -ATOM 876 H2 TIP3 1186 -13.501 9.263 17.322 0.417 1.000 -ATOM 877 OH2 TIP3 1188 -10.497 19.714 8.657 -0.834 1.520 -ATOM 878 H1 TIP3 1188 -10.010 19.551 7.781 0.417 1.000 -ATOM 879 H2 TIP3 1188 -9.798 19.991 9.334 0.417 1.000 -ATOM 880 OH2 TIP3 1194 -15.074 18.691 17.583 -0.834 1.520 -ATOM 881 H1 TIP3 1194 -15.526 19.517 17.888 0.417 1.000 -ATOM 882 H2 TIP3 1194 -15.789 18.140 17.209 0.417 1.000 -ATOM 883 OH2 TIP3 1197 -8.107 13.506 -9.559 -0.834 1.520 -ATOM 884 H1 TIP3 1197 -8.901 13.627 -9.090 0.417 1.000 -ATOM 885 H2 TIP3 1197 -7.648 14.369 -9.549 0.417 1.000 -ATOM 886 OH2 TIP3 1200 -13.364 18.508 -10.693 -0.834 1.520 -ATOM 887 H1 TIP3 1200 -14.034 18.183 -11.177 0.417 1.000 -ATOM 888 H2 TIP3 1200 -13.662 19.353 -10.245 0.417 1.000 -ATOM 889 OH2 TIP3 1201 -14.659 9.958 -7.817 -0.834 1.520 -ATOM 890 H1 TIP3 1201 -15.489 9.806 -8.267 0.417 1.000 -ATOM 891 H2 TIP3 1201 -14.243 10.640 -8.384 0.417 1.000 -ATOM 892 OH2 TIP3 1202 -2.734 13.646 0.485 -0.834 1.520 -ATOM 893 H1 TIP3 1202 -2.323 12.967 1.063 0.417 1.000 -ATOM 894 H2 TIP3 1202 -2.479 14.453 0.986 0.417 1.000 -ATOM 895 OH2 TIP3 1272 -11.212 -16.706 4.627 -0.834 1.520 -ATOM 896 H1 TIP3 1272 -12.126 -16.430 4.750 0.417 1.000 -ATOM 897 H2 TIP3 1272 -10.829 -16.091 4.019 0.417 1.000 -ATOM 898 OH2 TIP3 1274 -12.561 -18.940 14.760 -0.834 1.520 -ATOM 899 H1 TIP3 1274 -12.143 -18.084 14.514 0.417 1.000 -ATOM 900 H2 TIP3 1274 -12.552 -19.454 13.976 0.417 1.000 -ATOM 901 OH2 TIP3 1298 -19.148 -15.823 17.753 -0.834 1.520 -ATOM 902 H1 TIP3 1298 -18.276 -16.222 17.993 0.417 1.000 -ATOM 903 H2 TIP3 1298 -19.768 -16.555 17.885 0.417 1.000 -ATOM 904 OH2 TIP3 1301 -16.680 -18.561 -16.307 -0.834 1.520 -ATOM 905 H1 TIP3 1301 -16.982 -18.737 -17.205 0.417 1.000 -ATOM 906 H2 TIP3 1301 -15.782 -18.263 -16.467 0.417 1.000 -ATOM 907 OH2 TIP3 1307 -3.904 -11.595 -9.372 -0.834 1.520 -ATOM 908 H1 TIP3 1307 -3.915 -10.610 -9.285 0.417 1.000 -ATOM 909 H2 TIP3 1307 -3.923 -11.652 -10.379 0.417 1.000 -ATOM 910 OH2 TIP3 1308 -11.622 2.836 -5.926 -0.834 1.520 -ATOM 911 H1 TIP3 1308 -10.873 3.085 -6.522 0.417 1.000 -ATOM 912 H2 TIP3 1308 -12.194 3.652 -5.888 0.417 1.000 -ATOM 913 OH2 TIP3 1309 4.434 -15.226 13.071 -0.834 1.520 -ATOM 914 H1 TIP3 1309 5.249 -15.245 12.565 0.417 1.000 -ATOM 915 H2 TIP3 1309 4.297 -16.185 13.213 0.417 1.000 -ATOM 916 OH2 TIP3 1311 -8.145 -15.478 9.839 -0.834 1.520 -ATOM 917 H1 TIP3 1311 -7.664 -16.276 9.523 0.417 1.000 -ATOM 918 H2 TIP3 1311 -8.668 -15.764 10.567 0.417 1.000 -ATOM 919 OH2 TIP3 1313 -9.574 -0.458 7.064 -0.834 1.520 -ATOM 920 H1 TIP3 1313 -10.532 -0.612 7.335 0.417 1.000 -ATOM 921 H2 TIP3 1313 -9.347 -1.197 6.429 0.417 1.000 -ATOM 922 OH2 TIP3 1326 -1.521 -16.911 -18.622 -0.834 1.520 -ATOM 923 H1 TIP3 1326 -2.464 -16.792 -18.426 0.417 1.000 -ATOM 924 H2 TIP3 1326 -1.398 -17.860 -18.803 0.417 1.000 -ATOM 925 OH2 TIP3 1327 -4.471 -14.018 -11.481 -0.834 1.520 -ATOM 926 H1 TIP3 1327 -3.602 -14.368 -11.188 0.417 1.000 -ATOM 927 H2 TIP3 1327 -4.777 -14.667 -12.133 0.417 1.000 -ATOM 928 OH2 TIP3 1328 -15.461 -17.395 -11.705 -0.834 1.520 -ATOM 929 H1 TIP3 1328 -14.540 -17.298 -11.877 0.417 1.000 -ATOM 930 H2 TIP3 1328 -15.566 -18.384 -11.637 0.417 1.000 -ATOM 931 OH2 TIP3 1329 0.028 -12.920 -10.978 -0.834 1.520 -ATOM 932 H1 TIP3 1329 0.675 -12.285 -10.918 0.417 1.000 -ATOM 933 H2 TIP3 1329 -0.615 -12.427 -11.473 0.417 1.000 -ATOM 934 OH2 TIP3 1330 2.010 -8.972 -1.553 -0.834 1.520 -ATOM 935 H1 TIP3 1330 2.719 -8.939 -2.299 0.417 1.000 -ATOM 936 H2 TIP3 1330 2.590 -8.860 -0.780 0.417 1.000 -ATOM 937 OH2 TIP3 1332 -5.323 -17.212 9.301 -0.834 1.520 -ATOM 938 H1 TIP3 1332 -5.340 -16.370 8.811 0.417 1.000 -ATOM 939 H2 TIP3 1332 -5.459 -17.798 8.553 0.417 1.000 -ATOM 940 OH2 TIP3 1333 -1.650 -13.022 -2.385 -0.834 1.520 -ATOM 941 H1 TIP3 1333 -1.585 -12.709 -3.298 0.417 1.000 -ATOM 942 H2 TIP3 1333 -2.602 -12.841 -2.216 0.417 1.000 -ATOM 943 OH2 TIP3 1344 -11.117 1.581 -14.240 -0.834 1.520 -ATOM 944 H1 TIP3 1344 -11.295 2.232 -13.554 0.417 1.000 -ATOM 945 H2 TIP3 1344 -10.643 2.008 -14.923 0.417 1.000 -ATOM 946 OH2 TIP3 1346 -0.601 -7.636 -18.020 -0.834 1.520 -ATOM 947 H1 TIP3 1346 -0.285 -8.501 -18.402 0.417 1.000 -ATOM 948 H2 TIP3 1346 -0.909 -7.941 -17.154 0.417 1.000 -ATOM 949 OH2 TIP3 1347 4.165 -13.181 -14.225 -0.834 1.520 -ATOM 950 H1 TIP3 1347 3.867 -13.390 -15.127 0.417 1.000 -ATOM 951 H2 TIP3 1347 3.362 -12.823 -13.749 0.417 1.000 -ATOM 952 OH2 TIP3 1349 -7.207 -6.636 -7.832 -0.834 1.520 -ATOM 953 H1 TIP3 1349 -7.213 -6.452 -8.777 0.417 1.000 -ATOM 954 H2 TIP3 1349 -8.005 -6.206 -7.601 0.417 1.000 -ATOM 955 OH2 TIP3 1352 -13.333 -12.453 -10.354 -0.834 1.520 -ATOM 956 H1 TIP3 1352 -13.897 -13.025 -9.704 0.417 1.000 -ATOM 957 H2 TIP3 1352 -12.442 -12.708 -9.954 0.417 1.000 -ATOM 958 OH2 TIP3 1354 -19.818 3.403 1.361 -0.834 1.520 -ATOM 959 H1 TIP3 1354 -19.699 3.585 2.346 0.417 1.000 -ATOM 960 H2 TIP3 1354 -18.999 2.867 1.220 0.417 1.000 -ATOM 961 OH2 TIP3 1355 -8.653 -3.993 3.148 -0.834 1.520 -ATOM 962 H1 TIP3 1355 -8.221 -4.874 3.087 0.417 1.000 -ATOM 963 H2 TIP3 1355 -9.414 -4.077 2.581 0.417 1.000 -ATOM 964 OH2 TIP3 1356 -14.219 -11.030 5.936 -0.834 1.520 -ATOM 965 H1 TIP3 1356 -13.821 -10.823 5.053 0.417 1.000 -ATOM 966 H2 TIP3 1356 -13.529 -11.567 6.363 0.417 1.000 -ATOM 967 OH2 TIP3 1361 -2.743 9.681 13.676 -0.834 1.520 -ATOM 968 H1 TIP3 1361 -2.802 10.631 13.366 0.417 1.000 -ATOM 969 H2 TIP3 1361 -3.648 9.417 13.384 0.417 1.000 -ATOM 970 OH2 TIP3 1367 -9.871 -2.515 -13.450 -0.834 1.520 -ATOM 971 H1 TIP3 1367 -10.769 -2.533 -13.080 0.417 1.000 -ATOM 972 H2 TIP3 1367 -9.892 -3.298 -14.015 0.417 1.000 -ATOM 973 OH2 TIP3 1368 2.412 -12.394 -7.335 -0.834 1.520 -ATOM 974 H1 TIP3 1368 1.852 -12.020 -6.612 0.417 1.000 -ATOM 975 H2 TIP3 1368 1.958 -13.231 -7.507 0.417 1.000 -ATOM 976 OH2 TIP3 1370 -15.346 -14.283 -14.977 -0.834 1.520 -ATOM 977 H1 TIP3 1370 -14.941 -14.874 -15.605 0.417 1.000 -ATOM 978 H2 TIP3 1370 -14.591 -14.215 -14.366 0.417 1.000 -ATOM 979 OH2 TIP3 1371 -7.664 -5.095 -10.650 -0.834 1.520 -ATOM 980 H1 TIP3 1371 -8.151 -4.412 -11.117 0.417 1.000 -ATOM 981 H2 TIP3 1371 -8.432 -5.625 -10.230 0.417 1.000 -ATOM 982 OH2 TIP3 1372 -14.813 -18.301 4.688 -0.834 1.520 -ATOM 983 H1 TIP3 1372 -14.504 -17.407 4.739 0.417 1.000 -ATOM 984 H2 TIP3 1372 -15.831 -18.127 4.767 0.417 1.000 -ATOM 985 OH2 TIP3 1374 -14.512 -5.745 -6.788 -0.834 1.520 -ATOM 986 H1 TIP3 1374 -13.721 -5.874 -6.291 0.417 1.000 -ATOM 987 H2 TIP3 1374 -15.136 -6.009 -6.122 0.417 1.000 -ATOM 988 OH2 TIP3 1376 -7.402 -6.842 3.181 -0.834 1.520 -ATOM 989 H1 TIP3 1376 -7.831 -6.794 4.069 0.417 1.000 -ATOM 990 H2 TIP3 1376 -6.484 -6.977 3.463 0.417 1.000 -ATOM 991 OH2 TIP3 1387 -16.314 -11.647 -16.599 -0.834 1.520 -ATOM 992 H1 TIP3 1387 -15.506 -12.070 -16.916 0.417 1.000 -ATOM 993 H2 TIP3 1387 -16.959 -12.273 -16.803 0.417 1.000 -ATOM 994 OH2 TIP3 1388 -4.995 -5.474 -0.867 -0.834 1.520 -ATOM 995 H1 TIP3 1388 -4.258 -6.059 -0.762 0.417 1.000 -ATOM 996 H2 TIP3 1388 -5.254 -5.547 -1.812 0.417 1.000 -ATOM 997 OH2 TIP3 1389 -4.573 -6.101 -6.582 -0.834 1.520 -ATOM 998 H1 TIP3 1389 -4.402 -5.297 -6.085 0.417 1.000 -ATOM 999 H2 TIP3 1389 -5.431 -5.968 -7.006 0.417 1.000 -ATOM 1000 OH2 TIP3 1392 -4.883 -3.658 -4.680 -0.834 1.520 -ATOM 1001 H1 TIP3 1392 -5.810 -3.342 -4.765 0.417 1.000 -ATOM 1002 H2 TIP3 1392 -4.275 -2.920 -5.050 0.417 1.000 -ATOM 1003 OH2 TIP3 1394 -6.035 -12.670 8.278 -0.834 1.520 -ATOM 1004 H1 TIP3 1394 -6.373 -11.798 8.654 0.417 1.000 -ATOM 1005 H2 TIP3 1394 -5.866 -13.292 9.029 0.417 1.000 -ATOM 1006 OH2 TIP3 1396 -11.536 0.926 10.643 -0.834 1.520 -ATOM 1007 H1 TIP3 1396 -11.281 1.313 11.498 0.417 1.000 -ATOM 1008 H2 TIP3 1396 -11.523 -0.038 10.810 0.417 1.000 -ATOM 1009 OH2 TIP3 1398 -4.372 -16.112 11.949 -0.834 1.520 -ATOM 1010 H1 TIP3 1398 -4.305 -16.597 11.167 0.417 1.000 -ATOM 1011 H2 TIP3 1398 -4.313 -16.773 12.622 0.417 1.000 -ATOM 1012 OH2 TIP3 1407 -6.737 3.513 -12.674 -0.834 1.520 -ATOM 1013 H1 TIP3 1407 -5.917 3.900 -12.311 0.417 1.000 -ATOM 1014 H2 TIP3 1407 -6.331 2.803 -13.261 0.417 1.000 -ATOM 1015 OH2 TIP3 1408 -15.711 5.675 -18.525 -0.834 1.520 -ATOM 1016 H1 TIP3 1408 -14.986 5.297 -18.091 0.417 1.000 -ATOM 1017 H2 TIP3 1408 -16.372 5.027 -18.487 0.417 1.000 -ATOM 1018 OH2 TIP3 1411 -9.970 -8.559 -16.566 -0.834 1.520 -ATOM 1019 H1 TIP3 1411 -10.726 -9.173 -16.578 0.417 1.000 -ATOM 1020 H2 TIP3 1411 -9.467 -8.638 -17.339 0.417 1.000 -ATOM 1021 OH2 TIP3 1412 -9.450 -10.456 -8.685 -0.834 1.520 -ATOM 1022 H1 TIP3 1412 -9.945 -9.657 -8.604 0.417 1.000 -ATOM 1023 H2 TIP3 1412 -8.540 -10.154 -8.663 0.417 1.000 -ATOM 1024 OH2 TIP3 1413 -2.804 -1.962 -6.223 -0.834 1.520 -ATOM 1025 H1 TIP3 1413 -2.508 -2.915 -6.250 0.417 1.000 -ATOM 1026 H2 TIP3 1413 -3.132 -1.918 -7.145 0.417 1.000 -ATOM 1027 OH2 TIP3 1414 -17.995 -2.204 1.122 -0.834 1.520 -ATOM 1028 H1 TIP3 1414 -17.227 -2.675 1.598 0.417 1.000 -ATOM 1029 H2 TIP3 1414 -17.827 -1.242 1.265 0.417 1.000 -ATOM 1030 OH2 TIP3 1415 -6.447 -4.760 1.435 -0.834 1.520 -ATOM 1031 H1 TIP3 1415 -5.897 -5.041 0.726 0.417 1.000 -ATOM 1032 H2 TIP3 1415 -6.578 -5.530 1.979 0.417 1.000 -ATOM 1033 OH2 TIP3 1416 -12.004 -3.094 8.597 -0.834 1.520 -ATOM 1034 H1 TIP3 1416 -12.612 -3.309 7.856 0.417 1.000 -ATOM 1035 H2 TIP3 1416 -11.729 -2.162 8.310 0.417 1.000 -ATOM 1036 OH2 TIP3 1417 -1.413 -4.224 6.957 -0.834 1.520 -ATOM 1037 H1 TIP3 1417 -2.159 -3.739 6.479 0.417 1.000 -ATOM 1038 H2 TIP3 1417 -1.428 -5.174 6.675 0.417 1.000 -ATOM 1039 OH2 TIP3 1418 -8.544 -17.650 -0.415 -0.834 1.520 -ATOM 1040 H1 TIP3 1418 -9.269 -17.069 -0.270 0.417 1.000 -ATOM 1041 H2 TIP3 1418 -8.454 -18.138 0.401 0.417 1.000 -ATOM 1042 OH2 TIP3 1420 1.969 2.337 11.122 -0.834 1.520 -ATOM 1043 H1 TIP3 1420 1.598 2.329 10.260 0.417 1.000 -ATOM 1044 H2 TIP3 1420 2.906 2.787 11.039 0.417 1.000 -ATOM 1045 OH2 TIP3 1421 -4.360 2.903 18.615 -0.834 1.520 -ATOM 1046 H1 TIP3 1421 -3.757 3.661 18.665 0.417 1.000 -ATOM 1047 H2 TIP3 1421 -3.746 2.148 18.657 0.417 1.000 -ATOM 1048 OH2 TIP3 1428 -6.932 -17.086 -9.851 -0.834 1.520 -ATOM 1049 H1 TIP3 1428 -7.197 -17.527 -10.705 0.417 1.000 -ATOM 1050 H2 TIP3 1428 -5.990 -17.151 -9.888 0.417 1.000 -ATOM 1051 OH2 TIP3 1429 -14.550 -10.933 -14.663 -0.834 1.520 -ATOM 1052 H1 TIP3 1429 -15.278 -11.160 -15.289 0.417 1.000 -ATOM 1053 H2 TIP3 1429 -15.061 -11.230 -13.883 0.417 1.000 -ATOM 1054 OH2 TIP3 1430 -10.187 5.619 -5.270 -0.834 1.520 -ATOM 1055 H1 TIP3 1430 -9.344 5.876 -4.836 0.417 1.000 -ATOM 1056 H2 TIP3 1430 -10.804 6.145 -4.725 0.417 1.000 -ATOM 1057 OH2 TIP3 1431 8.957 1.722 -14.497 -0.834 1.520 -ATOM 1058 H1 TIP3 1431 8.135 1.403 -14.937 0.417 1.000 -ATOM 1059 H2 TIP3 1431 8.661 2.493 -13.925 0.417 1.000 -ATOM 1060 OH2 TIP3 1433 -16.703 -1.229 -2.697 -0.834 1.520 -ATOM 1061 H1 TIP3 1433 -16.087 -0.728 -2.175 0.417 1.000 -ATOM 1062 H2 TIP3 1433 -16.384 -1.065 -3.592 0.417 1.000 -ATOM 1063 OH2 TIP3 1435 -13.403 -4.046 1.463 -0.834 1.520 -ATOM 1064 H1 TIP3 1435 -12.843 -4.840 1.200 0.417 1.000 -ATOM 1065 H2 TIP3 1435 -12.795 -3.549 2.021 0.417 1.000 -ATOM 1066 OH2 TIP3 1436 -15.616 6.376 16.209 -0.834 1.520 -ATOM 1067 H1 TIP3 1436 -15.490 5.829 17.007 0.417 1.000 -ATOM 1068 H2 TIP3 1436 -16.256 7.049 16.456 0.417 1.000 -ATOM 1069 OH2 TIP3 1437 -5.082 -14.990 7.460 -0.834 1.520 -ATOM 1070 H1 TIP3 1437 -5.408 -14.066 7.510 0.417 1.000 -ATOM 1071 H2 TIP3 1437 -4.171 -14.925 7.140 0.417 1.000 -ATOM 1072 OH2 TIP3 1439 -13.438 9.156 9.103 -0.834 1.520 -ATOM 1073 H1 TIP3 1439 -12.443 9.127 9.247 0.417 1.000 -ATOM 1074 H2 TIP3 1439 -13.493 9.741 8.296 0.417 1.000 -ATOM 1075 OH2 TIP3 1440 -18.557 -16.020 -1.373 -0.834 1.520 -ATOM 1076 H1 TIP3 1440 -18.464 -16.950 -1.753 0.417 1.000 -ATOM 1077 H2 TIP3 1440 -19.411 -15.718 -1.744 0.417 1.000 -ATOM 1078 OH2 TIP3 1442 -13.752 -6.495 4.232 -0.834 1.520 -ATOM 1079 H1 TIP3 1442 -12.943 -6.178 3.871 0.417 1.000 -ATOM 1080 H2 TIP3 1442 -13.749 -6.199 5.132 0.417 1.000 -ATOM 1081 OH2 TIP3 1450 0.255 5.983 -16.871 -0.834 1.520 -ATOM 1082 H1 TIP3 1450 0.472 6.411 -16.046 0.417 1.000 -ATOM 1083 H2 TIP3 1450 -0.132 5.098 -16.674 0.417 1.000 -ATOM 1084 OH2 TIP3 1451 -16.752 2.876 -16.299 -0.834 1.520 -ATOM 1085 H1 TIP3 1451 -17.338 2.334 -15.752 0.417 1.000 -ATOM 1086 H2 TIP3 1451 -15.894 2.410 -16.219 0.417 1.000 -ATOM 1087 OH2 TIP3 1453 -2.095 8.143 -13.552 -0.834 1.520 -ATOM 1088 H1 TIP3 1453 -2.826 8.506 -14.038 0.417 1.000 -ATOM 1089 H2 TIP3 1453 -2.526 7.472 -13.020 0.417 1.000 -ATOM 1090 OH2 TIP3 1454 -11.057 -0.393 -10.607 -0.834 1.520 -ATOM 1091 H1 TIP3 1454 -10.110 -0.334 -10.826 0.417 1.000 -ATOM 1092 H2 TIP3 1454 -11.449 -0.798 -11.414 0.417 1.000 -ATOM 1093 OH2 TIP3 1455 -12.466 3.313 2.010 -0.834 1.520 -ATOM 1094 H1 TIP3 1455 -12.691 2.777 2.738 0.417 1.000 -ATOM 1095 H2 TIP3 1455 -13.303 3.403 1.532 0.417 1.000 -ATOM 1096 OH2 TIP3 1457 -6.660 -6.440 -3.523 -0.834 1.520 -ATOM 1097 H1 TIP3 1457 -6.600 -6.432 -4.458 0.417 1.000 -ATOM 1098 H2 TIP3 1457 -7.148 -5.594 -3.367 0.417 1.000 -ATOM 1099 OH2 TIP3 1458 -11.656 -12.155 0.429 -0.834 1.520 -ATOM 1100 H1 TIP3 1458 -11.521 -11.708 1.236 0.417 1.000 -ATOM 1101 H2 TIP3 1458 -10.898 -11.941 -0.100 0.417 1.000 -ATOM 1102 OH2 TIP3 1459 -14.562 11.554 2.819 -0.834 1.520 -ATOM 1103 H1 TIP3 1459 -15.377 11.788 3.335 0.417 1.000 -ATOM 1104 H2 TIP3 1459 -14.989 10.914 2.179 0.417 1.000 -ATOM 1105 OH2 TIP3 1461 -7.688 -11.207 18.101 -0.834 1.520 -ATOM 1106 H1 TIP3 1461 -8.485 -10.954 17.539 0.417 1.000 -ATOM 1107 H2 TIP3 1461 -7.086 -11.483 17.387 0.417 1.000 -ATOM 1108 OH2 TIP3 1466 -16.118 13.117 -18.731 -0.834 1.520 -ATOM 1109 H1 TIP3 1466 -15.703 13.920 -18.369 0.417 1.000 -ATOM 1110 H2 TIP3 1466 -15.370 12.476 -18.741 0.417 1.000 -ATOM 1111 OH2 TIP3 1471 1.892 -10.510 -17.046 -0.834 1.520 -ATOM 1112 H1 TIP3 1471 2.662 -11.035 -16.993 0.417 1.000 -ATOM 1113 H2 TIP3 1471 1.279 -11.090 -17.442 0.417 1.000 -ATOM 1114 OH2 TIP3 1474 -13.099 1.557 -10.674 -0.834 1.520 -ATOM 1115 H1 TIP3 1474 -12.590 0.744 -10.616 0.417 1.000 -ATOM 1116 H2 TIP3 1474 -12.526 2.077 -11.241 0.417 1.000 -ATOM 1117 OH2 TIP3 1475 -3.739 1.789 2.152 -0.834 1.520 -ATOM 1118 H1 TIP3 1475 -3.316 0.873 1.878 0.417 1.000 -ATOM 1119 H2 TIP3 1475 -3.212 2.010 2.873 0.417 1.000 -ATOM 1120 OH2 TIP3 1476 -15.942 -1.794 8.885 -0.834 1.520 -ATOM 1121 H1 TIP3 1476 -16.725 -2.400 8.880 0.417 1.000 -ATOM 1122 H2 TIP3 1476 -15.164 -2.347 9.254 0.417 1.000 -ATOM 1123 OH2 TIP3 1477 -15.471 14.567 1.893 -0.834 1.520 -ATOM 1124 H1 TIP3 1477 -15.650 13.803 1.339 0.417 1.000 -ATOM 1125 H2 TIP3 1477 -15.992 15.319 1.446 0.417 1.000 -ATOM 1126 OH2 TIP3 1478 -3.922 8.219 -3.537 -0.834 1.520 -ATOM 1127 H1 TIP3 1478 -4.730 8.606 -3.810 0.417 1.000 -ATOM 1128 H2 TIP3 1478 -3.513 8.107 -4.419 0.417 1.000 -ATOM 1129 OH2 TIP3 1479 -9.939 5.226 16.361 -0.834 1.520 -ATOM 1130 H1 TIP3 1479 -9.809 6.085 15.854 0.417 1.000 -ATOM 1131 H2 TIP3 1479 -8.950 4.997 16.510 0.417 1.000 -ATOM 1132 OH2 TIP3 1480 -18.159 8.556 -0.519 -0.834 1.520 -ATOM 1133 H1 TIP3 1480 -17.414 8.152 -0.929 0.417 1.000 -ATOM 1134 H2 TIP3 1480 -18.762 8.723 -1.259 0.417 1.000 -ATOM 1135 OH2 TIP3 1481 0.228 4.555 13.339 -0.834 1.520 -ATOM 1136 H1 TIP3 1481 -0.232 3.920 12.719 0.417 1.000 -ATOM 1137 H2 TIP3 1481 -0.548 4.798 13.967 0.417 1.000 -ATOM 1138 OH2 TIP3 1493 -14.404 3.880 -1.238 -0.834 1.520 -ATOM 1139 H1 TIP3 1493 -14.273 4.762 -0.815 0.417 1.000 -ATOM 1140 H2 TIP3 1493 -13.496 3.604 -1.569 0.417 1.000 -ATOM 1141 OH2 TIP3 1494 -5.597 -12.185 -4.788 -0.834 1.520 -ATOM 1142 H1 TIP3 1494 -6.468 -11.794 -5.089 0.417 1.000 -ATOM 1143 H2 TIP3 1494 -5.115 -12.319 -5.627 0.417 1.000 -ATOM 1144 OH2 TIP3 1497 -13.143 -8.862 -13.171 -0.834 1.520 -ATOM 1145 H1 TIP3 1497 -13.893 -8.250 -13.200 0.417 1.000 -ATOM 1146 H2 TIP3 1497 -13.520 -9.613 -13.647 0.417 1.000 -ATOM 1147 OH2 TIP3 1499 -8.243 6.769 0.348 -0.834 1.520 -ATOM 1148 H1 TIP3 1499 -8.536 7.496 0.874 0.417 1.000 -ATOM 1149 H2 TIP3 1499 -9.014 6.221 0.287 0.417 1.000 -ATOM 1150 OH2 TIP3 1500 -3.797 13.061 16.285 -0.834 1.520 -ATOM 1151 H1 TIP3 1500 -4.660 12.808 16.599 0.417 1.000 -ATOM 1152 H2 TIP3 1500 -3.356 13.638 16.927 0.417 1.000 -ATOM 1153 OH2 TIP3 1501 -14.593 -6.037 14.866 -0.834 1.520 -ATOM 1154 H1 TIP3 1501 -14.345 -5.437 15.653 0.417 1.000 -ATOM 1155 H2 TIP3 1501 -14.797 -6.854 15.256 0.417 1.000 -ATOM 1156 OH2 TIP3 1504 -2.847 5.314 10.166 -0.834 1.520 -ATOM 1157 H1 TIP3 1504 -3.540 5.077 9.558 0.417 1.000 -ATOM 1158 H2 TIP3 1504 -3.248 5.889 10.826 0.417 1.000 -ATOM 1159 OH2 TIP3 1506 -2.533 13.017 18.975 -0.834 1.520 -ATOM 1160 H1 TIP3 1506 -2.452 12.147 18.669 0.417 1.000 -ATOM 1161 H2 TIP3 1506 -1.613 13.298 19.206 0.417 1.000 -ATOM 1162 OH2 TIP3 1512 -9.691 1.500 -8.519 -0.834 1.520 -ATOM 1163 H1 TIP3 1512 -8.986 0.928 -8.815 0.417 1.000 -ATOM 1164 H2 TIP3 1512 -10.405 0.961 -8.817 0.417 1.000 -ATOM 1165 OH2 TIP3 1514 -14.767 13.186 -7.181 -0.834 1.520 -ATOM 1166 H1 TIP3 1514 -13.894 13.436 -7.294 0.417 1.000 -ATOM 1167 H2 TIP3 1514 -15.217 13.261 -8.046 0.417 1.000 -ATOM 1168 OH2 TIP3 1515 -3.311 6.229 -11.711 -0.834 1.520 -ATOM 1169 H1 TIP3 1515 -2.808 5.791 -11.000 0.417 1.000 -ATOM 1170 H2 TIP3 1515 -3.998 6.674 -11.148 0.417 1.000 -ATOM 1171 OH2 TIP3 1518 -15.671 7.006 6.531 -0.834 1.520 -ATOM 1172 H1 TIP3 1518 -15.907 7.925 6.417 0.417 1.000 -ATOM 1173 H2 TIP3 1518 -15.237 7.043 7.393 0.417 1.000 -ATOM 1174 OH2 TIP3 1519 -7.629 9.653 -8.110 -0.834 1.520 -ATOM 1175 H1 TIP3 1519 -6.690 9.891 -8.015 0.417 1.000 -ATOM 1176 H2 TIP3 1519 -8.022 10.381 -7.593 0.417 1.000 -ATOM 1177 OH2 TIP3 1520 -9.511 9.412 16.667 -0.834 1.520 -ATOM 1178 H1 TIP3 1520 -9.677 10.348 16.799 0.417 1.000 -ATOM 1179 H2 TIP3 1520 -10.082 9.212 15.870 0.417 1.000 -ATOM 1180 OH2 TIP3 1522 -14.728 11.045 13.344 -0.834 1.520 -ATOM 1181 H1 TIP3 1522 -13.963 11.028 12.684 0.417 1.000 -ATOM 1182 H2 TIP3 1522 -15.335 10.381 12.941 0.417 1.000 -ATOM 1183 OH2 TIP3 1523 -2.958 9.632 9.680 -0.834 1.520 -ATOM 1184 H1 TIP3 1523 -3.300 10.443 10.183 0.417 1.000 -ATOM 1185 H2 TIP3 1523 -3.187 8.905 10.358 0.417 1.000 -ATOM 1186 OH2 TIP3 1531 -6.622 16.017 -9.909 -0.834 1.520 -ATOM 1187 H1 TIP3 1531 -6.156 16.623 -9.399 0.417 1.000 -ATOM 1188 H2 TIP3 1531 -7.042 16.567 -10.595 0.417 1.000 -ATOM 1189 OH2 TIP3 1532 -6.765 2.943 -4.367 -0.834 1.520 -ATOM 1190 H1 TIP3 1532 -7.387 2.525 -3.806 0.417 1.000 -ATOM 1191 H2 TIP3 1532 -5.973 2.981 -3.820 0.417 1.000 -ATOM 1192 OH2 TIP3 1534 -0.764 12.819 -10.109 -0.834 1.520 -ATOM 1193 H1 TIP3 1534 -0.893 12.085 -10.646 0.417 1.000 -ATOM 1194 H2 TIP3 1534 -0.913 12.479 -9.243 0.417 1.000 -ATOM 1195 OH2 TIP3 1537 -4.414 15.909 -7.076 -0.834 1.520 -ATOM 1196 H1 TIP3 1537 -4.308 16.788 -7.440 0.417 1.000 -ATOM 1197 H2 TIP3 1537 -4.326 15.267 -7.850 0.417 1.000 -ATOM 1198 OH2 TIP3 1538 -4.999 12.510 -6.474 -0.834 1.520 -ATOM 1199 H1 TIP3 1538 -4.923 13.137 -7.235 0.417 1.000 -ATOM 1200 H2 TIP3 1538 -4.144 12.607 -6.037 0.417 1.000 -ATOM 1201 OH2 TIP3 1540 -2.268 14.385 -2.122 -0.834 1.520 -ATOM 1202 H1 TIP3 1540 -2.152 15.369 -1.849 0.417 1.000 -ATOM 1203 H2 TIP3 1540 -2.436 13.930 -1.255 0.417 1.000 -ATOM 1204 OH2 TIP3 1542 -6.426 4.360 4.620 -0.834 1.520 -ATOM 1205 H1 TIP3 1542 -5.835 4.812 3.959 0.417 1.000 -ATOM 1206 H2 TIP3 1542 -6.198 3.408 4.433 0.417 1.000 -ATOM 1207 OH2 TIP3 1543 6.491 19.767 15.452 -0.834 1.520 -ATOM 1208 H1 TIP3 1543 7.199 19.779 16.123 0.417 1.000 -ATOM 1209 H2 TIP3 1543 5.683 19.538 15.992 0.417 1.000 -ATOM 1210 OH2 TIP3 1544 2.184 -12.187 18.081 -0.834 1.520 -ATOM 1211 H1 TIP3 1544 1.493 -12.247 17.334 0.417 1.000 -ATOM 1212 H2 TIP3 1544 2.880 -11.697 17.673 0.417 1.000 -ATOM 1213 OH2 TIP3 1545 -3.285 12.366 13.648 -0.834 1.520 -ATOM 1214 H1 TIP3 1545 -3.649 12.423 14.592 0.417 1.000 -ATOM 1215 H2 TIP3 1545 -3.620 13.270 13.287 0.417 1.000 -ATOM 1216 OH2 TIP3 1546 -18.333 14.715 9.782 -0.834 1.520 -ATOM 1217 H1 TIP3 1546 -18.821 13.940 9.481 0.417 1.000 -ATOM 1218 H2 TIP3 1546 -17.750 14.347 10.478 0.417 1.000 -ATOM 1219 OH2 TIP3 1552 -14.000 12.305 -12.945 -0.834 1.520 -ATOM 1220 H1 TIP3 1552 -14.577 12.996 -13.267 0.417 1.000 -ATOM 1221 H2 TIP3 1552 -13.194 12.807 -12.633 0.417 1.000 -ATOM 1222 OH2 TIP3 1557 -17.966 19.107 4.801 -0.834 1.520 -ATOM 1223 H1 TIP3 1557 -18.711 19.408 4.252 0.417 1.000 -ATOM 1224 H2 TIP3 1557 -17.691 19.946 5.280 0.417 1.000 -ATOM 1225 OH2 TIP3 1559 -13.182 0.066 0.150 -0.834 1.520 -ATOM 1226 H1 TIP3 1559 -12.314 0.067 0.626 0.417 1.000 -ATOM 1227 H2 TIP3 1559 -13.031 -0.131 -0.788 0.417 1.000 -ATOM 1228 OH2 TIP3 1560 2.934 18.275 1.316 -0.834 1.520 -ATOM 1229 H1 TIP3 1560 2.474 17.391 1.397 0.417 1.000 -ATOM 1230 H2 TIP3 1560 2.500 18.687 0.537 0.417 1.000 -ATOM 1231 OH2 TIP3 1582 -2.949 15.779 -4.414 -0.834 1.520 -ATOM 1232 H1 TIP3 1582 -3.828 15.409 -4.301 0.417 1.000 -ATOM 1233 H2 TIP3 1582 -2.402 15.311 -3.746 0.417 1.000 -ATOM 1234 OH2 TIP3 1583 7.440 14.981 -8.254 -0.834 1.520 -ATOM 1235 H1 TIP3 1583 6.738 15.624 -8.575 0.417 1.000 -ATOM 1236 H2 TIP3 1583 7.067 14.537 -7.494 0.417 1.000 -ATOM 1237 OH2 TIP3 1587 -7.464 9.439 9.422 -0.834 1.520 -ATOM 1238 H1 TIP3 1587 -7.753 8.800 8.719 0.417 1.000 -ATOM 1239 H2 TIP3 1587 -6.639 9.655 9.068 0.417 1.000 -ATOM 1240 OH2 TIP3 1589 -18.402 17.055 18.588 -0.834 1.520 -ATOM 1241 H1 TIP3 1589 -18.022 17.799 18.061 0.417 1.000 -ATOM 1242 H2 TIP3 1589 -17.666 16.867 19.246 0.417 1.000 -ATOM 1243 OH2 TIP3 1592 -18.836 2.897 10.118 -0.834 1.520 -ATOM 1244 H1 TIP3 1592 -18.008 2.391 9.989 0.417 1.000 -ATOM 1245 H2 TIP3 1592 -19.494 2.586 9.458 0.417 1.000 -ATOM 1246 OH2 TIP3 1601 -4.685 11.721 0.639 -0.834 1.520 -ATOM 1247 H1 TIP3 1601 -5.285 11.546 -0.089 0.417 1.000 -ATOM 1248 H2 TIP3 1601 -3.987 12.225 0.266 0.417 1.000 -ATOM 1249 OH2 TIP3 1603 -6.204 12.788 8.549 -0.834 1.520 -ATOM 1250 H1 TIP3 1603 -6.912 13.020 7.894 0.417 1.000 -ATOM 1251 H2 TIP3 1603 -5.789 11.989 8.184 0.417 1.000 -ATOM 1252 OH2 TIP3 1611 -12.025 0.030 2.745 -0.834 1.520 -ATOM 1253 H1 TIP3 1611 -11.368 0.654 2.435 0.417 1.000 -ATOM 1254 H2 TIP3 1611 -12.559 0.490 3.501 0.417 1.000 -ATOM 1255 OH2 TIP3 1612 -16.334 15.780 12.993 -0.834 1.520 -ATOM 1256 H1 TIP3 1612 -15.393 15.948 13.319 0.417 1.000 -ATOM 1257 H2 TIP3 1612 -16.525 16.536 12.413 0.417 1.000 -ATOM 1258 OH2 TIP3 1618 -16.156 11.380 -5.086 -0.834 1.520 -ATOM 1259 H1 TIP3 1618 -15.487 11.715 -5.699 0.417 1.000 -ATOM 1260 H2 TIP3 1618 -16.018 10.438 -5.108 0.417 1.000 -ATOM 1261 OH2 TIP3 1624 -16.708 19.264 -3.123 -0.834 1.520 -ATOM 1262 H1 TIP3 1624 -16.277 18.402 -3.057 0.417 1.000 -ATOM 1263 H2 TIP3 1624 -16.075 19.831 -2.724 0.417 1.000 -ATOM 1264 OH2 TIP3 1626 -12.675 17.867 16.364 -0.834 1.520 -ATOM 1265 H1 TIP3 1626 -13.504 18.257 16.693 0.417 1.000 -ATOM 1266 H2 TIP3 1626 -12.115 17.917 17.176 0.417 1.000 -ATOM 1267 OH2 TIP3 1629 -19.451 17.374 14.273 -0.834 1.520 -ATOM 1268 H1 TIP3 1629 -19.619 17.772 13.420 0.417 1.000 -ATOM 1269 H2 TIP3 1629 -19.365 16.466 14.117 0.417 1.000 -ATOM 1270 OH2 TIP3 1638 8.131 13.693 -14.588 -0.834 1.520 -ATOM 1271 H1 TIP3 1638 8.039 12.821 -14.245 0.417 1.000 -ATOM 1272 H2 TIP3 1638 7.481 13.666 -15.332 0.417 1.000 -ATOM 1273 OH2 TIP3 1642 -17.998 12.689 6.857 -0.834 1.520 -ATOM 1274 H1 TIP3 1642 -17.350 13.256 7.437 0.417 1.000 -ATOM 1275 H2 TIP3 1642 -18.216 13.292 6.148 0.417 1.000 -ATOM 1276 OH2 TIP3 1643 -14.426 13.132 -3.286 -0.834 1.520 -ATOM 1277 H1 TIP3 1643 -14.876 12.329 -2.987 0.417 1.000 -ATOM 1278 H2 TIP3 1643 -14.921 13.786 -2.794 0.417 1.000 -ATOM 1279 OH2 TIP3 1670 -9.083 -13.361 8.367 -0.834 1.520 -ATOM 1280 H1 TIP3 1670 -8.359 -13.525 7.708 0.417 1.000 -ATOM 1281 H2 TIP3 1670 -8.861 -13.984 9.056 0.417 1.000 -ATOM 1282 OH2 TIP3 1692 -7.307 -18.670 15.462 -0.834 1.520 -ATOM 1283 H1 TIP3 1692 -6.646 -18.123 15.015 0.417 1.000 -ATOM 1284 H2 TIP3 1692 -6.865 -18.925 16.317 0.417 1.000 -ATOM 1285 OH2 TIP3 1707 -7.887 -19.079 -15.058 -0.834 1.520 -ATOM 1286 H1 TIP3 1707 -7.181 -19.365 -14.438 0.417 1.000 -ATOM 1287 H2 TIP3 1707 -8.186 -18.104 -14.777 0.417 1.000 -ATOM 1288 OH2 TIP3 1718 -14.485 -15.471 12.470 -0.834 1.520 -ATOM 1289 H1 TIP3 1718 -15.397 -15.136 12.559 0.417 1.000 -ATOM 1290 H2 TIP3 1718 -14.518 -15.745 11.597 0.417 1.000 -ATOM 1291 OH2 TIP3 1723 -10.803 -15.625 -4.036 -0.834 1.520 -ATOM 1292 H1 TIP3 1723 -10.837 -16.410 -4.613 0.417 1.000 -ATOM 1293 H2 TIP3 1723 -11.484 -15.833 -3.396 0.417 1.000 -ATOM 1294 OH2 TIP3 1725 -17.579 -16.225 -14.942 -0.834 1.520 -ATOM 1295 H1 TIP3 1725 -17.316 -17.066 -15.348 0.417 1.000 -ATOM 1296 H2 TIP3 1725 -16.781 -15.660 -14.952 0.417 1.000 -ATOM 1297 OH2 TIP3 1727 -1.626 -13.429 4.304 -0.834 1.520 -ATOM 1298 H1 TIP3 1727 -2.370 -13.175 3.710 0.417 1.000 -ATOM 1299 H2 TIP3 1727 -2.027 -14.169 4.860 0.417 1.000 -ATOM 1300 OH2 TIP3 1729 -13.206 -13.125 2.997 -0.834 1.520 -ATOM 1301 H1 TIP3 1729 -12.834 -12.185 3.093 0.417 1.000 -ATOM 1302 H2 TIP3 1729 -14.166 -12.971 3.036 0.417 1.000 -ATOM 1303 OH2 TIP3 1730 -8.482 -17.859 -5.165 -0.834 1.520 -ATOM 1304 H1 TIP3 1730 -8.644 -17.231 -5.899 0.417 1.000 -ATOM 1305 H2 TIP3 1730 -7.655 -18.273 -5.417 0.417 1.000 -ATOM 1306 OH2 TIP3 1733 -16.826 -18.416 -3.024 -0.834 1.520 -ATOM 1307 H1 TIP3 1733 -17.630 -17.923 -3.190 0.417 1.000 -ATOM 1308 H2 TIP3 1733 -16.730 -19.039 -3.748 0.417 1.000 -ATOM 1309 OH2 TIP3 1735 3.583 -10.324 16.567 -0.834 1.520 -ATOM 1310 H1 TIP3 1735 3.123 -9.802 15.925 0.417 1.000 -ATOM 1311 H2 TIP3 1735 4.026 -10.951 16.040 0.417 1.000 -ATOM 1312 OH2 TIP3 1744 -0.181 -18.815 -13.579 -0.834 1.520 -ATOM 1313 H1 TIP3 1744 0.354 -18.357 -14.248 0.417 1.000 -ATOM 1314 H2 TIP3 1744 -0.233 -19.768 -13.901 0.417 1.000 -ATOM 1315 OH2 TIP3 1746 -9.152 -9.929 -1.369 -0.834 1.520 -ATOM 1316 H1 TIP3 1746 -9.655 -9.523 -2.093 0.417 1.000 -ATOM 1317 H2 TIP3 1746 -8.337 -9.449 -1.362 0.417 1.000 -ATOM 1318 OH2 TIP3 1750 -12.939 4.972 -17.457 -0.834 1.520 -ATOM 1319 H1 TIP3 1750 -12.015 5.260 -17.563 0.417 1.000 -ATOM 1320 H2 TIP3 1750 -12.849 4.003 -17.555 0.417 1.000 -ATOM 1321 OH2 TIP3 1752 -7.931 -11.234 3.082 -0.834 1.520 -ATOM 1322 H1 TIP3 1752 -7.977 -10.710 3.888 0.417 1.000 -ATOM 1323 H2 TIP3 1752 -8.410 -12.044 3.400 0.417 1.000 -ATOM 1324 OH2 TIP3 1755 1.084 -16.732 14.355 -0.834 1.520 -ATOM 1325 H1 TIP3 1755 0.432 -17.234 13.844 0.417 1.000 -ATOM 1326 H2 TIP3 1755 0.865 -16.909 15.225 0.417 1.000 -ATOM 1327 OH2 TIP3 1757 -11.286 -9.146 6.340 -0.834 1.520 -ATOM 1328 H1 TIP3 1757 -10.309 -9.440 6.364 0.417 1.000 -ATOM 1329 H2 TIP3 1757 -11.601 -9.189 7.287 0.417 1.000 -ATOM 1330 OH2 TIP3 1764 -14.859 -18.389 -19.501 -0.834 1.520 -ATOM 1331 H1 TIP3 1764 -15.303 -18.890 -18.766 0.417 1.000 -ATOM 1332 H2 TIP3 1764 -13.969 -18.698 -19.414 0.417 1.000 -ATOM 1333 OH2 TIP3 1766 -2.069 -5.628 -8.406 -0.834 1.520 -ATOM 1334 H1 TIP3 1766 -2.990 -5.576 -8.713 0.417 1.000 -ATOM 1335 H2 TIP3 1766 -2.074 -5.044 -7.601 0.417 1.000 -ATOM 1336 OH2 TIP3 1771 -17.491 -16.495 -7.090 -0.834 1.520 -ATOM 1337 H1 TIP3 1771 -17.886 -15.862 -7.685 0.417 1.000 -ATOM 1338 H2 TIP3 1771 -17.285 -17.288 -7.617 0.417 1.000 -ATOM 1339 OH2 TIP3 1772 -6.100 -18.734 11.625 -0.834 1.520 -ATOM 1340 H1 TIP3 1772 -5.368 -19.331 11.842 0.417 1.000 -ATOM 1341 H2 TIP3 1772 -5.733 -18.258 10.831 0.417 1.000 -ATOM 1342 OH2 TIP3 1773 -5.646 -18.648 -5.996 -0.834 1.520 -ATOM 1343 H1 TIP3 1773 -5.306 -19.377 -5.435 0.417 1.000 -ATOM 1344 H2 TIP3 1773 -5.427 -17.805 -5.574 0.417 1.000 -ATOM 1345 OH2 TIP3 1775 -18.087 -18.594 7.668 -0.834 1.520 -ATOM 1346 H1 TIP3 1775 -18.279 -18.573 8.637 0.417 1.000 -ATOM 1347 H2 TIP3 1775 -17.661 -17.701 7.574 0.417 1.000 -ATOM 1348 OH2 TIP3 1776 -12.992 -15.476 16.761 -0.834 1.520 -ATOM 1349 H1 TIP3 1776 -13.730 -14.940 17.088 0.417 1.000 -ATOM 1350 H2 TIP3 1776 -12.255 -14.989 17.135 0.417 1.000 -ATOM 1351 OH2 TIP3 1778 -17.562 -13.996 16.100 -0.834 1.520 -ATOM 1352 H1 TIP3 1778 -18.031 -14.475 16.753 0.417 1.000 -ATOM 1353 H2 TIP3 1778 -18.268 -13.982 15.391 0.417 1.000 -ATOM 1354 OH2 TIP3 1788 -5.422 3.489 -2.150 -0.834 1.520 -ATOM 1355 H1 TIP3 1788 -4.524 3.267 -2.139 0.417 1.000 -ATOM 1356 H2 TIP3 1788 -5.641 3.484 -1.229 0.417 1.000 -ATOM 1357 OH2 TIP3 1789 -14.539 -13.246 -18.057 -0.834 1.520 -ATOM 1358 H1 TIP3 1789 -13.588 -13.373 -17.982 0.417 1.000 -ATOM 1359 H2 TIP3 1789 -14.791 -14.044 -18.566 0.417 1.000 -ATOM 1360 OH2 TIP3 1790 -1.937 -5.563 -3.088 -0.834 1.520 -ATOM 1361 H1 TIP3 1790 -1.261 -6.112 -2.627 0.417 1.000 -ATOM 1362 H2 TIP3 1790 -2.816 -6.023 -3.042 0.417 1.000 -ATOM 1363 OH2 TIP3 1794 -4.701 -18.629 4.731 -0.834 1.520 -ATOM 1364 H1 TIP3 1794 -5.144 -18.285 3.949 0.417 1.000 -ATOM 1365 H2 TIP3 1794 -3.772 -18.473 4.527 0.417 1.000 -ATOM 1366 OH2 TIP3 1795 -5.899 -18.098 2.316 -0.834 1.520 -ATOM 1367 H1 TIP3 1795 -5.114 -17.602 2.002 0.417 1.000 -ATOM 1368 H2 TIP3 1795 -5.892 -18.959 1.813 0.417 1.000 -ATOM 1369 OH2 TIP3 1796 1.008 -14.939 -1.543 -0.834 1.520 -ATOM 1370 H1 TIP3 1796 0.384 -14.979 -0.793 0.417 1.000 -ATOM 1371 H2 TIP3 1796 1.508 -15.790 -1.373 0.417 1.000 -ATOM 1372 OH2 TIP3 1798 -5.880 -1.003 13.901 -0.834 1.520 -ATOM 1373 H1 TIP3 1798 -6.725 -0.812 14.327 0.417 1.000 -ATOM 1374 H2 TIP3 1798 -5.312 -0.203 14.158 0.417 1.000 -ATOM 1375 OH2 TIP3 1808 4.934 -9.881 3.588 -0.834 1.520 -ATOM 1376 H1 TIP3 1808 5.124 -10.621 4.125 0.417 1.000 -ATOM 1377 H2 TIP3 1808 4.257 -9.461 4.069 0.417 1.000 -ATOM 1378 OH2 TIP3 1810 10.667 1.477 -18.568 -0.834 1.520 -ATOM 1379 H1 TIP3 1810 10.600 2.083 -17.781 0.417 1.000 -ATOM 1380 H2 TIP3 1810 9.728 1.243 -18.726 0.417 1.000 -ATOM 1381 OH2 TIP3 1811 10.667 -14.998 -12.111 -0.834 1.520 -ATOM 1382 H1 TIP3 1811 10.007 -14.348 -12.442 0.417 1.000 -ATOM 1383 H2 TIP3 1811 11.404 -14.870 -12.754 0.417 1.000 -ATOM 1384 OH2 TIP3 1812 -14.557 -10.544 8.801 -0.834 1.520 -ATOM 1385 H1 TIP3 1812 -15.371 -10.057 8.641 0.417 1.000 -ATOM 1386 H2 TIP3 1812 -14.873 -11.287 9.296 0.417 1.000 -ATOM 1387 OH2 TIP3 1813 -13.858 -8.142 -3.948 -0.834 1.520 -ATOM 1388 H1 TIP3 1813 -14.238 -7.358 -4.325 0.417 1.000 -ATOM 1389 H2 TIP3 1813 -14.434 -8.854 -4.339 0.417 1.000 -ATOM 1390 OH2 TIP3 1814 -8.813 -0.896 -1.319 -0.834 1.520 -ATOM 1391 H1 TIP3 1814 -7.971 -1.434 -1.137 0.417 1.000 -ATOM 1392 H2 TIP3 1814 -9.426 -1.227 -0.636 0.417 1.000 -ATOM 1393 OH2 TIP3 1815 -12.069 -0.265 8.005 -0.834 1.520 -ATOM 1394 H1 TIP3 1815 -12.770 -0.043 7.391 0.417 1.000 -ATOM 1395 H2 TIP3 1815 -12.157 0.396 8.753 0.417 1.000 -ATOM 1396 OH2 TIP3 1816 -10.095 4.448 1.184 -0.834 1.520 -ATOM 1397 H1 TIP3 1816 -9.546 4.369 2.014 0.417 1.000 -ATOM 1398 H2 TIP3 1816 -10.904 3.987 1.368 0.417 1.000 -ATOM 1399 OH2 TIP3 1817 -0.849 -8.233 16.611 -0.834 1.520 -ATOM 1400 H1 TIP3 1817 -1.631 -8.413 17.199 0.417 1.000 -ATOM 1401 H2 TIP3 1817 -1.284 -8.226 15.731 0.417 1.000 -ATOM 1402 OH2 TIP3 1820 -11.199 -16.666 9.609 -0.834 1.520 -ATOM 1403 H1 TIP3 1820 -11.218 -17.615 9.788 0.417 1.000 -ATOM 1404 H2 TIP3 1820 -10.487 -16.583 8.993 0.417 1.000 -ATOM 1405 OH2 TIP3 1821 -4.060 -8.964 16.024 -0.834 1.520 -ATOM 1406 H1 TIP3 1821 -3.587 -9.337 15.247 0.417 1.000 -ATOM 1407 H2 TIP3 1821 -3.651 -9.497 16.672 0.417 1.000 -ATOM 1408 OH2 TIP3 1824 2.523 -17.842 -18.502 -0.834 1.520 -ATOM 1409 H1 TIP3 1824 2.432 -17.928 -19.454 0.417 1.000 -ATOM 1410 H2 TIP3 1824 2.118 -18.679 -18.139 0.417 1.000 -ATOM 1411 OH2 TIP3 1829 -8.220 -6.491 -19.017 -0.834 1.520 -ATOM 1412 H1 TIP3 1829 -7.689 -6.578 -18.206 0.417 1.000 -ATOM 1413 H2 TIP3 1829 -7.621 -6.184 -19.700 0.417 1.000 -ATOM 1414 OH2 TIP3 1830 -6.590 -6.204 -16.794 -0.834 1.520 -ATOM 1415 H1 TIP3 1830 -7.140 -6.658 -16.048 0.417 1.000 -ATOM 1416 H2 TIP3 1830 -5.622 -6.376 -16.514 0.417 1.000 -ATOM 1417 OH2 TIP3 1831 -12.686 -19.772 -10.848 -0.834 1.520 -ATOM 1418 H1 TIP3 1831 -12.553 -19.804 -11.843 0.417 1.000 -ATOM 1419 H2 TIP3 1831 -11.781 -19.664 -10.574 0.417 1.000 -ATOM 1420 OH2 TIP3 1832 -1.569 -10.142 1.140 -0.834 1.520 -ATOM 1421 H1 TIP3 1832 -1.780 -10.080 0.160 0.417 1.000 -ATOM 1422 H2 TIP3 1832 -0.997 -10.962 1.186 0.417 1.000 -ATOM 1423 OH2 TIP3 1833 -10.061 -9.807 17.050 -0.834 1.520 -ATOM 1424 H1 TIP3 1833 -9.895 -9.246 17.880 0.417 1.000 -ATOM 1425 H2 TIP3 1833 -9.832 -9.166 16.364 0.417 1.000 -ATOM 1426 OH2 TIP3 1835 -8.394 7.709 -2.393 -0.834 1.520 -ATOM 1427 H1 TIP3 1835 -8.304 6.784 -2.445 0.417 1.000 -ATOM 1428 H2 TIP3 1835 -8.154 7.850 -1.482 0.417 1.000 -ATOM 1429 OH2 TIP3 1836 -4.069 -9.860 2.479 -0.834 1.520 -ATOM 1430 H1 TIP3 1836 -3.196 -10.049 2.187 0.417 1.000 -ATOM 1431 H2 TIP3 1836 -4.547 -9.573 1.645 0.417 1.000 -ATOM 1432 OH2 TIP3 1837 -10.737 8.274 -7.577 -0.834 1.520 -ATOM 1433 H1 TIP3 1837 -11.054 8.886 -6.952 0.417 1.000 -ATOM 1434 H2 TIP3 1837 -11.203 8.532 -8.415 0.417 1.000 -ATOM 1435 OH2 TIP3 1838 1.198 -8.648 2.162 -0.834 1.520 -ATOM 1436 H1 TIP3 1838 1.433 -9.350 2.754 0.417 1.000 -ATOM 1437 H2 TIP3 1838 0.481 -8.941 1.590 0.417 1.000 -ATOM 1438 OH2 TIP3 1839 -5.597 -13.162 13.628 -0.834 1.520 -ATOM 1439 H1 TIP3 1839 -6.386 -13.482 13.273 0.417 1.000 -ATOM 1440 H2 TIP3 1839 -5.113 -13.994 13.778 0.417 1.000 -ATOM 1441 OH2 TIP3 1840 5.717 -2.953 11.584 -0.834 1.520 -ATOM 1442 H1 TIP3 1840 5.864 -2.065 11.383 0.417 1.000 -ATOM 1443 H2 TIP3 1840 6.567 -3.411 11.607 0.417 1.000 -ATOM 1444 OH2 TIP3 1841 -6.526 -5.814 18.781 -0.834 1.520 -ATOM 1445 H1 TIP3 1841 -7.234 -5.207 19.131 0.417 1.000 -ATOM 1446 H2 TIP3 1841 -6.012 -5.149 18.339 0.417 1.000 -ATOM 1447 OH2 TIP3 1847 -6.620 9.030 -17.190 -0.834 1.520 -ATOM 1448 H1 TIP3 1847 -7.330 9.133 -16.514 0.417 1.000 -ATOM 1449 H2 TIP3 1847 -6.806 9.795 -17.817 0.417 1.000 -ATOM 1450 OH2 TIP3 1850 -9.299 4.822 -12.461 -0.834 1.520 -ATOM 1451 H1 TIP3 1850 -8.375 4.508 -12.384 0.417 1.000 -ATOM 1452 H2 TIP3 1850 -9.623 4.718 -11.524 0.417 1.000 -ATOM 1453 OH2 TIP3 1851 0.846 0.362 -15.259 -0.834 1.520 -ATOM 1454 H1 TIP3 1851 0.810 0.846 -14.356 0.417 1.000 -ATOM 1455 H2 TIP3 1851 0.840 -0.611 -15.065 0.417 1.000 -ATOM 1456 OH2 TIP3 1852 -9.972 4.028 -9.993 -0.834 1.520 -ATOM 1457 H1 TIP3 1852 -9.925 3.132 -9.576 0.417 1.000 -ATOM 1458 H2 TIP3 1852 -9.960 4.627 -9.215 0.417 1.000 -ATOM 1459 OH2 TIP3 1853 -19.711 -9.462 -6.532 -0.834 1.520 -ATOM 1460 H1 TIP3 1853 -19.714 -9.063 -7.398 0.417 1.000 -ATOM 1461 H2 TIP3 1853 -18.738 -9.643 -6.331 0.417 1.000 -ATOM 1462 OH2 TIP3 1854 -3.786 -12.153 -15.234 -0.834 1.520 -ATOM 1463 H1 TIP3 1854 -4.746 -12.008 -14.839 0.417 1.000 -ATOM 1464 H2 TIP3 1854 -4.095 -12.608 -16.004 0.417 1.000 -ATOM 1465 OH2 TIP3 1856 -7.560 -7.593 -14.630 -0.834 1.520 -ATOM 1466 H1 TIP3 1856 -8.348 -8.113 -14.895 0.417 1.000 -ATOM 1467 H2 TIP3 1856 -7.107 -8.133 -14.023 0.417 1.000 -ATOM 1468 OH2 TIP3 1858 -16.664 -12.238 14.144 -0.834 1.520 -ATOM 1469 H1 TIP3 1858 -17.444 -12.364 13.586 0.417 1.000 -ATOM 1470 H2 TIP3 1858 -16.795 -12.882 14.833 0.417 1.000 -ATOM 1471 OH2 TIP3 1859 -15.649 -12.220 10.737 -0.834 1.520 -ATOM 1472 H1 TIP3 1859 -16.581 -12.269 11.041 0.417 1.000 -ATOM 1473 H2 TIP3 1859 -15.250 -12.906 11.271 0.417 1.000 -ATOM 1474 OH2 TIP3 1860 -8.664 -2.573 5.469 -0.834 1.520 -ATOM 1475 H1 TIP3 1860 -7.881 -2.952 5.850 0.417 1.000 -ATOM 1476 H2 TIP3 1860 -8.757 -3.114 4.615 0.417 1.000 -ATOM 1477 OH2 TIP3 1861 -1.303 -3.425 3.068 -0.834 1.520 -ATOM 1478 H1 TIP3 1861 -1.992 -3.221 3.727 0.417 1.000 -ATOM 1479 H2 TIP3 1861 -1.772 -4.017 2.454 0.417 1.000 -ATOM 1480 OH2 TIP3 1862 15.117 -15.618 13.692 -0.834 1.520 -ATOM 1481 H1 TIP3 1862 14.931 -16.509 13.482 0.417 1.000 -ATOM 1482 H2 TIP3 1862 15.883 -15.701 14.254 0.417 1.000 -ATOM 1483 OH2 TIP3 1866 -7.163 -4.566 9.756 -0.834 1.520 -ATOM 1484 H1 TIP3 1866 -7.336 -3.576 9.827 0.417 1.000 -ATOM 1485 H2 TIP3 1866 -8.058 -4.939 9.951 0.417 1.000 -ATOM 1486 OH2 TIP3 1870 -1.188 9.340 -17.251 -0.834 1.520 -ATOM 1487 H1 TIP3 1870 -1.117 9.394 -16.323 0.417 1.000 -ATOM 1488 H2 TIP3 1870 -2.069 8.859 -17.453 0.417 1.000 -ATOM 1489 OH2 TIP3 1871 -13.032 -8.371 -17.647 -0.834 1.520 -ATOM 1490 H1 TIP3 1871 -13.425 -9.104 -18.193 0.417 1.000 -ATOM 1491 H2 TIP3 1871 -12.917 -7.710 -18.410 0.417 1.000 -ATOM 1492 OH2 TIP3 1872 10.797 -4.682 -13.217 -0.834 1.520 -ATOM 1493 H1 TIP3 1872 11.156 -3.952 -12.761 0.417 1.000 -ATOM 1494 H2 TIP3 1872 10.134 -4.353 -13.790 0.417 1.000 -ATOM 1495 OH2 TIP3 1873 -6.467 -9.450 -12.840 -0.834 1.520 -ATOM 1496 H1 TIP3 1873 -7.392 -9.691 -12.510 0.417 1.000 -ATOM 1497 H2 TIP3 1873 -5.992 -9.060 -12.075 0.417 1.000 -ATOM 1498 OH2 TIP3 1874 -6.957 -1.169 2.933 -0.834 1.520 -ATOM 1499 H1 TIP3 1874 -6.561 -2.064 2.986 0.417 1.000 -ATOM 1500 H2 TIP3 1874 -7.861 -1.236 3.145 0.417 1.000 -ATOM 1501 OH2 TIP3 1875 -7.132 4.879 -15.674 -0.834 1.520 -ATOM 1502 H1 TIP3 1875 -6.822 5.390 -14.883 0.417 1.000 -ATOM 1503 H2 TIP3 1875 -6.811 4.009 -15.497 0.417 1.000 -ATOM 1504 OH2 TIP3 1876 -9.869 8.853 1.944 -0.834 1.520 -ATOM 1505 H1 TIP3 1876 -10.567 9.536 2.151 0.417 1.000 -ATOM 1506 H2 TIP3 1876 -9.650 8.482 2.801 0.417 1.000 -ATOM 1507 OH2 TIP3 1877 2.780 12.600 -3.433 -0.834 1.520 -ATOM 1508 H1 TIP3 1877 2.151 12.517 -2.703 0.417 1.000 -ATOM 1509 H2 TIP3 1877 3.032 11.657 -3.633 0.417 1.000 -ATOM 1510 OH2 TIP3 1878 3.306 -12.189 2.076 -0.834 1.520 -ATOM 1511 H1 TIP3 1878 2.635 -12.114 2.789 0.417 1.000 -ATOM 1512 H2 TIP3 1878 3.960 -12.834 2.410 0.417 1.000 -ATOM 1513 OH2 TIP3 1880 -19.664 -6.521 13.304 -0.834 1.520 -ATOM 1514 H1 TIP3 1880 -19.936 -6.277 12.406 0.417 1.000 -ATOM 1515 H2 TIP3 1880 -18.688 -6.483 13.284 0.417 1.000 -ATOM 1516 OH2 TIP3 1881 -2.292 0.770 -7.131 -0.834 1.520 -ATOM 1517 H1 TIP3 1881 -3.296 0.781 -7.220 0.417 1.000 -ATOM 1518 H2 TIP3 1881 -2.106 -0.052 -6.677 0.417 1.000 -ATOM 1519 OH2 TIP3 1883 -12.137 3.614 15.172 -0.834 1.520 -ATOM 1520 H1 TIP3 1883 -12.664 3.211 15.892 0.417 1.000 -ATOM 1521 H2 TIP3 1883 -11.620 4.370 15.576 0.417 1.000 -ATOM 1522 OH2 TIP3 1885 4.964 -6.124 -17.131 -0.834 1.520 -ATOM 1523 H1 TIP3 1885 4.211 -6.801 -17.127 0.417 1.000 -ATOM 1524 H2 TIP3 1885 5.157 -5.944 -18.090 0.417 1.000 -ATOM 1525 OH2 TIP3 1891 -8.938 9.274 -15.814 -0.834 1.520 -ATOM 1526 H1 TIP3 1891 -9.767 9.104 -15.328 0.417 1.000 -ATOM 1527 H2 TIP3 1891 -8.264 9.011 -15.161 0.417 1.000 -ATOM 1528 OH2 TIP3 1892 -15.121 14.045 -10.003 -0.834 1.520 -ATOM 1529 H1 TIP3 1892 -14.817 14.410 -10.863 0.417 1.000 -ATOM 1530 H2 TIP3 1892 -14.645 14.696 -9.366 0.417 1.000 -ATOM 1531 OH2 TIP3 1894 -8.294 -4.189 -3.171 -0.834 1.520 -ATOM 1532 H1 TIP3 1894 -9.108 -3.653 -3.410 0.417 1.000 -ATOM 1533 H2 TIP3 1894 -7.656 -3.534 -2.838 0.417 1.000 -ATOM 1534 OH2 TIP3 1895 6.537 -6.096 -4.508 -0.834 1.520 -ATOM 1535 H1 TIP3 1895 6.365 -5.498 -3.823 0.417 1.000 -ATOM 1536 H2 TIP3 1895 7.409 -6.518 -4.307 0.417 1.000 -ATOM 1537 OH2 TIP3 1896 3.194 0.211 -9.587 -0.834 1.520 -ATOM 1538 H1 TIP3 1896 3.287 -0.138 -8.660 0.417 1.000 -ATOM 1539 H2 TIP3 1896 3.903 0.869 -9.727 0.417 1.000 -ATOM 1540 OH2 TIP3 1897 -17.001 3.837 0.047 -0.834 1.520 -ATOM 1541 H1 TIP3 1897 -17.415 4.567 -0.381 0.417 1.000 -ATOM 1542 H2 TIP3 1897 -16.033 3.961 -0.137 0.417 1.000 -ATOM 1543 OH2 TIP3 1898 -16.276 5.584 3.543 -0.834 1.520 -ATOM 1544 H1 TIP3 1898 -16.065 6.464 3.222 0.417 1.000 -ATOM 1545 H2 TIP3 1898 -15.690 5.508 4.314 0.417 1.000 -ATOM 1546 OH2 TIP3 1899 -3.739 -2.221 15.664 -0.834 1.520 -ATOM 1547 H1 TIP3 1899 -2.936 -2.009 15.207 0.417 1.000 -ATOM 1548 H2 TIP3 1899 -4.393 -1.736 15.157 0.417 1.000 -ATOM 1549 OH2 TIP3 1900 -5.479 -3.404 4.056 -0.834 1.520 -ATOM 1550 H1 TIP3 1900 -5.626 -4.000 4.808 0.417 1.000 -ATOM 1551 H2 TIP3 1900 -5.945 -3.868 3.347 0.417 1.000 -ATOM 1552 OH2 TIP3 1901 -8.459 -3.672 14.335 -0.834 1.520 -ATOM 1553 H1 TIP3 1901 -8.693 -3.158 15.143 0.417 1.000 -ATOM 1554 H2 TIP3 1901 -7.488 -3.790 14.437 0.417 1.000 -ATOM 1555 OH2 TIP3 1902 -10.571 1.891 13.233 -0.834 1.520 -ATOM 1556 H1 TIP3 1902 -10.952 2.477 13.914 0.417 1.000 -ATOM 1557 H2 TIP3 1902 -10.056 2.530 12.713 0.417 1.000 -ATOM 1558 OH2 TIP3 1907 0.732 -4.433 17.945 -0.834 1.520 -ATOM 1559 H1 TIP3 1907 0.341 -4.361 17.048 0.417 1.000 -ATOM 1560 H2 TIP3 1907 1.017 -5.336 17.919 0.417 1.000 -ATOM 1561 OH2 TIP3 1911 -8.358 -0.970 -15.134 -0.834 1.520 -ATOM 1562 H1 TIP3 1911 -9.248 -1.214 -14.791 0.417 1.000 -ATOM 1563 H2 TIP3 1911 -8.466 -0.853 -16.103 0.417 1.000 -ATOM 1564 OH2 TIP3 1912 -6.450 1.522 -10.435 -0.834 1.520 -ATOM 1565 H1 TIP3 1912 -6.721 1.744 -11.345 0.417 1.000 -ATOM 1566 H2 TIP3 1912 -6.141 2.419 -10.086 0.417 1.000 -ATOM 1567 OH2 TIP3 1913 1.097 12.860 -15.300 -0.834 1.520 -ATOM 1568 H1 TIP3 1913 0.853 13.778 -15.395 0.417 1.000 -ATOM 1569 H2 TIP3 1913 0.276 12.355 -15.391 0.417 1.000 -ATOM 1570 OH2 TIP3 1914 -7.999 0.877 -5.892 -0.834 1.520 -ATOM 1571 H1 TIP3 1914 -7.940 1.566 -5.226 0.417 1.000 -ATOM 1572 H2 TIP3 1914 -8.814 1.104 -6.371 0.417 1.000 -ATOM 1573 OH2 TIP3 1915 -7.186 -2.094 -12.617 -0.834 1.520 -ATOM 1574 H1 TIP3 1915 -6.621 -2.590 -13.312 0.417 1.000 -ATOM 1575 H2 TIP3 1915 -8.037 -2.006 -13.046 0.417 1.000 -ATOM 1576 OH2 TIP3 1916 -10.837 14.477 4.848 -0.834 1.520 -ATOM 1577 H1 TIP3 1916 -10.206 13.719 4.654 0.417 1.000 -ATOM 1578 H2 TIP3 1916 -11.499 14.351 4.107 0.417 1.000 -ATOM 1579 OH2 TIP3 1918 -18.636 14.101 -10.624 -0.834 1.520 -ATOM 1580 H1 TIP3 1918 -19.578 14.237 -10.695 0.417 1.000 -ATOM 1581 H2 TIP3 1918 -18.247 14.697 -11.307 0.417 1.000 -ATOM 1582 OH2 TIP3 1919 -5.991 5.677 1.729 -0.834 1.520 -ATOM 1583 H1 TIP3 1919 -5.731 4.939 1.201 0.417 1.000 -ATOM 1584 H2 TIP3 1919 -6.828 5.892 1.272 0.417 1.000 -ATOM 1585 OH2 TIP3 1920 -9.504 -1.732 16.274 -0.834 1.520 -ATOM 1586 H1 TIP3 1920 -9.534 -1.267 17.138 0.417 1.000 -ATOM 1587 H2 TIP3 1920 -10.283 -2.299 16.279 0.417 1.000 -ATOM 1588 OH2 TIP3 1922 2.183 -6.931 10.851 -0.834 1.520 -ATOM 1589 H1 TIP3 1922 2.615 -6.077 10.919 0.417 1.000 -ATOM 1590 H2 TIP3 1922 2.806 -7.386 10.265 0.417 1.000 -ATOM 1591 OH2 TIP3 1923 -11.890 10.743 2.992 -0.834 1.520 -ATOM 1592 H1 TIP3 1923 -12.832 10.903 2.969 0.417 1.000 -ATOM 1593 H2 TIP3 1923 -11.794 10.251 3.816 0.417 1.000 -ATOM 1594 OH2 TIP3 1924 -2.643 12.575 5.351 -0.834 1.520 -ATOM 1595 H1 TIP3 1924 -3.299 13.201 4.994 0.417 1.000 -ATOM 1596 H2 TIP3 1924 -1.975 13.149 5.772 0.417 1.000 -ATOM 1597 OH2 TIP3 1925 -15.575 1.890 18.126 -0.834 1.520 -ATOM 1598 H1 TIP3 1925 -15.751 1.639 19.106 0.417 1.000 -ATOM 1599 H2 TIP3 1925 -16.079 1.119 17.675 0.417 1.000 -ATOM 1600 OH2 TIP3 1934 -2.567 14.841 -15.855 -0.834 1.520 -ATOM 1601 H1 TIP3 1934 -3.249 15.502 -15.543 0.417 1.000 -ATOM 1602 H2 TIP3 1934 -3.028 14.395 -16.596 0.417 1.000 -ATOM 1603 OH2 TIP3 1935 -2.005 5.202 -9.577 -0.834 1.520 -ATOM 1604 H1 TIP3 1935 -1.147 5.548 -9.739 0.417 1.000 -ATOM 1605 H2 TIP3 1935 -1.842 4.442 -8.926 0.417 1.000 -ATOM 1606 OH2 TIP3 1936 -4.312 5.619 -4.974 -0.834 1.520 -ATOM 1607 H1 TIP3 1936 -5.292 5.775 -5.087 0.417 1.000 -ATOM 1608 H2 TIP3 1936 -4.274 4.688 -5.303 0.417 1.000 -ATOM 1609 OH2 TIP3 1937 -8.556 9.458 -4.532 -0.834 1.520 -ATOM 1610 H1 TIP3 1937 -8.311 9.004 -3.728 0.417 1.000 -ATOM 1611 H2 TIP3 1937 -9.486 9.271 -4.551 0.417 1.000 -ATOM 1612 OH2 TIP3 1938 -3.989 -14.895 1.062 -0.834 1.520 -ATOM 1613 H1 TIP3 1938 -3.911 -15.833 1.099 0.417 1.000 -ATOM 1614 H2 TIP3 1938 -4.866 -14.848 0.694 0.417 1.000 -ATOM 1615 OH2 TIP3 1939 -17.322 11.993 3.775 -0.834 1.520 -ATOM 1616 H1 TIP3 1939 -17.819 11.299 4.246 0.417 1.000 -ATOM 1617 H2 TIP3 1939 -18.064 12.527 3.342 0.417 1.000 -ATOM 1618 OH2 TIP3 1940 -0.923 -3.763 11.800 -0.834 1.520 -ATOM 1619 H1 TIP3 1940 -1.492 -3.933 10.961 0.417 1.000 -ATOM 1620 H2 TIP3 1940 -0.095 -3.448 11.352 0.417 1.000 -ATOM 1621 OH2 TIP3 1941 -3.741 -1.558 8.650 -0.834 1.520 -ATOM 1622 H1 TIP3 1941 -3.953 -1.183 9.527 0.417 1.000 -ATOM 1623 H2 TIP3 1941 -3.478 -0.771 8.190 0.417 1.000 -ATOM 1624 OH2 TIP3 1942 -2.708 16.170 16.891 -0.834 1.520 -ATOM 1625 H1 TIP3 1942 -2.724 16.320 17.868 0.417 1.000 -ATOM 1626 H2 TIP3 1942 -3.571 16.626 16.655 0.417 1.000 -ATOM 1627 OH2 TIP3 1943 -0.442 8.328 18.936 -0.834 1.520 -ATOM 1628 H1 TIP3 1943 -0.864 8.281 18.086 0.417 1.000 -ATOM 1629 H2 TIP3 1943 -1.186 8.573 19.541 0.417 1.000 -ATOM 1630 OH2 TIP3 1946 -11.257 18.619 12.721 -0.834 1.520 -ATOM 1631 H1 TIP3 1946 -11.058 18.923 13.577 0.417 1.000 -ATOM 1632 H2 TIP3 1946 -11.002 17.661 12.717 0.417 1.000 -ATOM 1633 OH2 TIP3 1948 -8.810 -7.634 19.187 -0.834 1.520 -ATOM 1634 H1 TIP3 1948 -8.799 -8.186 19.956 0.417 1.000 -ATOM 1635 H2 TIP3 1948 -7.880 -7.309 19.132 0.417 1.000 -ATOM 1636 OH2 TIP3 1949 -17.129 0.653 9.415 -0.834 1.520 -ATOM 1637 H1 TIP3 1949 -16.885 -0.221 9.135 0.417 1.000 -ATOM 1638 H2 TIP3 1949 -17.883 0.410 9.894 0.417 1.000 -ATOM 1639 OH2 TIP3 1950 -4.268 8.840 -15.046 -0.834 1.520 -ATOM 1640 H1 TIP3 1950 -5.208 9.023 -15.188 0.417 1.000 -ATOM 1641 H2 TIP3 1950 -4.095 8.211 -15.757 0.417 1.000 -ATOM 1642 OH2 TIP3 1952 -4.011 -0.249 -15.138 -0.834 1.520 -ATOM 1643 H1 TIP3 1952 -4.048 0.632 -15.540 0.417 1.000 -ATOM 1644 H2 TIP3 1952 -4.443 -0.790 -15.812 0.417 1.000 -ATOM 1645 OH2 TIP3 1953 -8.866 12.630 -16.006 -0.834 1.520 -ATOM 1646 H1 TIP3 1953 -9.542 12.295 -15.277 0.417 1.000 -ATOM 1647 H2 TIP3 1953 -8.833 13.577 -15.879 0.417 1.000 -ATOM 1648 OH2 TIP3 1954 -9.795 10.663 -11.399 -0.834 1.520 -ATOM 1649 H1 TIP3 1954 -9.771 10.950 -10.452 0.417 1.000 -ATOM 1650 H2 TIP3 1954 -9.056 10.051 -11.491 0.417 1.000 -ATOM 1651 OH2 TIP3 1955 -13.615 5.655 -12.517 -0.834 1.520 -ATOM 1652 H1 TIP3 1955 -13.415 5.839 -13.461 0.417 1.000 -ATOM 1653 H2 TIP3 1955 -14.275 6.337 -12.270 0.417 1.000 -ATOM 1654 OH2 TIP3 1961 -8.983 3.800 3.596 -0.834 1.520 -ATOM 1655 H1 TIP3 1961 -9.236 3.363 4.471 0.417 1.000 -ATOM 1656 H2 TIP3 1961 -8.032 4.032 3.763 0.417 1.000 -ATOM 1657 OH2 TIP3 1962 -3.147 9.921 4.396 -0.834 1.520 -ATOM 1658 H1 TIP3 1962 -3.759 10.299 3.746 0.417 1.000 -ATOM 1659 H2 TIP3 1962 -2.915 10.590 5.060 0.417 1.000 -ATOM 1660 OH2 TIP3 1963 1.960 13.969 13.910 -0.834 1.520 -ATOM 1661 H1 TIP3 1963 2.544 13.341 14.372 0.417 1.000 -ATOM 1662 H2 TIP3 1963 1.055 13.872 14.298 0.417 1.000 -ATOM 1663 OH2 TIP3 1965 -17.882 -7.577 15.784 -0.834 1.520 -ATOM 1664 H1 TIP3 1965 -18.643 -8.169 15.813 0.417 1.000 -ATOM 1665 H2 TIP3 1965 -17.560 -7.729 14.837 0.417 1.000 -ATOM 1666 OH2 TIP3 1967 -14.082 -4.166 9.930 -0.834 1.520 -ATOM 1667 H1 TIP3 1967 -13.393 -3.443 9.684 0.417 1.000 -ATOM 1668 H2 TIP3 1967 -14.172 -4.191 10.917 0.417 1.000 -ATOM 1669 OH2 TIP3 1976 0.293 14.856 -18.461 -0.834 1.520 -ATOM 1670 H1 TIP3 1976 0.002 14.771 -19.393 0.417 1.000 -ATOM 1671 H2 TIP3 1976 -0.071 14.068 -18.034 0.417 1.000 -ATOM 1672 OH2 TIP3 1977 3.688 3.202 -15.897 -0.834 1.520 -ATOM 1673 H1 TIP3 1977 3.403 2.394 -16.449 0.417 1.000 -ATOM 1674 H2 TIP3 1977 3.793 3.867 -16.621 0.417 1.000 -ATOM 1675 OH2 TIP3 1979 0.290 19.044 -4.402 -0.834 1.520 -ATOM 1676 H1 TIP3 1979 -0.666 19.056 -4.347 0.417 1.000 -ATOM 1677 H2 TIP3 1979 0.536 19.607 -5.161 0.417 1.000 -ATOM 1678 OH2 TIP3 1980 -7.219 12.593 11.693 -0.834 1.520 -ATOM 1679 H1 TIP3 1980 -8.070 12.353 11.168 0.417 1.000 -ATOM 1680 H2 TIP3 1980 -6.924 13.438 11.352 0.417 1.000 -ATOM 1681 OH2 TIP3 1982 -1.033 6.471 16.810 -0.834 1.520 -ATOM 1682 H1 TIP3 1982 -0.864 5.649 17.228 0.417 1.000 -ATOM 1683 H2 TIP3 1982 -1.290 6.229 15.951 0.417 1.000 -ATOM 1684 OH2 TIP3 1984 -10.044 11.919 17.094 -0.834 1.520 -ATOM 1685 H1 TIP3 1984 -9.839 12.883 17.257 0.417 1.000 -ATOM 1686 H2 TIP3 1984 -10.116 11.612 18.042 0.417 1.000 -ATOM 1687 OH2 TIP3 1986 -12.087 17.648 9.840 -0.834 1.520 -ATOM 1688 H1 TIP3 1986 -11.545 18.374 9.431 0.417 1.000 -ATOM 1689 H2 TIP3 1986 -12.019 17.883 10.756 0.417 1.000 -ATOM 1690 OH2 TIP3 1987 -5.591 -0.672 5.695 -0.834 1.520 -ATOM 1691 H1 TIP3 1987 -5.747 -0.940 6.626 0.417 1.000 -ATOM 1692 H2 TIP3 1987 -6.207 -1.191 5.183 0.417 1.000 -ATOM 1693 OH2 TIP3 1988 2.230 8.195 19.629 -0.834 1.520 -ATOM 1694 H1 TIP3 1988 2.614 7.339 19.356 0.417 1.000 -ATOM 1695 H2 TIP3 1988 1.337 8.266 19.164 0.417 1.000 -ATOM 1696 OH2 TIP3 1989 -0.265 17.590 15.776 -0.834 1.520 -ATOM 1697 H1 TIP3 1989 -0.976 17.031 15.347 0.417 1.000 -ATOM 1698 H2 TIP3 1989 -0.736 18.245 16.281 0.417 1.000 -ATOM 1699 OH2 TIP3 1993 2.691 9.073 -13.850 -0.834 1.520 -ATOM 1700 H1 TIP3 1993 3.249 8.638 -14.462 0.417 1.000 -ATOM 1701 H2 TIP3 1993 2.694 8.441 -13.081 0.417 1.000 -ATOM 1702 OH2 TIP3 1998 -10.258 15.426 -11.763 -0.834 1.520 -ATOM 1703 H1 TIP3 1998 -9.767 15.615 -10.952 0.417 1.000 -ATOM 1704 H2 TIP3 1998 -9.577 15.170 -12.483 0.417 1.000 -ATOM 1705 OH2 TIP3 1999 -10.521 13.182 1.768 -0.834 1.520 -ATOM 1706 H1 TIP3 1999 -11.307 13.725 1.761 0.417 1.000 -ATOM 1707 H2 TIP3 1999 -10.814 12.339 2.131 0.417 1.000 -ATOM 1708 OH2 TIP3 2002 -4.653 10.170 -7.971 -0.834 1.520 -ATOM 1709 H1 TIP3 2002 -4.265 9.648 -8.701 0.417 1.000 -ATOM 1710 H2 TIP3 2002 -3.918 10.398 -7.418 0.417 1.000 -ATOM 1711 OH2 TIP3 2003 -10.261 11.436 6.578 -0.834 1.520 -ATOM 1712 H1 TIP3 2003 -10.819 10.653 6.654 0.417 1.000 -ATOM 1713 H2 TIP3 2003 -9.862 11.376 5.663 0.417 1.000 -ATOM 1714 OH2 TIP3 2009 0.569 -0.349 18.788 -0.834 1.520 -ATOM 1715 H1 TIP3 2009 0.947 -1.166 19.205 0.417 1.000 -ATOM 1716 H2 TIP3 2009 0.693 -0.485 17.847 0.417 1.000 -ATOM 1717 OH2 TIP3 2014 -3.319 13.631 -18.200 -0.834 1.520 -ATOM 1718 H1 TIP3 2014 -3.374 13.886 -19.115 0.417 1.000 -ATOM 1719 H2 TIP3 2014 -4.118 13.213 -17.996 0.417 1.000 -ATOM 1720 OH2 TIP3 2018 -6.159 19.123 -9.510 -0.834 1.520 -ATOM 1721 H1 TIP3 2018 -5.738 19.328 -10.337 0.417 1.000 -ATOM 1722 H2 TIP3 2018 -6.643 19.915 -9.274 0.417 1.000 -ATOM 1723 OH2 TIP3 2020 0.221 11.597 7.386 -0.834 1.520 -ATOM 1724 H1 TIP3 2020 0.133 11.804 8.277 0.417 1.000 -ATOM 1725 H2 TIP3 2020 0.202 10.634 7.321 0.417 1.000 -ATOM 1726 OH2 TIP3 2021 -6.150 11.054 -4.066 -0.834 1.520 -ATOM 1727 H1 TIP3 2021 -5.824 11.533 -4.844 0.417 1.000 -ATOM 1728 H2 TIP3 2021 -6.692 10.414 -4.550 0.417 1.000 -ATOM 1729 OH2 TIP3 2022 -16.341 16.945 -6.365 -0.834 1.520 -ATOM 1730 H1 TIP3 2022 -16.631 16.694 -7.252 0.417 1.000 -ATOM 1731 H2 TIP3 2022 -15.389 16.868 -6.432 0.417 1.000 -ATOM 1732 OH2 TIP3 2025 -16.274 14.553 4.475 -0.834 1.520 -ATOM 1733 H1 TIP3 2025 -15.892 14.814 3.599 0.417 1.000 -ATOM 1734 H2 TIP3 2025 -16.633 13.696 4.203 0.417 1.000 -ATOM 1735 OH2 TIP3 2026 5.565 12.679 17.388 -0.834 1.520 -ATOM 1736 H1 TIP3 2026 6.267 12.035 17.075 0.417 1.000 -ATOM 1737 H2 TIP3 2026 5.491 13.252 16.591 0.417 1.000 -ATOM 1738 OH2 TIP3 2031 9.438 16.373 18.993 -0.834 1.520 -ATOM 1739 H1 TIP3 2031 9.976 16.804 18.343 0.417 1.000 -ATOM 1740 H2 TIP3 2031 10.075 16.399 19.741 0.417 1.000 -ATOM 1741 OH2 TIP3 2037 -7.470 17.675 -12.217 -0.834 1.520 -ATOM 1742 H1 TIP3 2037 -6.758 18.363 -12.110 0.417 1.000 -ATOM 1743 H2 TIP3 2037 -8.324 18.280 -12.242 0.417 1.000 -ATOM 1744 OH2 TIP3 2039 2.501 18.806 -19.404 -0.834 1.520 -ATOM 1745 H1 TIP3 2039 1.645 18.424 -19.104 0.417 1.000 -ATOM 1746 H2 TIP3 2039 2.458 19.666 -18.894 0.417 1.000 -ATOM 1747 OH2 TIP3 2040 -7.838 17.850 -16.009 -0.834 1.520 -ATOM 1748 H1 TIP3 2040 -7.166 18.534 -15.664 0.417 1.000 -ATOM 1749 H2 TIP3 2040 -8.684 18.141 -15.559 0.417 1.000 -ATOM 1750 OH2 TIP3 2042 1.676 16.469 -4.678 -0.834 1.520 -ATOM 1751 H1 TIP3 2042 1.602 16.118 -3.791 0.417 1.000 -ATOM 1752 H2 TIP3 2042 1.363 17.388 -4.652 0.417 1.000 -ATOM 1753 OH2 TIP3 2043 15.399 18.905 -8.489 -0.834 1.520 -ATOM 1754 H1 TIP3 2043 15.834 18.074 -8.723 0.417 1.000 -ATOM 1755 H2 TIP3 2043 15.700 19.072 -7.575 0.417 1.000 -ATOM 1756 OH2 TIP3 2044 -2.679 19.308 0.360 -0.834 1.520 -ATOM 1757 H1 TIP3 2044 -3.518 19.745 0.448 0.417 1.000 -ATOM 1758 H2 TIP3 2044 -2.015 19.946 0.715 0.417 1.000 -ATOM 1759 OH2 TIP3 2061 -2.461 18.628 -4.607 -0.834 1.520 -ATOM 1760 H1 TIP3 2061 -2.718 18.910 -5.451 0.417 1.000 -ATOM 1761 H2 TIP3 2061 -2.514 17.693 -4.700 0.417 1.000 -ATOM 1762 OH2 TIP3 2070 -11.282 15.755 13.150 -0.834 1.520 -ATOM 1763 H1 TIP3 2070 -11.730 15.309 13.875 0.417 1.000 -ATOM 1764 H2 TIP3 2070 -11.419 15.078 12.442 0.417 1.000 -ATOM 1765 OH2 TIP3 2079 -4.571 17.194 -16.923 -0.834 1.520 -ATOM 1766 H1 TIP3 2079 -5.173 16.701 -17.396 0.417 1.000 -ATOM 1767 H2 TIP3 2079 -4.744 17.007 -15.937 0.417 1.000 -ATOM 1768 OH2 TIP3 2082 2.263 18.788 -16.029 -0.834 1.520 -ATOM 1769 H1 TIP3 2082 3.127 19.127 -16.167 0.417 1.000 -ATOM 1770 H2 TIP3 2082 1.659 19.087 -16.835 0.417 1.000 -ATOM 1771 OH2 TIP3 2083 -18.479 17.571 -4.668 -0.834 1.520 -ATOM 1772 H1 TIP3 2083 -17.758 17.486 -5.349 0.417 1.000 -ATOM 1773 H2 TIP3 2083 -18.060 18.181 -3.995 0.417 1.000 -ATOM 1774 OH2 TIP3 2086 3.402 17.593 4.419 -0.834 1.520 -ATOM 1775 H1 TIP3 2086 3.148 16.633 4.549 0.417 1.000 -ATOM 1776 H2 TIP3 2086 3.908 17.810 5.218 0.417 1.000 -ATOM 1777 OH2 TIP3 2105 -11.927 8.386 -4.115 -0.834 1.520 -ATOM 1778 H1 TIP3 2105 -12.129 8.913 -4.903 0.417 1.000 -ATOM 1779 H2 TIP3 2105 -11.792 9.108 -3.427 0.417 1.000 -ATOM 1780 OH2 TIP3 2123 -9.037 -18.263 -8.210 -0.834 1.520 -ATOM 1781 H1 TIP3 2123 -9.681 -17.760 -8.666 0.417 1.000 -ATOM 1782 H2 TIP3 2123 -8.291 -17.833 -8.790 0.417 1.000 -ATOM 1783 OH2 TIP3 2127 -19.018 -12.588 5.939 -0.834 1.520 -ATOM 1784 H1 TIP3 2127 -18.758 -11.970 5.208 0.417 1.000 -ATOM 1785 H2 TIP3 2127 -19.040 -13.477 5.504 0.417 1.000 -ATOM 1786 OH2 TIP3 2133 -5.207 -15.408 18.528 -0.834 1.520 -ATOM 1787 H1 TIP3 2133 -5.550 -14.893 17.758 0.417 1.000 -ATOM 1788 H2 TIP3 2133 -5.166 -14.771 19.194 0.417 1.000 -ATOM 1789 OH2 TIP3 2147 -11.718 -12.192 7.208 -0.834 1.520 -ATOM 1790 H1 TIP3 2147 -10.787 -11.843 7.568 0.417 1.000 -ATOM 1791 H2 TIP3 2147 -12.108 -12.539 8.013 0.417 1.000 -ATOM 1792 OH2 TIP3 2151 -1.294 -18.993 18.225 -0.834 1.520 -ATOM 1793 H1 TIP3 2151 -2.025 -19.609 18.331 0.417 1.000 -ATOM 1794 H2 TIP3 2151 -1.579 -18.233 18.756 0.417 1.000 -ATOM 1795 OH2 TIP3 2155 8.045 -11.616 11.621 -0.834 1.520 -ATOM 1796 H1 TIP3 2155 7.356 -11.039 11.192 0.417 1.000 -ATOM 1797 H2 TIP3 2155 7.459 -12.073 12.301 0.417 1.000 -ATOM 1798 OH2 TIP3 2163 -14.474 -11.631 -5.142 -0.834 1.520 -ATOM 1799 H1 TIP3 2163 -15.050 -11.782 -5.928 0.417 1.000 -ATOM 1800 H2 TIP3 2163 -15.055 -11.081 -4.637 0.417 1.000 -ATOM 1801 OH2 TIP3 2165 -5.224 -15.061 -7.557 -0.834 1.520 -ATOM 1802 H1 TIP3 2165 -5.364 -14.048 -7.748 0.417 1.000 -ATOM 1803 H2 TIP3 2165 -6.135 -15.288 -7.396 0.417 1.000 -ATOM 1804 OH2 TIP3 2167 -12.471 -15.492 -18.604 -0.834 1.520 -ATOM 1805 H1 TIP3 2167 -11.687 -15.418 -19.143 0.417 1.000 -ATOM 1806 H2 TIP3 2167 -13.217 -15.489 -19.232 0.417 1.000 -ATOM 1807 OH2 TIP3 2172 -8.565 -19.164 2.059 -0.834 1.520 -ATOM 1808 H1 TIP3 2172 -8.142 -19.897 1.657 0.417 1.000 -ATOM 1809 H2 TIP3 2172 -7.781 -18.719 2.508 0.417 1.000 -ATOM 1810 OH2 TIP3 2185 -0.992 -17.803 -0.139 -0.834 1.520 -ATOM 1811 H1 TIP3 2185 -1.064 -16.914 -0.575 0.417 1.000 -ATOM 1812 H2 TIP3 2185 -0.468 -18.289 -0.839 0.417 1.000 -ATOM 1813 OH2 TIP3 2186 4.048 -14.612 -3.267 -0.834 1.520 -ATOM 1814 H1 TIP3 2186 4.171 -14.139 -2.391 0.417 1.000 -ATOM 1815 H2 TIP3 2186 3.125 -14.629 -3.401 0.417 1.000 -ATOM 1816 OH2 TIP3 2187 4.212 -18.286 -7.867 -0.834 1.520 -ATOM 1817 H1 TIP3 2187 3.582 -18.639 -7.201 0.417 1.000 -ATOM 1818 H2 TIP3 2187 4.341 -19.001 -8.475 0.417 1.000 -ATOM 1819 OH2 TIP3 2195 10.295 -12.380 9.842 -0.834 1.520 -ATOM 1820 H1 TIP3 2195 9.590 -12.662 9.214 0.417 1.000 -ATOM 1821 H2 TIP3 2195 9.871 -12.139 10.617 0.417 1.000 -ATOM 1822 OH2 TIP3 2208 12.275 -3.562 -9.308 -0.834 1.520 -ATOM 1823 H1 TIP3 2208 12.945 -4.242 -9.368 0.417 1.000 -ATOM 1824 H2 TIP3 2208 12.204 -3.287 -10.258 0.417 1.000 -ATOM 1825 OH2 TIP3 2211 -2.076 -15.320 6.419 -0.834 1.520 -ATOM 1826 H1 TIP3 2211 -1.138 -15.470 6.316 0.417 1.000 -ATOM 1827 H2 TIP3 2211 -2.169 -15.289 7.395 0.417 1.000 -ATOM 1828 OH2 TIP3 2212 1.339 -2.977 10.377 -0.834 1.520 -ATOM 1829 H1 TIP3 2212 1.748 -3.374 9.690 0.417 1.000 -ATOM 1830 H2 TIP3 2212 1.134 -2.070 10.068 0.417 1.000 -ATOM 1831 OH2 TIP3 2213 14.913 -4.945 5.651 -0.834 1.520 -ATOM 1832 H1 TIP3 2213 14.238 -4.945 6.364 0.417 1.000 -ATOM 1833 H2 TIP3 2213 15.296 -4.025 5.770 0.417 1.000 -ATOM 1834 OH2 TIP3 2217 -3.525 -10.834 13.855 -0.834 1.520 -ATOM 1835 H1 TIP3 2217 -4.559 -10.784 13.831 0.417 1.000 -ATOM 1836 H2 TIP3 2217 -3.275 -10.906 12.897 0.417 1.000 -ATOM 1837 OH2 TIP3 2219 -6.451 -13.680 16.634 -0.834 1.520 -ATOM 1838 H1 TIP3 2219 -5.971 -13.032 16.104 0.417 1.000 -ATOM 1839 H2 TIP3 2219 -6.985 -14.124 15.911 0.417 1.000 -ATOM 1840 OH2 TIP3 2227 -8.800 -15.849 -16.529 -0.834 1.520 -ATOM 1841 H1 TIP3 2227 -7.947 -15.640 -16.072 0.417 1.000 -ATOM 1842 H2 TIP3 2227 -9.428 -15.574 -15.862 0.417 1.000 -ATOM 1843 OH2 TIP3 2229 0.914 -1.712 -10.772 -0.834 1.520 -ATOM 1844 H1 TIP3 2229 1.719 -1.532 -10.181 0.417 1.000 -ATOM 1845 H2 TIP3 2229 1.059 -1.125 -11.484 0.417 1.000 -ATOM 1846 OH2 TIP3 2231 -15.116 -15.919 -6.287 -0.834 1.520 -ATOM 1847 H1 TIP3 2231 -15.030 -15.254 -5.627 0.417 1.000 -ATOM 1848 H2 TIP3 2231 -16.068 -16.025 -6.407 0.417 1.000 -ATOM 1849 OH2 TIP3 2232 -0.433 -6.220 -0.713 -0.834 1.520 -ATOM 1850 H1 TIP3 2232 0.031 -5.318 -0.607 0.417 1.000 -ATOM 1851 H2 TIP3 2232 0.202 -6.764 -1.255 0.417 1.000 -ATOM 1852 OH2 TIP3 2234 1.592 -11.839 6.970 -0.834 1.520 -ATOM 1853 H1 TIP3 2234 1.978 -12.733 7.048 0.417 1.000 -ATOM 1854 H2 TIP3 2234 1.533 -11.492 7.881 0.417 1.000 -ATOM 1855 OH2 TIP3 2235 10.123 -12.130 17.078 -0.834 1.520 -ATOM 1856 H1 TIP3 2235 10.906 -11.757 16.625 0.417 1.000 -ATOM 1857 H2 TIP3 2235 10.369 -12.269 17.997 0.417 1.000 -ATOM 1858 OH2 TIP3 2236 -18.204 -3.353 6.522 -0.834 1.520 -ATOM 1859 H1 TIP3 2236 -17.562 -2.620 6.694 0.417 1.000 -ATOM 1860 H2 TIP3 2236 -18.069 -3.974 7.267 0.417 1.000 -ATOM 1861 OH2 TIP3 2240 -3.666 -17.737 13.909 -0.834 1.520 -ATOM 1862 H1 TIP3 2240 -3.853 -18.542 14.509 0.417 1.000 -ATOM 1863 H2 TIP3 2240 -2.748 -17.919 13.641 0.417 1.000 -ATOM 1864 OH2 TIP3 2244 -6.133 -15.376 -16.046 -0.834 1.520 -ATOM 1865 H1 TIP3 2244 -5.933 -15.359 -15.096 0.417 1.000 -ATOM 1866 H2 TIP3 2244 -5.878 -14.506 -16.352 0.417 1.000 -ATOM 1867 OH2 TIP3 2250 -2.578 -16.600 -15.798 -0.834 1.520 -ATOM 1868 H1 TIP3 2250 -1.805 -16.566 -16.402 0.417 1.000 -ATOM 1869 H2 TIP3 2250 -2.603 -17.575 -15.593 0.417 1.000 -ATOM 1870 OH2 TIP3 2251 -3.309 -2.084 -13.241 -0.834 1.520 -ATOM 1871 H1 TIP3 2251 -3.594 -1.447 -13.908 0.417 1.000 -ATOM 1872 H2 TIP3 2251 -3.185 -1.474 -12.418 0.417 1.000 -ATOM 1873 OH2 TIP3 2253 -1.807 -2.030 -10.250 -0.834 1.520 -ATOM 1874 H1 TIP3 2253 -2.042 -1.089 -10.167 0.417 1.000 -ATOM 1875 H2 TIP3 2253 -0.849 -2.010 -10.353 0.417 1.000 -ATOM 1876 OH2 TIP3 2254 -2.573 -11.540 -4.938 -0.834 1.520 -ATOM 1877 H1 TIP3 2254 -3.541 -11.477 -4.957 0.417 1.000 -ATOM 1878 H2 TIP3 2254 -2.363 -12.231 -5.612 0.417 1.000 -ATOM 1879 OH2 TIP3 2256 -4.655 -9.948 7.391 -0.834 1.520 -ATOM 1880 H1 TIP3 2256 -3.854 -10.164 7.773 0.417 1.000 -ATOM 1881 H2 TIP3 2256 -5.349 -10.127 8.112 0.417 1.000 -ATOM 1882 OH2 TIP3 2257 -10.328 -19.412 4.858 -0.834 1.520 -ATOM 1883 H1 TIP3 2257 -11.052 -19.706 5.377 0.417 1.000 -ATOM 1884 H2 TIP3 2257 -10.659 -18.594 4.518 0.417 1.000 -ATOM 1885 OH2 TIP3 2258 2.420 -13.866 14.132 -0.834 1.520 -ATOM 1886 H1 TIP3 2258 1.893 -14.665 14.236 0.417 1.000 -ATOM 1887 H2 TIP3 2258 3.154 -14.232 13.532 0.417 1.000 -ATOM 1888 OH2 TIP3 2269 0.640 -12.012 0.638 -0.834 1.520 -ATOM 1889 H1 TIP3 2269 0.659 -12.056 -0.305 0.417 1.000 -ATOM 1890 H2 TIP3 2269 1.535 -11.696 0.911 0.417 1.000 -ATOM 1891 OH2 TIP3 2270 -16.826 -8.841 -14.046 -0.834 1.520 -ATOM 1892 H1 TIP3 2270 -16.096 -8.927 -14.648 0.417 1.000 -ATOM 1893 H2 TIP3 2270 -16.796 -7.896 -13.871 0.417 1.000 -ATOM 1894 OH2 TIP3 2271 4.035 -8.563 -9.058 -0.834 1.520 -ATOM 1895 H1 TIP3 2271 4.407 -7.653 -9.161 0.417 1.000 -ATOM 1896 H2 TIP3 2271 3.483 -8.658 -9.848 0.417 1.000 -ATOM 1897 OH2 TIP3 2272 -7.078 -17.089 -2.588 -0.834 1.520 -ATOM 1898 H1 TIP3 2272 -7.579 -17.569 -1.911 0.417 1.000 -ATOM 1899 H2 TIP3 2272 -7.760 -17.004 -3.299 0.417 1.000 -ATOM 1900 OH2 TIP3 2273 9.572 4.909 -1.184 -0.834 1.520 -ATOM 1901 H1 TIP3 2273 10.207 5.395 -0.688 0.417 1.000 -ATOM 1902 H2 TIP3 2273 10.024 4.065 -1.256 0.417 1.000 -ATOM 1903 OH2 TIP3 2274 -6.245 10.376 -1.340 -0.834 1.520 -ATOM 1904 H1 TIP3 2274 -7.199 10.330 -1.190 0.417 1.000 -ATOM 1905 H2 TIP3 2274 -6.116 10.626 -2.222 0.417 1.000 -ATOM 1906 OH2 TIP3 2275 0.843 -4.997 -11.408 -0.834 1.520 -ATOM 1907 H1 TIP3 2275 1.616 -4.345 -11.476 0.417 1.000 -ATOM 1908 H2 TIP3 2275 0.048 -4.481 -11.445 0.417 1.000 -ATOM 1909 OH2 TIP3 2276 2.830 14.458 0.419 -0.834 1.520 -ATOM 1910 H1 TIP3 2276 3.519 14.206 1.114 0.417 1.000 -ATOM 1911 H2 TIP3 2276 2.353 15.136 0.871 0.417 1.000 -ATOM 1912 OH2 TIP3 2277 -6.356 -12.039 0.946 -0.834 1.520 -ATOM 1913 H1 TIP3 2277 -6.817 -12.842 0.680 0.417 1.000 -ATOM 1914 H2 TIP3 2277 -6.982 -11.685 1.687 0.417 1.000 -ATOM 1915 OH2 TIP3 2278 2.665 -14.370 6.951 -0.834 1.520 -ATOM 1916 H1 TIP3 2278 2.656 -15.139 7.490 0.417 1.000 -ATOM 1917 H2 TIP3 2278 3.484 -14.508 6.420 0.417 1.000 -ATOM 1918 OH2 TIP3 2280 -13.388 -16.604 -2.958 -0.834 1.520 -ATOM 1919 H1 TIP3 2280 -13.862 -17.013 -2.170 0.417 1.000 -ATOM 1920 H2 TIP3 2280 -13.752 -17.117 -3.694 0.417 1.000 -ATOM 1921 OH2 TIP3 2281 -10.082 -8.222 10.774 -0.834 1.520 -ATOM 1922 H1 TIP3 2281 -10.248 -7.298 10.633 0.417 1.000 -ATOM 1923 H2 TIP3 2281 -10.696 -8.689 10.145 0.417 1.000 -ATOM 1924 OH2 TIP3 2283 -14.205 -4.682 17.290 -0.834 1.520 -ATOM 1925 H1 TIP3 2283 -15.161 -4.549 17.478 0.417 1.000 -ATOM 1926 H2 TIP3 2283 -13.947 -5.411 17.884 0.417 1.000 -ATOM 1927 OH2 TIP3 2284 -5.706 -3.601 13.982 -0.834 1.520 -ATOM 1928 H1 TIP3 2284 -5.784 -2.691 13.609 0.417 1.000 -ATOM 1929 H2 TIP3 2284 -4.729 -3.777 13.919 0.417 1.000 -ATOM 1930 OH2 TIP3 2286 -11.658 -3.462 17.080 -0.834 1.520 -ATOM 1931 H1 TIP3 2286 -11.133 -4.147 17.501 0.417 1.000 -ATOM 1932 H2 TIP3 2286 -12.579 -3.840 16.954 0.417 1.000 -ATOM 1933 OH2 TIP3 2288 -16.372 -4.547 -10.316 -0.834 1.520 -ATOM 1934 H1 TIP3 2288 -16.396 -3.632 -10.635 0.417 1.000 -ATOM 1935 H2 TIP3 2288 -16.734 -4.522 -9.408 0.417 1.000 -ATOM 1936 OH2 TIP3 2290 -18.388 12.495 -15.466 -0.834 1.520 -ATOM 1937 H1 TIP3 2290 -18.076 11.828 -14.819 0.417 1.000 -ATOM 1938 H2 TIP3 2290 -19.322 12.557 -15.269 0.417 1.000 -ATOM 1939 OH2 TIP3 2292 -0.540 -14.409 -5.555 -0.834 1.520 -ATOM 1940 H1 TIP3 2292 0.196 -13.750 -5.355 0.417 1.000 -ATOM 1941 H2 TIP3 2292 -0.906 -14.125 -6.419 0.417 1.000 -ATOM 1942 OH2 TIP3 2293 -18.359 -1.736 -11.864 -0.834 1.520 -ATOM 1943 H1 TIP3 2293 -19.245 -1.510 -11.992 0.417 1.000 -ATOM 1944 H2 TIP3 2293 -18.019 -0.997 -11.335 0.417 1.000 -ATOM 1945 OH2 TIP3 2294 9.495 3.138 -4.110 -0.834 1.520 -ATOM 1946 H1 TIP3 2294 9.139 2.254 -3.841 0.417 1.000 -ATOM 1947 H2 TIP3 2294 10.438 2.912 -4.208 0.417 1.000 -ATOM 1948 OH2 TIP3 2295 -11.284 -19.181 1.571 -0.834 1.520 -ATOM 1949 H1 TIP3 2295 -11.641 -19.601 2.460 0.417 1.000 -ATOM 1950 H2 TIP3 2295 -10.378 -18.954 1.690 0.417 1.000 -ATOM 1951 OH2 TIP3 2296 7.308 -9.359 -7.457 -0.834 1.520 -ATOM 1952 H1 TIP3 2296 7.329 -9.716 -8.400 0.417 1.000 -ATOM 1953 H2 TIP3 2296 7.336 -8.403 -7.626 0.417 1.000 -ATOM 1954 OH2 TIP3 2297 3.117 -0.907 8.405 -0.834 1.520 -ATOM 1955 H1 TIP3 2297 2.229 -0.819 8.079 0.417 1.000 -ATOM 1956 H2 TIP3 2297 3.353 -0.032 8.715 0.417 1.000 -ATOM 1957 OH2 TIP3 2298 3.212 -14.197 10.846 -0.834 1.520 -ATOM 1958 H1 TIP3 2298 3.803 -14.486 11.557 0.417 1.000 -ATOM 1959 H2 TIP3 2298 3.808 -13.865 10.158 0.417 1.000 -ATOM 1960 OH2 TIP3 2299 -6.566 5.337 13.390 -0.834 1.520 -ATOM 1961 H1 TIP3 2299 -6.418 4.364 13.530 0.417 1.000 -ATOM 1962 H2 TIP3 2299 -7.137 5.449 12.588 0.417 1.000 -ATOM 1963 OH2 TIP3 2300 -5.531 1.877 4.235 -0.834 1.520 -ATOM 1964 H1 TIP3 2300 -4.676 1.872 3.803 0.417 1.000 -ATOM 1965 H2 TIP3 2300 -5.575 0.993 4.640 0.417 1.000 -ATOM 1966 OH2 TIP3 2301 -9.635 -10.289 13.459 -0.834 1.520 -ATOM 1967 H1 TIP3 2301 -9.266 -10.294 12.552 0.417 1.000 -ATOM 1968 H2 TIP3 2301 -9.163 -9.574 13.909 0.417 1.000 -ATOM 1969 OH2 TIP3 2302 -4.891 -6.546 4.094 -0.834 1.520 -ATOM 1970 H1 TIP3 2302 -4.467 -7.374 4.413 0.417 1.000 -ATOM 1971 H2 TIP3 2302 -4.218 -6.101 3.586 0.417 1.000 -ATOM 1972 OH2 TIP3 2309 -5.731 -9.999 -15.631 -0.834 1.520 -ATOM 1973 H1 TIP3 2309 -5.027 -9.472 -15.248 0.417 1.000 -ATOM 1974 H2 TIP3 2309 -6.310 -10.141 -14.908 0.417 1.000 -ATOM 1975 OH2 TIP3 2311 -5.309 -6.183 -10.950 -0.834 1.520 -ATOM 1976 H1 TIP3 2311 -4.838 -5.628 -11.615 0.417 1.000 -ATOM 1977 H2 TIP3 2311 -6.179 -5.750 -10.887 0.417 1.000 -ATOM 1978 OH2 TIP3 2313 8.308 -12.249 -8.799 -0.834 1.520 -ATOM 1979 H1 TIP3 2313 8.564 -13.175 -9.084 0.417 1.000 -ATOM 1980 H2 TIP3 2313 8.125 -12.349 -7.860 0.417 1.000 -ATOM 1981 OH2 TIP3 2315 -0.749 4.031 -4.981 -0.834 1.520 -ATOM 1982 H1 TIP3 2315 -0.584 4.218 -4.033 0.417 1.000 -ATOM 1983 H2 TIP3 2315 0.120 3.940 -5.437 0.417 1.000 -ATOM 1984 OH2 TIP3 2316 -7.727 -14.576 -9.596 -0.834 1.520 -ATOM 1985 H1 TIP3 2316 -7.616 -15.528 -9.790 0.417 1.000 -ATOM 1986 H2 TIP3 2316 -6.847 -14.286 -9.499 0.417 1.000 -ATOM 1987 OH2 TIP3 2317 -16.241 -6.747 -4.857 -0.834 1.520 -ATOM 1988 H1 TIP3 2317 -16.448 -6.454 -3.941 0.417 1.000 -ATOM 1989 H2 TIP3 2317 -17.138 -6.679 -5.260 0.417 1.000 -ATOM 1990 OH2 TIP3 2318 -9.711 4.036 -17.707 -0.834 1.520 -ATOM 1991 H1 TIP3 2318 -9.653 4.942 -17.982 0.417 1.000 -ATOM 1992 H2 TIP3 2318 -8.811 3.864 -17.445 0.417 1.000 -ATOM 1993 OH2 TIP3 2319 -1.292 0.702 -3.058 -0.834 1.520 -ATOM 1994 H1 TIP3 2319 -1.015 1.641 -2.839 0.417 1.000 -ATOM 1995 H2 TIP3 2319 -1.005 0.185 -2.291 0.417 1.000 -ATOM 1996 OH2 TIP3 2320 -1.861 5.548 2.658 -0.834 1.520 -ATOM 1997 H1 TIP3 2320 -2.466 6.233 2.529 0.417 1.000 -ATOM 1998 H2 TIP3 2320 -1.908 5.149 1.779 0.417 1.000 -ATOM 1999 OH2 TIP3 2321 -11.333 5.901 10.752 -0.834 1.520 -ATOM 2000 H1 TIP3 2321 -11.686 5.203 10.087 0.417 1.000 -ATOM 2001 H2 TIP3 2321 -12.053 5.888 11.430 0.417 1.000 -ATOM 2002 OH2 TIP3 2322 5.181 -6.033 8.608 -0.834 1.520 -ATOM 2003 H1 TIP3 2322 5.211 -6.094 9.597 0.417 1.000 -ATOM 2004 H2 TIP3 2322 4.539 -6.789 8.454 0.417 1.000 -ATOM 2005 OH2 TIP3 2326 -6.455 -7.376 16.168 -0.834 1.520 -ATOM 2006 H1 TIP3 2326 -6.485 -6.980 17.055 0.417 1.000 -ATOM 2007 H2 TIP3 2326 -5.799 -8.127 16.247 0.417 1.000 -ATOM 2008 OH2 TIP3 2327 -15.918 4.655 18.495 -0.834 1.520 -ATOM 2009 H1 TIP3 2327 -15.637 3.688 18.391 0.417 1.000 -ATOM 2010 H2 TIP3 2327 -16.860 4.570 18.697 0.417 1.000 -ATOM 2011 OH2 TIP3 2329 5.575 -3.241 -18.058 -0.834 1.520 -ATOM 2012 H1 TIP3 2329 5.444 -3.693 -17.180 0.417 1.000 -ATOM 2013 H2 TIP3 2329 5.764 -4.038 -18.645 0.417 1.000 -ATOM 2014 OH2 TIP3 2331 7.117 -6.596 -12.875 -0.834 1.520 -ATOM 2015 H1 TIP3 2331 7.014 -6.658 -11.921 0.417 1.000 -ATOM 2016 H2 TIP3 2331 7.894 -7.127 -13.063 0.417 1.000 -ATOM 2017 OH2 TIP3 2332 6.050 -1.247 -9.554 -0.834 1.520 -ATOM 2018 H1 TIP3 2332 5.900 -0.327 -9.635 0.417 1.000 -ATOM 2019 H2 TIP3 2332 6.455 -1.484 -10.453 0.417 1.000 -ATOM 2020 OH2 TIP3 2333 -6.898 9.392 -13.686 -0.834 1.520 -ATOM 2021 H1 TIP3 2333 -6.796 10.236 -14.050 0.417 1.000 -ATOM 2022 H2 TIP3 2333 -6.727 9.565 -12.739 0.417 1.000 -ATOM 2023 OH2 TIP3 2335 -12.681 -5.568 -4.985 -0.834 1.520 -ATOM 2024 H1 TIP3 2335 -12.367 -4.681 -5.258 0.417 1.000 -ATOM 2025 H2 TIP3 2335 -12.298 -5.697 -4.067 0.417 1.000 -ATOM 2026 OH2 TIP3 2336 3.587 13.492 -14.424 -0.834 1.520 -ATOM 2027 H1 TIP3 2336 2.950 13.226 -15.085 0.417 1.000 -ATOM 2028 H2 TIP3 2336 3.460 14.481 -14.329 0.417 1.000 -ATOM 2029 OH2 TIP3 2337 -0.839 15.629 -6.246 -0.834 1.520 -ATOM 2030 H1 TIP3 2337 -1.488 15.731 -5.545 0.417 1.000 -ATOM 2031 H2 TIP3 2337 0.026 15.799 -5.787 0.417 1.000 -ATOM 2032 OH2 TIP3 2338 -1.195 12.960 -7.480 -0.834 1.520 -ATOM 2033 H1 TIP3 2338 -0.703 12.167 -7.218 0.417 1.000 -ATOM 2034 H2 TIP3 2338 -0.445 13.610 -7.281 0.417 1.000 -ATOM 2035 OH2 TIP3 2339 -2.997 2.235 -0.803 -0.834 1.520 -ATOM 2036 H1 TIP3 2339 -2.606 1.585 -1.428 0.417 1.000 -ATOM 2037 H2 TIP3 2339 -3.371 1.813 -0.013 0.417 1.000 -ATOM 2038 OH2 TIP3 2340 -8.728 3.285 10.928 -0.834 1.520 -ATOM 2039 H1 TIP3 2340 -8.630 4.190 11.223 0.417 1.000 -ATOM 2040 H2 TIP3 2340 -8.844 3.343 9.964 0.417 1.000 -ATOM 2041 OH2 TIP3 2342 -4.171 -0.461 11.081 -0.834 1.520 -ATOM 2042 H1 TIP3 2342 -4.438 0.513 11.007 0.417 1.000 -ATOM 2043 H2 TIP3 2342 -4.592 -0.785 11.931 0.417 1.000 -ATOM 2044 OH2 TIP3 2345 -6.539 -4.232 6.741 -0.834 1.520 -ATOM 2045 H1 TIP3 2345 -6.391 -3.634 7.510 0.417 1.000 -ATOM 2046 H2 TIP3 2345 -6.600 -5.129 7.165 0.417 1.000 -ATOM 2047 OH2 TIP3 2346 4.597 -9.421 13.207 -0.834 1.520 -ATOM 2048 H1 TIP3 2346 4.222 -8.579 13.469 0.417 1.000 -ATOM 2049 H2 TIP3 2346 5.117 -9.691 13.974 0.417 1.000 -ATOM 2050 OH2 TIP3 2351 -2.710 -0.708 -17.641 -0.834 1.520 -ATOM 2051 H1 TIP3 2351 -2.429 -1.587 -17.928 0.417 1.000 -ATOM 2052 H2 TIP3 2351 -2.752 -0.755 -16.654 0.417 1.000 -ATOM 2053 OH2 TIP3 2352 -1.234 3.787 -16.016 -0.834 1.520 -ATOM 2054 H1 TIP3 2352 -1.015 3.007 -16.543 0.417 1.000 -ATOM 2055 H2 TIP3 2352 -1.564 3.402 -15.218 0.417 1.000 -ATOM 2056 OH2 TIP3 2354 -3.137 11.310 -12.657 -0.834 1.520 -ATOM 2057 H1 TIP3 2354 -2.921 12.272 -12.729 0.417 1.000 -ATOM 2058 H2 TIP3 2354 -2.289 10.861 -12.781 0.417 1.000 -ATOM 2059 OH2 TIP3 2355 -0.934 -3.532 -13.203 -0.834 1.520 -ATOM 2060 H1 TIP3 2355 -1.700 -3.070 -12.811 0.417 1.000 -ATOM 2061 H2 TIP3 2355 -1.256 -3.708 -14.117 0.417 1.000 -ATOM 2062 OH2 TIP3 2357 -16.883 -8.181 -9.930 -0.834 1.520 -ATOM 2063 H1 TIP3 2357 -16.510 -7.504 -10.477 0.417 1.000 -ATOM 2064 H2 TIP3 2357 -16.063 -8.417 -9.461 0.417 1.000 -ATOM 2065 OH2 TIP3 2358 -19.451 -3.607 -9.634 -0.834 1.520 -ATOM 2066 H1 TIP3 2358 -18.708 -3.678 -8.984 0.417 1.000 -ATOM 2067 H2 TIP3 2358 -19.335 -2.717 -10.028 0.417 1.000 -ATOM 2068 OH2 TIP3 2359 1.404 3.372 -6.577 -0.834 1.520 -ATOM 2069 H1 TIP3 2359 2.157 3.832 -6.909 0.417 1.000 -ATOM 2070 H2 TIP3 2359 1.702 2.597 -6.064 0.417 1.000 -ATOM 2071 OH2 TIP3 2360 -9.507 4.964 7.613 -0.834 1.520 -ATOM 2072 H1 TIP3 2360 -8.860 4.305 7.322 0.417 1.000 -ATOM 2073 H2 TIP3 2360 -10.284 4.459 7.898 0.417 1.000 -ATOM 2074 OH2 TIP3 2361 -8.898 7.719 13.804 -0.834 1.520 -ATOM 2075 H1 TIP3 2361 -8.363 8.501 13.492 0.417 1.000 -ATOM 2076 H2 TIP3 2361 -9.724 8.173 14.077 0.417 1.000 -ATOM 2077 OH2 TIP3 2362 -2.377 -15.037 9.019 -0.834 1.520 -ATOM 2078 H1 TIP3 2362 -1.536 -15.413 9.324 0.417 1.000 -ATOM 2079 H2 TIP3 2362 -2.782 -14.477 9.781 0.417 1.000 -ATOM 2080 OH2 TIP3 2363 6.706 -6.590 17.116 -0.834 1.520 -ATOM 2081 H1 TIP3 2363 7.228 -6.121 16.472 0.417 1.000 -ATOM 2082 H2 TIP3 2363 7.053 -7.484 17.045 0.417 1.000 -ATOM 2083 OH2 TIP3 2364 0.166 13.918 15.942 -0.834 1.520 -ATOM 2084 H1 TIP3 2364 1.019 13.915 16.533 0.417 1.000 -ATOM 2085 H2 TIP3 2364 -0.376 14.719 16.250 0.417 1.000 -ATOM 2086 OH2 TIP3 2365 10.249 -3.744 9.525 -0.834 1.520 -ATOM 2087 H1 TIP3 2365 9.874 -2.993 9.132 0.417 1.000 -ATOM 2088 H2 TIP3 2365 9.562 -4.176 10.012 0.417 1.000 -ATOM 2089 OH2 TIP3 2367 -2.385 10.502 16.418 -0.834 1.520 -ATOM 2090 H1 TIP3 2367 -2.516 10.146 15.556 0.417 1.000 -ATOM 2091 H2 TIP3 2367 -2.164 11.456 16.298 0.417 1.000 -ATOM 2092 OH2 TIP3 2375 8.380 1.948 3.685 -0.834 1.520 -ATOM 2093 H1 TIP3 2375 7.883 1.107 3.699 0.417 1.000 -ATOM 2094 H2 TIP3 2375 9.311 1.736 3.879 0.417 1.000 -ATOM 2095 OH2 TIP3 2376 -3.064 6.039 -16.049 -0.834 1.520 -ATOM 2096 H1 TIP3 2376 -3.448 5.515 -15.384 0.417 1.000 -ATOM 2097 H2 TIP3 2376 -2.269 5.524 -16.316 0.417 1.000 -ATOM 2098 OH2 TIP3 2377 -2.653 -13.106 -7.290 -0.834 1.520 -ATOM 2099 H1 TIP3 2377 -2.965 -12.719 -8.069 0.417 1.000 -ATOM 2100 H2 TIP3 2377 -2.312 -13.953 -7.614 0.417 1.000 -ATOM 2101 OH2 TIP3 2379 -0.703 7.146 9.355 -0.834 1.520 -ATOM 2102 H1 TIP3 2379 -0.088 6.961 10.059 0.417 1.000 -ATOM 2103 H2 TIP3 2379 -1.415 6.521 9.489 0.417 1.000 -ATOM 2104 OH2 TIP3 2380 -4.189 -4.711 -12.800 -0.834 1.520 -ATOM 2105 H1 TIP3 2380 -4.386 -5.031 -13.691 0.417 1.000 -ATOM 2106 H2 TIP3 2380 -3.976 -3.802 -13.013 0.417 1.000 -ATOM 2107 OH2 TIP3 2381 -1.066 0.840 13.368 -0.834 1.520 -ATOM 2108 H1 TIP3 2381 -1.229 -0.094 13.498 0.417 1.000 -ATOM 2109 H2 TIP3 2381 -1.088 1.268 14.242 0.417 1.000 -ATOM 2110 OH2 TIP3 2382 5.578 17.279 2.344 -0.834 1.520 -ATOM 2111 H1 TIP3 2382 4.837 17.870 2.407 0.417 1.000 -ATOM 2112 H2 TIP3 2382 5.510 16.800 3.195 0.417 1.000 -ATOM 2113 OH2 TIP3 2383 -9.446 11.776 9.968 -0.834 1.520 -ATOM 2114 H1 TIP3 2383 -9.269 10.864 9.643 0.417 1.000 -ATOM 2115 H2 TIP3 2383 -9.022 12.349 9.323 0.417 1.000 -ATOM 2116 OH2 TIP3 2385 -6.807 14.917 10.198 -0.834 1.520 -ATOM 2117 H1 TIP3 2385 -6.788 14.153 9.673 0.417 1.000 -ATOM 2118 H2 TIP3 2385 -6.598 15.582 9.559 0.417 1.000 -ATOM 2119 OH2 TIP3 2388 5.526 10.079 11.561 -0.834 1.520 -ATOM 2120 H1 TIP3 2388 4.871 10.095 12.202 0.417 1.000 -ATOM 2121 H2 TIP3 2388 6.295 9.737 12.042 0.417 1.000 -ATOM 2122 OH2 TIP3 2397 -12.706 10.336 -15.568 -0.834 1.520 -ATOM 2123 H1 TIP3 2397 -12.458 11.062 -15.086 0.417 1.000 -ATOM 2124 H2 TIP3 2397 -11.880 9.814 -15.585 0.417 1.000 -ATOM 2125 OH2 TIP3 2398 1.177 10.370 -0.880 -0.834 1.520 -ATOM 2126 H1 TIP3 2398 1.205 11.325 -0.802 0.417 1.000 -ATOM 2127 H2 TIP3 2398 0.266 10.095 -0.620 0.417 1.000 -ATOM 2128 OH2 TIP3 2399 -8.446 18.325 -3.695 -0.834 1.520 -ATOM 2129 H1 TIP3 2399 -8.052 17.932 -2.845 0.417 1.000 -ATOM 2130 H2 TIP3 2399 -7.608 18.669 -4.118 0.417 1.000 -ATOM 2131 OH2 TIP3 2400 -5.634 18.228 -4.039 -0.834 1.520 -ATOM 2132 H1 TIP3 2400 -4.768 18.021 -4.330 0.417 1.000 -ATOM 2133 H2 TIP3 2400 -5.924 17.386 -3.652 0.417 1.000 -ATOM 2134 OH2 TIP3 2402 -9.382 2.201 6.019 -0.834 1.520 -ATOM 2135 H1 TIP3 2402 -10.051 2.230 6.749 0.417 1.000 -ATOM 2136 H2 TIP3 2402 -9.057 1.315 6.136 0.417 1.000 -ATOM 2137 OH2 TIP3 2404 -1.613 15.661 14.268 -0.834 1.520 -ATOM 2138 H1 TIP3 2404 -2.181 14.999 14.712 0.417 1.000 -ATOM 2139 H2 TIP3 2404 -1.772 15.487 13.351 0.417 1.000 -ATOM 2140 OH2 TIP3 2405 -15.263 6.898 9.253 -0.834 1.520 -ATOM 2141 H1 TIP3 2405 -16.010 7.512 9.251 0.417 1.000 -ATOM 2142 H2 TIP3 2405 -14.483 7.467 9.109 0.417 1.000 -ATOM 2143 OH2 TIP3 2406 -1.501 -2.004 14.059 -0.834 1.520 -ATOM 2144 H1 TIP3 2406 -0.959 -2.471 14.748 0.417 1.000 -ATOM 2145 H2 TIP3 2406 -1.464 -2.611 13.319 0.417 1.000 -ATOM 2146 OH2 TIP3 2407 8.179 -0.534 16.622 -0.834 1.520 -ATOM 2147 H1 TIP3 2407 7.417 -0.869 16.267 0.417 1.000 -ATOM 2148 H2 TIP3 2407 8.469 0.165 15.942 0.417 1.000 -ATOM 2149 OH2 TIP3 2416 12.086 16.644 -8.961 -0.834 1.520 -ATOM 2150 H1 TIP3 2416 11.700 15.888 -8.421 0.417 1.000 -ATOM 2151 H2 TIP3 2416 11.393 16.767 -9.661 0.417 1.000 -ATOM 2152 OH2 TIP3 2418 4.789 2.892 1.785 -0.834 1.520 -ATOM 2153 H1 TIP3 2418 4.614 1.960 1.659 0.417 1.000 -ATOM 2154 H2 TIP3 2418 4.930 3.181 0.799 0.417 1.000 -ATOM 2155 OH2 TIP3 2419 -0.855 12.320 -17.951 -0.834 1.520 -ATOM 2156 H1 TIP3 2419 -1.012 11.387 -18.018 0.417 1.000 -ATOM 2157 H2 TIP3 2419 -1.748 12.669 -17.667 0.417 1.000 -ATOM 2158 OH2 TIP3 2420 9.550 15.456 2.808 -0.834 1.520 -ATOM 2159 H1 TIP3 2420 8.745 15.698 2.368 0.417 1.000 -ATOM 2160 H2 TIP3 2420 9.944 16.350 3.078 0.417 1.000 -ATOM 2161 OH2 TIP3 2421 -10.363 11.703 -7.639 -0.834 1.520 -ATOM 2162 H1 TIP3 2421 -10.449 12.630 -7.969 0.417 1.000 -ATOM 2163 H2 TIP3 2421 -9.623 11.806 -6.973 0.417 1.000 -ATOM 2164 OH2 TIP3 2422 -4.878 14.283 4.320 -0.834 1.520 -ATOM 2165 H1 TIP3 2422 -5.722 14.109 3.835 0.417 1.000 -ATOM 2166 H2 TIP3 2422 -4.936 15.157 4.611 0.417 1.000 -ATOM 2167 OH2 TIP3 2424 7.445 16.533 16.119 -0.834 1.520 -ATOM 2168 H1 TIP3 2424 7.227 17.325 16.603 0.417 1.000 -ATOM 2169 H2 TIP3 2424 6.724 15.919 16.445 0.417 1.000 -ATOM 2170 OH2 TIP3 2427 11.792 5.068 17.401 -0.834 1.520 -ATOM 2171 H1 TIP3 2427 12.217 5.675 17.997 0.417 1.000 -ATOM 2172 H2 TIP3 2427 12.136 4.216 17.746 0.417 1.000 -ATOM 2173 OH2 TIP3 2436 -3.581 11.379 -15.573 -0.834 1.520 -ATOM 2174 H1 TIP3 2436 -3.497 11.761 -14.716 0.417 1.000 -ATOM 2175 H2 TIP3 2436 -3.663 10.424 -15.426 0.417 1.000 -ATOM 2176 OH2 TIP3 2439 1.444 13.518 3.608 -0.834 1.520 -ATOM 2177 H1 TIP3 2439 2.227 13.781 4.139 0.417 1.000 -ATOM 2178 H2 TIP3 2439 1.497 12.499 3.687 0.417 1.000 -ATOM 2179 OH2 TIP3 2442 1.058 18.464 -1.607 -0.834 1.520 -ATOM 2180 H1 TIP3 2442 0.985 19.446 -1.444 0.417 1.000 -ATOM 2181 H2 TIP3 2442 0.680 18.330 -2.499 0.417 1.000 -ATOM 2182 OH2 TIP3 2443 -5.271 16.895 5.412 -0.834 1.520 -ATOM 2183 H1 TIP3 2443 -5.222 17.735 4.944 0.417 1.000 -ATOM 2184 H2 TIP3 2443 -6.171 16.879 5.716 0.417 1.000 -ATOM 2185 OH2 TIP3 2444 -0.416 8.718 2.611 -0.834 1.520 -ATOM 2186 H1 TIP3 2444 -0.112 8.010 3.173 0.417 1.000 -ATOM 2187 H2 TIP3 2444 -1.398 8.710 2.688 0.417 1.000 -ATOM 2188 OH2 TIP3 2445 4.514 8.408 8.576 -0.834 1.520 -ATOM 2189 H1 TIP3 2445 4.242 9.169 8.106 0.417 1.000 -ATOM 2190 H2 TIP3 2445 4.628 8.696 9.512 0.417 1.000 -ATOM 2191 OH2 TIP3 2449 -3.618 -0.083 17.413 -0.834 1.520 -ATOM 2192 H1 TIP3 2449 -3.813 -0.936 16.955 0.417 1.000 -ATOM 2193 H2 TIP3 2449 -3.551 -0.321 18.329 0.417 1.000 -ATOM 2194 OH2 TIP3 2450 0.487 16.609 18.307 -0.834 1.520 -ATOM 2195 H1 TIP3 2450 0.542 16.359 17.338 0.417 1.000 -ATOM 2196 H2 TIP3 2450 -0.079 17.406 18.228 0.417 1.000 -ATOM 2197 OH2 TIP3 2458 4.953 17.068 -17.085 -0.834 1.520 -ATOM 2198 H1 TIP3 2458 5.615 16.967 -17.798 0.417 1.000 -ATOM 2199 H2 TIP3 2458 4.145 16.516 -17.433 0.417 1.000 -ATOM 2200 OH2 TIP3 2460 3.392 16.149 -14.679 -0.834 1.520 -ATOM 2201 H1 TIP3 2460 2.454 16.253 -14.966 0.417 1.000 -ATOM 2202 H2 TIP3 2460 3.773 16.596 -15.443 0.417 1.000 -ATOM 2203 OH2 TIP3 2463 -10.363 16.331 -0.396 -0.834 1.520 -ATOM 2204 H1 TIP3 2463 -9.532 16.186 -0.017 0.417 1.000 -ATOM 2205 H2 TIP3 2463 -10.348 15.680 -1.118 0.417 1.000 -ATOM 2206 OH2 TIP3 2464 -6.426 11.494 5.789 -0.834 1.520 -ATOM 2207 H1 TIP3 2464 -5.944 11.618 5.000 0.417 1.000 -ATOM 2208 H2 TIP3 2464 -5.751 11.043 6.314 0.417 1.000 -ATOM 2209 OH2 TIP3 2465 5.035 18.136 -0.832 -0.834 1.520 -ATOM 2210 H1 TIP3 2465 4.860 17.789 0.025 0.417 1.000 -ATOM 2211 H2 TIP3 2465 4.744 19.054 -0.665 0.417 1.000 -ATOM 2212 OH2 TIP3 2466 3.435 16.999 18.783 -0.834 1.520 -ATOM 2213 H1 TIP3 2466 2.571 16.794 18.441 0.417 1.000 -ATOM 2214 H2 TIP3 2466 3.944 16.799 18.018 0.417 1.000 -ATOM 2215 OH2 TIP3 2467 -4.399 17.916 13.849 -0.834 1.520 -ATOM 2216 H1 TIP3 2467 -4.353 17.865 12.892 0.417 1.000 -ATOM 2217 H2 TIP3 2467 -4.037 18.810 13.994 0.417 1.000 -ATOM 2218 OH2 TIP3 2469 0.483 8.826 7.557 -0.834 1.520 -ATOM 2219 H1 TIP3 2469 -0.078 8.497 8.339 0.417 1.000 -ATOM 2220 H2 TIP3 2469 -0.208 8.611 6.826 0.417 1.000 -ATOM 2221 OH2 TIP3 2479 -7.319 13.694 3.012 -0.834 1.520 -ATOM 2222 H1 TIP3 2479 -7.486 13.491 2.077 0.417 1.000 -ATOM 2223 H2 TIP3 2479 -7.963 13.127 3.442 0.417 1.000 -ATOM 2224 OH2 TIP3 2482 -12.027 17.457 -19.162 -0.834 1.520 -ATOM 2225 H1 TIP3 2482 -12.045 17.961 -18.300 0.417 1.000 -ATOM 2226 H2 TIP3 2482 -12.865 17.732 -19.609 0.417 1.000 -ATOM 2227 OH2 TIP3 2488 -7.116 19.132 13.204 -0.834 1.520 -ATOM 2228 H1 TIP3 2488 -7.614 18.406 12.723 0.417 1.000 -ATOM 2229 H2 TIP3 2488 -6.371 18.775 13.657 0.417 1.000 -ATOM 2230 OH2 TIP3 2492 -1.234 19.076 17.778 -0.834 1.520 -ATOM 2231 H1 TIP3 2492 -2.182 18.887 17.981 0.417 1.000 -ATOM 2232 H2 TIP3 2492 -1.042 19.797 18.353 0.417 1.000 -ATOM 2233 OH2 TIP3 2501 14.741 18.679 2.991 -0.834 1.520 -ATOM 2234 H1 TIP3 2501 14.837 18.816 2.050 0.417 1.000 -ATOM 2235 H2 TIP3 2501 13.848 18.992 3.178 0.417 1.000 -ATOM 2236 OH2 TIP3 2507 9.142 13.772 11.652 -0.834 1.520 -ATOM 2237 H1 TIP3 2507 8.872 13.113 12.275 0.417 1.000 -ATOM 2238 H2 TIP3 2507 8.448 13.766 10.998 0.417 1.000 -ATOM 2239 OH2 TIP3 2508 -8.796 10.133 -0.556 -0.834 1.520 -ATOM 2240 H1 TIP3 2508 -8.778 11.077 -0.267 0.417 1.000 -ATOM 2241 H2 TIP3 2508 -8.773 9.668 0.308 0.417 1.000 -ATOM 2242 OH2 TIP3 2541 -11.704 14.793 -14.192 -0.834 1.520 -ATOM 2243 H1 TIP3 2541 -12.372 14.702 -14.886 0.417 1.000 -ATOM 2244 H2 TIP3 2541 -11.088 15.487 -14.513 0.417 1.000 -ATOM 2245 OH2 TIP3 2582 -6.695 16.968 -19.228 -0.834 1.520 -ATOM 2246 H1 TIP3 2582 -7.651 17.077 -19.405 0.417 1.000 -ATOM 2247 H2 TIP3 2582 -6.267 17.791 -19.457 0.417 1.000 -ATOM 2248 OH2 TIP3 2587 5.100 -14.257 1.879 -0.834 1.520 -ATOM 2249 H1 TIP3 2587 5.444 -14.912 1.185 0.417 1.000 -ATOM 2250 H2 TIP3 2587 5.721 -14.424 2.596 0.417 1.000 -ATOM 2251 OH2 TIP3 2591 -10.485 -19.389 10.327 -0.834 1.520 -ATOM 2252 H1 TIP3 2591 -9.993 -19.757 9.596 0.417 1.000 -ATOM 2253 H2 TIP3 2591 -9.690 -18.964 10.864 0.417 1.000 -ATOM 2254 OH2 TIP3 2606 -1.673 -19.625 -8.542 -0.834 1.520 -ATOM 2255 H1 TIP3 2606 -1.175 -19.859 -7.706 0.417 1.000 -ATOM 2256 H2 TIP3 2606 -1.597 -18.634 -8.620 0.417 1.000 -ATOM 2257 OH2 TIP3 2607 -9.950 -14.395 -14.242 -0.834 1.520 -ATOM 2258 H1 TIP3 2607 -9.845 -13.446 -14.444 0.417 1.000 -ATOM 2259 H2 TIP3 2607 -9.203 -14.611 -13.691 0.417 1.000 -ATOM 2260 OH2 TIP3 2608 -12.119 -16.482 -14.300 -0.834 1.520 -ATOM 2261 H1 TIP3 2608 -11.450 -15.775 -14.188 0.417 1.000 -ATOM 2262 H2 TIP3 2608 -12.930 -16.166 -13.831 0.417 1.000 -ATOM 2263 OH2 TIP3 2610 5.589 -14.730 -7.463 -0.834 1.520 -ATOM 2264 H1 TIP3 2610 5.815 -15.522 -7.882 0.417 1.000 -ATOM 2265 H2 TIP3 2610 6.224 -14.566 -6.743 0.417 1.000 -ATOM 2266 OH2 TIP3 2616 -5.672 -6.663 10.714 -0.834 1.520 -ATOM 2267 H1 TIP3 2616 -5.988 -5.859 10.228 0.417 1.000 -ATOM 2268 H2 TIP3 2616 -5.774 -6.445 11.617 0.417 1.000 -ATOM 2269 OH2 TIP3 2617 -1.197 -14.024 11.699 -0.834 1.520 -ATOM 2270 H1 TIP3 2617 -0.751 -14.772 12.081 0.417 1.000 -ATOM 2271 H2 TIP3 2617 -0.382 -13.434 11.513 0.417 1.000 -ATOM 2272 OH2 TIP3 2628 6.162 -10.473 -9.944 -0.834 1.520 -ATOM 2273 H1 TIP3 2628 5.979 -11.367 -9.666 0.417 1.000 -ATOM 2274 H2 TIP3 2628 5.294 -9.977 -9.718 0.417 1.000 -ATOM 2275 OH2 TIP3 2632 5.214 -0.932 -4.568 -0.834 1.520 -ATOM 2276 H1 TIP3 2632 4.652 -1.270 -3.860 0.417 1.000 -ATOM 2277 H2 TIP3 2632 4.602 -0.856 -5.342 0.417 1.000 -ATOM 2278 OH2 TIP3 2633 3.139 -3.798 8.164 -0.834 1.520 -ATOM 2279 H1 TIP3 2633 3.293 -2.858 8.197 0.417 1.000 -ATOM 2280 H2 TIP3 2633 3.953 -4.145 8.642 0.417 1.000 -ATOM 2281 OH2 TIP3 2634 -11.441 -16.485 -8.465 -0.834 1.520 -ATOM 2282 H1 TIP3 2634 -11.565 -15.702 -7.845 0.417 1.000 -ATOM 2283 H2 TIP3 2634 -12.045 -17.101 -8.048 0.417 1.000 -ATOM 2284 OH2 TIP3 2635 13.234 -18.643 1.754 -0.834 1.520 -ATOM 2285 H1 TIP3 2635 13.961 -18.998 1.291 0.417 1.000 -ATOM 2286 H2 TIP3 2635 12.849 -18.048 1.080 0.417 1.000 -ATOM 2287 OH2 TIP3 2649 9.773 -10.375 -10.236 -0.834 1.520 -ATOM 2288 H1 TIP3 2649 9.262 -10.746 -9.526 0.417 1.000 -ATOM 2289 H2 TIP3 2649 9.260 -9.559 -10.423 0.417 1.000 -ATOM 2290 OH2 TIP3 2650 5.669 -16.299 -10.966 -0.834 1.520 -ATOM 2291 H1 TIP3 2650 5.837 -17.235 -11.111 0.417 1.000 -ATOM 2292 H2 TIP3 2650 6.139 -16.085 -10.145 0.417 1.000 -ATOM 2293 OH2 TIP3 2654 7.204 -10.323 -12.424 -0.834 1.520 -ATOM 2294 H1 TIP3 2654 7.643 -9.604 -11.980 0.417 1.000 -ATOM 2295 H2 TIP3 2654 6.766 -10.747 -11.674 0.417 1.000 -ATOM 2296 OH2 TIP3 2656 -13.968 -3.657 6.922 -0.834 1.520 -ATOM 2297 H1 TIP3 2656 -14.881 -3.831 6.946 0.417 1.000 -ATOM 2298 H2 TIP3 2656 -13.889 -3.435 5.983 0.417 1.000 -ATOM 2299 OH2 TIP3 2657 -3.286 -14.989 14.329 -0.834 1.520 -ATOM 2300 H1 TIP3 2657 -3.307 -15.911 14.500 0.417 1.000 -ATOM 2301 H2 TIP3 2657 -2.869 -15.000 13.463 0.417 1.000 -ATOM 2302 OH2 TIP3 2659 -3.076 -11.014 17.568 -0.834 1.520 -ATOM 2303 H1 TIP3 2659 -2.482 -11.367 18.338 0.417 1.000 -ATOM 2304 H2 TIP3 2659 -3.165 -11.780 16.959 0.417 1.000 -ATOM 2305 OH2 TIP3 2662 0.109 -14.403 19.779 -0.834 1.520 -ATOM 2306 H1 TIP3 2662 1.070 -14.633 19.700 0.417 1.000 -ATOM 2307 H2 TIP3 2662 -0.245 -14.861 19.051 0.417 1.000 -ATOM 2308 OH2 TIP3 2667 12.951 -14.346 -0.591 -0.834 1.520 -ATOM 2309 H1 TIP3 2667 12.204 -14.063 -0.012 0.417 1.000 -ATOM 2310 H2 TIP3 2667 12.732 -14.152 -1.551 0.417 1.000 -ATOM 2311 OH2 TIP3 2669 -6.961 -9.489 -8.223 -0.834 1.520 -ATOM 2312 H1 TIP3 2669 -6.175 -9.411 -8.718 0.417 1.000 -ATOM 2313 H2 TIP3 2669 -7.117 -8.527 -8.084 0.417 1.000 -ATOM 2314 OH2 TIP3 2670 7.684 -10.298 -3.912 -0.834 1.520 -ATOM 2315 H1 TIP3 2670 7.282 -11.211 -3.787 0.417 1.000 -ATOM 2316 H2 TIP3 2670 7.247 -9.756 -3.229 0.417 1.000 -ATOM 2317 OH2 TIP3 2672 15.298 -9.010 -3.999 -0.834 1.520 -ATOM 2318 H1 TIP3 2672 15.295 -8.277 -4.546 0.417 1.000 -ATOM 2319 H2 TIP3 2672 14.284 -9.261 -3.912 0.417 1.000 -ATOM 2320 OH2 TIP3 2673 -1.811 -15.418 -1.151 -0.834 1.520 -ATOM 2321 H1 TIP3 2673 -2.408 -15.228 -0.409 0.417 1.000 -ATOM 2322 H2 TIP3 2673 -1.538 -14.571 -1.482 0.417 1.000 -ATOM 2323 OH2 TIP3 2674 13.936 -18.170 -2.122 -0.834 1.520 -ATOM 2324 H1 TIP3 2674 13.988 -17.572 -2.901 0.417 1.000 -ATOM 2325 H2 TIP3 2674 13.180 -18.802 -2.269 0.417 1.000 -ATOM 2326 OH2 TIP3 2675 -6.413 -18.148 6.990 -0.834 1.520 -ATOM 2327 H1 TIP3 2675 -5.889 -18.229 6.142 0.417 1.000 -ATOM 2328 H2 TIP3 2675 -6.304 -19.035 7.380 0.417 1.000 -ATOM 2329 OH2 TIP3 2676 5.774 -16.116 -0.004 -0.834 1.520 -ATOM 2330 H1 TIP3 2676 5.595 -17.004 0.380 0.417 1.000 -ATOM 2331 H2 TIP3 2676 5.873 -16.363 -0.998 0.417 1.000 -ATOM 2332 OH2 TIP3 2677 -8.740 -6.761 5.511 -0.834 1.520 -ATOM 2333 H1 TIP3 2677 -8.935 -5.999 5.990 0.417 1.000 -ATOM 2334 H2 TIP3 2677 -8.347 -7.410 6.175 0.417 1.000 -ATOM 2335 OH2 TIP3 2678 8.025 -6.221 9.088 -0.834 1.520 -ATOM 2336 H1 TIP3 2678 8.704 -5.819 8.609 0.417 1.000 -ATOM 2337 H2 TIP3 2678 7.189 -5.812 8.743 0.417 1.000 -ATOM 2338 OH2 TIP3 2680 0.331 -12.429 15.970 -0.834 1.520 -ATOM 2339 H1 TIP3 2680 -0.596 -12.261 15.737 0.417 1.000 -ATOM 2340 H2 TIP3 2680 0.797 -12.749 15.171 0.417 1.000 -ATOM 2341 OH2 TIP3 2683 0.059 -19.029 15.754 -0.834 1.520 -ATOM 2342 H1 TIP3 2683 -0.305 -19.160 16.633 0.417 1.000 -ATOM 2343 H2 TIP3 2683 -0.545 -19.575 15.252 0.417 1.000 -ATOM 2344 OH2 TIP3 2689 1.509 -15.070 -13.679 -0.834 1.520 -ATOM 2345 H1 TIP3 2689 1.670 -14.168 -13.722 0.417 1.000 -ATOM 2346 H2 TIP3 2689 2.198 -15.413 -13.036 0.417 1.000 -ATOM 2347 OH2 TIP3 2690 3.213 -14.759 -11.172 -0.834 1.520 -ATOM 2348 H1 TIP3 2690 4.050 -15.326 -10.885 0.417 1.000 -ATOM 2349 H2 TIP3 2690 3.460 -13.914 -10.826 0.417 1.000 -ATOM 2350 OH2 TIP3 2691 -4.684 -16.024 -4.967 -0.834 1.520 -ATOM 2351 H1 TIP3 2691 -4.647 -15.735 -5.935 0.417 1.000 -ATOM 2352 H2 TIP3 2691 -5.415 -15.467 -4.540 0.417 1.000 -ATOM 2353 OH2 TIP3 2692 5.596 -13.267 -9.669 -0.834 1.520 -ATOM 2354 H1 TIP3 2692 6.356 -13.859 -9.906 0.417 1.000 -ATOM 2355 H2 TIP3 2692 5.494 -13.449 -8.709 0.417 1.000 -ATOM 2356 OH2 TIP3 2693 -2.949 -18.510 10.533 -0.834 1.520 -ATOM 2357 H1 TIP3 2693 -2.514 -18.280 9.668 0.417 1.000 -ATOM 2358 H2 TIP3 2693 -3.722 -19.073 10.237 0.417 1.000 -ATOM 2359 OH2 TIP3 2694 -11.600 -14.448 -6.443 -0.834 1.520 -ATOM 2360 H1 TIP3 2694 -10.930 -14.760 -5.815 0.417 1.000 -ATOM 2361 H2 TIP3 2694 -12.261 -14.055 -5.837 0.417 1.000 -ATOM 2362 OH2 TIP3 2695 13.084 -11.238 -5.690 -0.834 1.520 -ATOM 2363 H1 TIP3 2695 12.733 -10.456 -5.249 0.417 1.000 -ATOM 2364 H2 TIP3 2695 12.272 -11.743 -5.877 0.417 1.000 -ATOM 2365 OH2 TIP3 2696 12.654 -16.309 4.596 -0.834 1.520 -ATOM 2366 H1 TIP3 2696 12.880 -16.116 5.513 0.417 1.000 -ATOM 2367 H2 TIP3 2696 12.744 -17.242 4.501 0.417 1.000 -ATOM 2368 OH2 TIP3 2697 3.742 -4.291 -1.904 -0.834 1.520 -ATOM 2369 H1 TIP3 2697 4.551 -3.894 -2.179 0.417 1.000 -ATOM 2370 H2 TIP3 2697 3.413 -4.712 -2.769 0.417 1.000 -ATOM 2371 OH2 TIP3 2699 8.004 -2.354 8.912 -0.834 1.520 -ATOM 2372 H1 TIP3 2699 7.434 -1.589 9.281 0.417 1.000 -ATOM 2373 H2 TIP3 2699 7.354 -2.956 8.559 0.417 1.000 -ATOM 2374 OH2 TIP3 2701 -8.206 5.052 -2.354 -0.834 1.520 -ATOM 2375 H1 TIP3 2701 -7.333 4.804 -2.716 0.417 1.000 -ATOM 2376 H2 TIP3 2701 -8.394 4.326 -1.718 0.417 1.000 -ATOM 2377 OH2 TIP3 2703 4.549 -12.992 15.738 -0.834 1.520 -ATOM 2378 H1 TIP3 2703 3.797 -13.555 15.329 0.417 1.000 -ATOM 2379 H2 TIP3 2703 4.671 -13.424 16.621 0.417 1.000 -ATOM 2380 OH2 TIP3 2709 -0.746 1.282 -17.342 -0.834 1.520 -ATOM 2381 H1 TIP3 2709 -0.081 0.761 -16.859 0.417 1.000 -ATOM 2382 H2 TIP3 2709 -1.319 0.629 -17.676 0.417 1.000 -ATOM 2383 OH2 TIP3 2710 11.648 -3.762 -18.762 -0.834 1.520 -ATOM 2384 H1 TIP3 2710 11.394 -2.870 -18.371 0.417 1.000 -ATOM 2385 H2 TIP3 2710 10.936 -4.357 -18.482 0.417 1.000 -ATOM 2386 OH2 TIP3 2713 -3.886 0.023 -11.152 -0.834 1.520 -ATOM 2387 H1 TIP3 2713 -3.768 0.963 -11.391 0.417 1.000 -ATOM 2388 H2 TIP3 2713 -4.743 -0.085 -10.700 0.417 1.000 -ATOM 2389 OH2 TIP3 2714 -15.719 1.161 -0.934 -0.834 1.520 -ATOM 2390 H1 TIP3 2714 -14.843 1.058 -0.619 0.417 1.000 -ATOM 2391 H2 TIP3 2714 -15.831 2.110 -1.096 0.417 1.000 -ATOM 2392 OH2 TIP3 2715 1.505 -11.802 -13.855 -0.834 1.520 -ATOM 2393 H1 TIP3 2715 1.809 -10.929 -13.681 0.417 1.000 -ATOM 2394 H2 TIP3 2715 1.328 -11.751 -14.803 0.417 1.000 -ATOM 2395 OH2 TIP3 2717 11.568 1.320 1.163 -0.834 1.520 -ATOM 2396 H1 TIP3 2717 10.799 0.711 1.305 0.417 1.000 -ATOM 2397 H2 TIP3 2717 11.323 1.603 0.269 0.417 1.000 -ATOM 2398 OH2 TIP3 2718 8.597 2.409 18.875 -0.834 1.520 -ATOM 2399 H1 TIP3 2718 8.089 2.419 19.687 0.417 1.000 -ATOM 2400 H2 TIP3 2718 8.701 1.435 18.799 0.417 1.000 -ATOM 2401 OH2 TIP3 2719 5.995 -7.637 5.902 -0.834 1.520 -ATOM 2402 H1 TIP3 2719 5.653 -6.793 5.530 0.417 1.000 -ATOM 2403 H2 TIP3 2719 5.203 -8.194 5.809 0.417 1.000 -ATOM 2404 OH2 TIP3 2720 -2.456 -12.747 15.428 -0.834 1.520 -ATOM 2405 H1 TIP3 2720 -2.917 -12.083 14.937 0.417 1.000 -ATOM 2406 H2 TIP3 2720 -2.819 -13.576 15.037 0.417 1.000 -ATOM 2407 OH2 TIP3 2721 8.586 -8.743 16.679 -0.834 1.520 -ATOM 2408 H1 TIP3 2721 9.542 -8.629 16.997 0.417 1.000 -ATOM 2409 H2 TIP3 2721 8.692 -9.379 15.967 0.417 1.000 -ATOM 2410 OH2 TIP3 2732 -6.130 -12.526 -7.813 -0.834 1.520 -ATOM 2411 H1 TIP3 2732 -6.791 -11.927 -7.367 0.417 1.000 -ATOM 2412 H2 TIP3 2732 -5.543 -11.971 -8.341 0.417 1.000 -ATOM 2413 OH2 TIP3 2734 0.488 -6.827 -13.356 -0.834 1.520 -ATOM 2414 H1 TIP3 2734 -0.366 -7.303 -13.069 0.417 1.000 -ATOM 2415 H2 TIP3 2734 0.688 -6.266 -12.550 0.417 1.000 -ATOM 2416 OH2 TIP3 2735 -6.400 -2.753 -10.002 -0.834 1.520 -ATOM 2417 H1 TIP3 2735 -6.744 -3.615 -9.893 0.417 1.000 -ATOM 2418 H2 TIP3 2735 -6.384 -2.663 -10.953 0.417 1.000 -ATOM 2419 OH2 TIP3 2736 9.201 -8.366 -12.246 -0.834 1.520 -ATOM 2420 H1 TIP3 2736 9.874 -7.686 -12.123 0.417 1.000 -ATOM 2421 H2 TIP3 2736 9.387 -8.653 -13.190 0.417 1.000 -ATOM 2422 OH2 TIP3 2737 3.968 -5.752 5.301 -0.834 1.520 -ATOM 2423 H1 TIP3 2737 3.469 -5.336 6.014 0.417 1.000 -ATOM 2424 H2 TIP3 2737 3.898 -5.141 4.541 0.417 1.000 -ATOM 2425 OH2 TIP3 2738 -10.766 6.832 5.736 -0.834 1.520 -ATOM 2426 H1 TIP3 2738 -10.254 6.180 6.234 0.417 1.000 -ATOM 2427 H2 TIP3 2738 -11.116 6.235 5.066 0.417 1.000 -ATOM 2428 OH2 TIP3 2739 14.024 7.737 5.007 -0.834 1.520 -ATOM 2429 H1 TIP3 2739 14.615 7.021 5.086 0.417 1.000 -ATOM 2430 H2 TIP3 2739 14.589 8.553 4.850 0.417 1.000 -ATOM 2431 OH2 TIP3 2740 7.087 -0.388 3.133 -0.834 1.520 -ATOM 2432 H1 TIP3 2740 7.094 -1.103 3.801 0.417 1.000 -ATOM 2433 H2 TIP3 2740 6.150 -0.210 3.002 0.417 1.000 -ATOM 2434 OH2 TIP3 2741 -3.495 2.219 11.618 -0.834 1.520 -ATOM 2435 H1 TIP3 2741 -2.750 1.631 11.854 0.417 1.000 -ATOM 2436 H2 TIP3 2741 -2.987 2.977 11.275 0.417 1.000 -ATOM 2437 OH2 TIP3 2743 -1.524 -6.983 6.155 -0.834 1.520 -ATOM 2438 H1 TIP3 2743 -2.124 -7.442 5.566 0.417 1.000 -ATOM 2439 H2 TIP3 2743 -1.643 -7.392 7.053 0.417 1.000 -ATOM 2440 OH2 TIP3 2753 0.306 6.975 -13.863 -0.834 1.520 -ATOM 2441 H1 TIP3 2753 -0.571 7.310 -13.743 0.417 1.000 -ATOM 2442 H2 TIP3 2753 0.838 7.794 -13.981 0.417 1.000 -ATOM 2443 OH2 TIP3 2754 4.900 -9.096 -6.137 -0.834 1.520 -ATOM 2444 H1 TIP3 2754 4.395 -8.989 -6.964 0.417 1.000 -ATOM 2445 H2 TIP3 2754 5.838 -9.213 -6.379 0.417 1.000 -ATOM 2446 OH2 TIP3 2755 -13.352 6.409 -0.992 -0.834 1.520 -ATOM 2447 H1 TIP3 2755 -12.956 7.167 -0.499 0.417 1.000 -ATOM 2448 H2 TIP3 2755 -13.010 6.530 -1.849 0.417 1.000 -ATOM 2449 OH2 TIP3 2756 8.512 -8.004 6.333 -0.834 1.520 -ATOM 2450 H1 TIP3 2756 9.099 -7.178 6.113 0.417 1.000 -ATOM 2451 H2 TIP3 2756 7.537 -7.755 6.168 0.417 1.000 -ATOM 2452 OH2 TIP3 2757 -3.154 5.884 -2.277 -0.834 1.520 -ATOM 2453 H1 TIP3 2757 -3.457 5.668 -3.194 0.417 1.000 -ATOM 2454 H2 TIP3 2757 -3.531 6.717 -2.238 0.417 1.000 -ATOM 2455 OH2 TIP3 2758 -9.901 -1.917 1.099 -0.834 1.520 -ATOM 2456 H1 TIP3 2758 -9.547 -2.742 0.699 0.417 1.000 -ATOM 2457 H2 TIP3 2758 -10.602 -2.254 1.690 0.417 1.000 -ATOM 2458 OH2 TIP3 2760 -6.517 -7.344 7.905 -0.834 1.520 -ATOM 2459 H1 TIP3 2760 -6.435 -7.079 8.822 0.417 1.000 -ATOM 2460 H2 TIP3 2760 -6.042 -8.201 7.830 0.417 1.000 -ATOM 2461 OH2 TIP3 2761 16.470 -11.691 14.969 -0.834 1.520 -ATOM 2462 H1 TIP3 2761 16.184 -11.645 13.997 0.417 1.000 -ATOM 2463 H2 TIP3 2761 17.427 -11.531 14.971 0.417 1.000 -ATOM 2464 OH2 TIP3 2767 -13.647 12.350 19.261 -0.834 1.520 -ATOM 2465 H1 TIP3 2767 -13.550 11.938 18.415 0.417 1.000 -ATOM 2466 H2 TIP3 2767 -14.608 12.146 19.419 0.417 1.000 -ATOM 2467 OH2 TIP3 2771 3.915 -3.797 -15.779 -0.834 1.520 -ATOM 2468 H1 TIP3 2771 4.358 -4.064 -14.935 0.417 1.000 -ATOM 2469 H2 TIP3 2771 3.944 -4.654 -16.232 0.417 1.000 -ATOM 2470 OH2 TIP3 2774 13.812 9.049 -8.862 -0.834 1.520 -ATOM 2471 H1 TIP3 2774 13.368 8.234 -9.056 0.417 1.000 -ATOM 2472 H2 TIP3 2774 14.731 8.861 -9.092 0.417 1.000 -ATOM 2473 OH2 TIP3 2775 9.677 -11.246 -15.552 -0.834 1.520 -ATOM 2474 H1 TIP3 2775 9.019 -10.574 -15.342 0.417 1.000 -ATOM 2475 H2 TIP3 2775 9.888 -11.607 -14.699 0.417 1.000 -ATOM 2476 OH2 TIP3 2776 -2.398 -0.378 1.532 -0.834 1.520 -ATOM 2477 H1 TIP3 2776 -1.724 -0.621 2.185 0.417 1.000 -ATOM 2478 H2 TIP3 2776 -2.876 -1.189 1.522 0.417 1.000 -ATOM 2479 OH2 TIP3 2777 6.417 0.249 -12.088 -0.834 1.520 -ATOM 2480 H1 TIP3 2777 5.862 0.922 -12.459 0.417 1.000 -ATOM 2481 H2 TIP3 2777 7.149 0.907 -11.751 0.417 1.000 -ATOM 2482 OH2 TIP3 2778 -4.535 -12.045 -2.186 -0.834 1.520 -ATOM 2483 H1 TIP3 2778 -4.850 -12.021 -3.068 0.417 1.000 -ATOM 2484 H2 TIP3 2778 -5.294 -12.437 -1.694 0.417 1.000 -ATOM 2485 OH2 TIP3 2779 -10.844 -7.686 3.966 -0.834 1.520 -ATOM 2486 H1 TIP3 2779 -11.134 -8.115 4.871 0.417 1.000 -ATOM 2487 H2 TIP3 2779 -9.914 -7.519 4.093 0.417 1.000 -ATOM 2488 OH2 TIP3 2780 -15.853 4.095 8.652 -0.834 1.520 -ATOM 2489 H1 TIP3 2780 -15.475 4.949 8.960 0.417 1.000 -ATOM 2490 H2 TIP3 2780 -16.667 4.040 9.113 0.417 1.000 -ATOM 2491 OH2 TIP3 2781 -18.093 18.378 -9.838 -0.834 1.520 -ATOM 2492 H1 TIP3 2781 -17.693 17.490 -9.732 0.417 1.000 -ATOM 2493 H2 TIP3 2781 -18.252 18.649 -8.926 0.417 1.000 -ATOM 2494 OH2 TIP3 2782 12.884 8.064 10.649 -0.834 1.520 -ATOM 2495 H1 TIP3 2782 13.631 8.473 11.131 0.417 1.000 -ATOM 2496 H2 TIP3 2782 13.301 7.781 9.866 0.417 1.000 -ATOM 2497 OH2 TIP3 2783 9.419 6.542 19.110 -0.834 1.520 -ATOM 2498 H1 TIP3 2783 8.963 6.568 18.230 0.417 1.000 -ATOM 2499 H2 TIP3 2783 10.285 6.854 18.907 0.417 1.000 -ATOM 2500 OH2 TIP3 2784 -7.728 9.826 12.189 -0.834 1.520 -ATOM 2501 H1 TIP3 2784 -7.844 10.869 12.133 0.417 1.000 -ATOM 2502 H2 TIP3 2784 -7.894 9.537 11.318 0.417 1.000 -ATOM 2503 OH2 TIP3 2794 2.042 -9.231 -13.524 -0.834 1.520 -ATOM 2504 H1 TIP3 2794 2.762 -8.834 -12.936 0.417 1.000 -ATOM 2505 H2 TIP3 2794 1.379 -8.499 -13.654 0.417 1.000 -ATOM 2506 OH2 TIP3 2795 -4.419 8.901 -11.059 -0.834 1.520 -ATOM 2507 H1 TIP3 2795 -4.125 9.699 -11.454 0.417 1.000 -ATOM 2508 H2 TIP3 2795 -3.623 8.333 -11.092 0.417 1.000 -ATOM 2509 OH2 TIP3 2797 3.031 9.489 -4.238 -0.834 1.520 -ATOM 2510 H1 TIP3 2797 3.931 9.176 -4.113 0.417 1.000 -ATOM 2511 H2 TIP3 2797 2.945 9.581 -5.203 0.417 1.000 -ATOM 2512 OH2 TIP3 2799 4.053 5.323 16.555 -0.834 1.520 -ATOM 2513 H1 TIP3 2799 3.778 4.765 17.255 0.417 1.000 -ATOM 2514 H2 TIP3 2799 3.538 5.083 15.793 0.417 1.000 -ATOM 2515 OH2 TIP3 2800 -0.963 -0.357 10.882 -0.834 1.520 -ATOM 2516 H1 TIP3 2800 -1.558 -1.117 11.027 0.417 1.000 -ATOM 2517 H2 TIP3 2800 -0.818 0.037 11.784 0.417 1.000 -ATOM 2518 OH2 TIP3 2801 -3.207 -9.793 9.783 -0.834 1.520 -ATOM 2519 H1 TIP3 2801 -3.388 -10.456 10.483 0.417 1.000 -ATOM 2520 H2 TIP3 2801 -2.292 -10.035 9.460 0.417 1.000 -ATOM 2521 OH2 TIP3 2802 -17.239 14.861 -2.664 -0.834 1.520 -ATOM 2522 H1 TIP3 2802 -17.849 14.338 -2.118 0.417 1.000 -ATOM 2523 H2 TIP3 2802 -17.352 14.491 -3.501 0.417 1.000 -ATOM 2524 OH2 TIP3 2803 5.886 15.235 18.227 -0.834 1.520 -ATOM 2525 H1 TIP3 2803 5.644 14.327 18.100 0.417 1.000 -ATOM 2526 H2 TIP3 2803 6.487 15.306 19.006 0.417 1.000 -ATOM 2527 OH2 TIP3 2806 -8.534 7.575 7.795 -0.834 1.520 -ATOM 2528 H1 TIP3 2806 -8.324 7.642 6.825 0.417 1.000 -ATOM 2529 H2 TIP3 2806 -8.909 6.734 7.835 0.417 1.000 -ATOM 2530 OH2 TIP3 2815 0.395 -10.430 -8.366 -0.834 1.520 -ATOM 2531 H1 TIP3 2815 1.018 -11.111 -8.144 0.417 1.000 -ATOM 2532 H2 TIP3 2815 0.725 -9.687 -7.898 0.417 1.000 -ATOM 2533 OH2 TIP3 2817 -0.108 3.014 -1.949 -0.834 1.520 -ATOM 2534 H1 TIP3 2817 0.854 3.005 -1.812 0.417 1.000 -ATOM 2535 H2 TIP3 2817 -0.299 4.011 -2.047 0.417 1.000 -ATOM 2536 OH2 TIP3 2818 4.927 4.245 -4.003 -0.834 1.520 -ATOM 2537 H1 TIP3 2818 5.786 4.617 -4.065 0.417 1.000 -ATOM 2538 H2 TIP3 2818 4.853 4.047 -3.021 0.417 1.000 -ATOM 2539 OH2 TIP3 2819 4.700 13.170 -9.255 -0.834 1.520 -ATOM 2540 H1 TIP3 2819 5.184 12.434 -9.631 0.417 1.000 -ATOM 2541 H2 TIP3 2819 5.355 13.588 -8.658 0.417 1.000 -ATOM 2542 OH2 TIP3 2821 7.254 1.261 0.770 -0.834 1.520 -ATOM 2543 H1 TIP3 2821 7.904 1.713 1.261 0.417 1.000 -ATOM 2544 H2 TIP3 2821 6.810 0.778 1.494 0.417 1.000 -ATOM 2545 OH2 TIP3 2823 17.156 18.784 0.387 -0.834 1.520 -ATOM 2546 H1 TIP3 2823 16.616 18.131 -0.043 0.417 1.000 -ATOM 2547 H2 TIP3 2823 17.603 19.169 -0.403 0.417 1.000 -ATOM 2548 OH2 TIP3 2824 -11.747 -5.917 14.818 -0.834 1.520 -ATOM 2549 H1 TIP3 2824 -12.671 -6.137 14.718 0.417 1.000 -ATOM 2550 H2 TIP3 2824 -11.714 -5.329 15.651 0.417 1.000 -ATOM 2551 OH2 TIP3 2825 9.678 10.880 14.427 -0.834 1.520 -ATOM 2552 H1 TIP3 2825 10.466 10.742 13.888 0.417 1.000 -ATOM 2553 H2 TIP3 2825 10.062 11.228 15.205 0.417 1.000 -ATOM 2554 OH2 TIP3 2827 -6.023 2.652 13.422 -0.834 1.520 -ATOM 2555 H1 TIP3 2827 -5.241 2.740 12.797 0.417 1.000 -ATOM 2556 H2 TIP3 2827 -5.648 2.123 14.190 0.417 1.000 -ATOM 2557 OH2 TIP3 2832 -0.083 6.551 -10.960 -0.834 1.520 -ATOM 2558 H1 TIP3 2832 0.120 6.190 -11.860 0.417 1.000 -ATOM 2559 H2 TIP3 2832 -0.194 7.508 -11.129 0.417 1.000 -ATOM 2560 OH2 TIP3 2839 5.461 17.158 -4.472 -0.834 1.520 -ATOM 2561 H1 TIP3 2839 4.943 16.639 -5.094 0.417 1.000 -ATOM 2562 H2 TIP3 2839 4.876 17.217 -3.746 0.417 1.000 -ATOM 2563 OH2 TIP3 2840 -2.107 17.193 -1.716 -0.834 1.520 -ATOM 2564 H1 TIP3 2840 -2.302 17.733 -2.532 0.417 1.000 -ATOM 2565 H2 TIP3 2840 -1.831 17.859 -1.108 0.417 1.000 -ATOM 2566 OH2 TIP3 2841 1.057 13.054 -1.300 -0.834 1.520 -ATOM 2567 H1 TIP3 2841 1.397 13.374 -0.462 0.417 1.000 -ATOM 2568 H2 TIP3 2841 1.324 13.836 -1.915 0.417 1.000 -ATOM 2569 OH2 TIP3 2842 0.002 10.235 -5.227 -0.834 1.520 -ATOM 2570 H1 TIP3 2842 -0.320 10.758 -4.422 0.417 1.000 -ATOM 2571 H2 TIP3 2842 0.498 9.580 -4.815 0.417 1.000 -ATOM 2572 OH2 TIP3 2843 10.918 6.815 -3.533 -0.834 1.520 -ATOM 2573 H1 TIP3 2843 11.359 6.038 -3.268 0.417 1.000 -ATOM 2574 H2 TIP3 2843 10.366 7.062 -2.724 0.417 1.000 -ATOM 2575 OH2 TIP3 2844 -12.052 8.004 17.445 -0.834 1.520 -ATOM 2576 H1 TIP3 2844 -12.114 7.389 16.693 0.417 1.000 -ATOM 2577 H2 TIP3 2844 -11.385 8.635 17.269 0.417 1.000 -ATOM 2578 OH2 TIP3 2845 -5.998 2.548 7.246 -0.834 1.520 -ATOM 2579 H1 TIP3 2845 -6.001 2.223 6.330 0.417 1.000 -ATOM 2580 H2 TIP3 2845 -6.753 1.983 7.672 0.417 1.000 -ATOM 2581 OH2 TIP3 2848 2.534 18.000 15.364 -0.834 1.520 -ATOM 2582 H1 TIP3 2848 1.544 17.950 15.278 0.417 1.000 -ATOM 2583 H2 TIP3 2848 2.680 18.710 16.030 0.417 1.000 -ATOM 2584 OH2 TIP3 2857 -4.273 6.799 -8.529 -0.834 1.520 -ATOM 2585 H1 TIP3 2857 -3.553 6.161 -8.206 0.417 1.000 -ATOM 2586 H2 TIP3 2857 -4.332 7.359 -7.784 0.417 1.000 -ATOM 2587 OH2 TIP3 2859 -6.476 11.510 -15.250 -0.834 1.520 -ATOM 2588 H1 TIP3 2859 -5.698 12.013 -15.570 0.417 1.000 -ATOM 2589 H2 TIP3 2859 -7.210 11.810 -15.738 0.417 1.000 -ATOM 2590 OH2 TIP3 2860 1.077 14.629 7.395 -0.834 1.520 -ATOM 2591 H1 TIP3 2860 1.048 15.379 6.771 0.417 1.000 -ATOM 2592 H2 TIP3 2860 0.459 13.944 6.930 0.417 1.000 -ATOM 2593 OH2 TIP3 2862 -1.571 10.247 -0.425 -0.834 1.520 -ATOM 2594 H1 TIP3 2862 -2.321 9.554 -0.532 0.417 1.000 -ATOM 2595 H2 TIP3 2862 -2.021 10.898 0.090 0.417 1.000 -ATOM 2596 OH2 TIP3 2863 -5.861 14.491 -0.746 -0.834 1.520 -ATOM 2597 H1 TIP3 2863 -6.746 14.086 -0.607 0.417 1.000 -ATOM 2598 H2 TIP3 2863 -5.344 13.811 -1.252 0.417 1.000 -ATOM 2599 OH2 TIP3 2865 -5.011 10.052 7.685 -0.834 1.520 -ATOM 2600 H1 TIP3 2865 -4.914 9.323 7.155 0.417 1.000 -ATOM 2601 H2 TIP3 2865 -4.434 9.840 8.381 0.417 1.000 -ATOM 2602 OH2 TIP3 2866 -2.693 1.454 4.794 -0.834 1.520 -ATOM 2603 H1 TIP3 2866 -2.006 0.811 4.602 0.417 1.000 -ATOM 2604 H2 TIP3 2866 -2.220 2.132 5.344 0.417 1.000 -ATOM 2605 OH2 TIP3 2867 1.674 15.212 10.136 -0.834 1.520 -ATOM 2606 H1 TIP3 2867 1.346 14.932 9.292 0.417 1.000 -ATOM 2607 H2 TIP3 2867 1.751 14.443 10.663 0.417 1.000 -ATOM 2608 OH2 TIP3 2877 4.857 8.631 -18.261 -0.834 1.520 -ATOM 2609 H1 TIP3 2877 3.986 8.916 -18.688 0.417 1.000 -ATOM 2610 H2 TIP3 2877 5.159 9.541 -17.886 0.417 1.000 -ATOM 2611 OH2 TIP3 2878 1.862 7.684 -18.306 -0.834 1.520 -ATOM 2612 H1 TIP3 2878 1.911 8.691 -18.287 0.417 1.000 -ATOM 2613 H2 TIP3 2878 0.977 7.455 -18.015 0.417 1.000 -ATOM 2614 OH2 TIP3 2882 10.376 16.016 -1.679 -0.834 1.520 -ATOM 2615 H1 TIP3 2882 10.542 15.187 -2.116 0.417 1.000 -ATOM 2616 H2 TIP3 2882 9.490 16.074 -1.908 0.417 1.000 -ATOM 2617 OH2 TIP3 2884 -2.186 16.110 -9.299 -0.834 1.520 -ATOM 2618 H1 TIP3 2884 -1.712 15.457 -8.770 0.417 1.000 -ATOM 2619 H2 TIP3 2884 -2.657 16.669 -8.647 0.417 1.000 -ATOM 2620 OH2 TIP3 2885 1.319 1.993 16.278 -0.834 1.520 -ATOM 2621 H1 TIP3 2885 1.626 1.109 15.812 0.417 1.000 -ATOM 2622 H2 TIP3 2885 2.130 2.551 16.370 0.417 1.000 -ATOM 2623 OH2 TIP3 2886 0.382 18.751 8.484 -0.834 1.520 -ATOM 2624 H1 TIP3 2886 0.560 18.177 7.677 0.417 1.000 -ATOM 2625 H2 TIP3 2886 1.200 19.321 8.548 0.417 1.000 -ATOM 2626 OH2 TIP3 2893 5.029 19.028 17.694 -0.834 1.520 -ATOM 2627 H1 TIP3 2893 5.498 18.942 18.542 0.417 1.000 -ATOM 2628 H2 TIP3 2893 4.146 18.871 17.933 0.417 1.000 -ATOM 2629 OH2 TIP3 2903 -14.445 11.449 -17.376 -0.834 1.520 -ATOM 2630 H1 TIP3 2903 -14.042 12.299 -17.283 0.417 1.000 -ATOM 2631 H2 TIP3 2903 -13.964 10.896 -16.785 0.417 1.000 -ATOM 2632 OH2 TIP3 2904 -1.957 16.132 1.546 -0.834 1.520 -ATOM 2633 H1 TIP3 2904 -1.744 16.487 0.682 0.417 1.000 -ATOM 2634 H2 TIP3 2904 -2.887 16.377 1.741 0.417 1.000 -ATOM 2635 OH2 TIP3 2906 -15.967 18.122 11.647 -0.834 1.520 -ATOM 2636 H1 TIP3 2906 -16.211 19.030 11.681 0.417 1.000 -ATOM 2637 H2 TIP3 2906 -15.388 18.170 10.894 0.417 1.000 -ATOM 2638 OH2 TIP3 2909 -5.592 18.995 16.722 -0.834 1.520 -ATOM 2639 H1 TIP3 2909 -6.204 19.707 16.506 0.417 1.000 -ATOM 2640 H2 TIP3 2909 -6.168 18.231 16.698 0.417 1.000 -ATOM 2641 OH2 TIP3 2918 -7.468 15.205 -16.074 -0.834 1.520 -ATOM 2642 H1 TIP3 2918 -6.681 15.020 -16.587 0.417 1.000 -ATOM 2643 H2 TIP3 2918 -7.436 16.141 -15.888 0.417 1.000 -ATOM 2644 OH2 TIP3 2919 3.513 12.168 -18.444 -0.834 1.520 -ATOM 2645 H1 TIP3 2919 2.857 11.774 -19.120 0.417 1.000 -ATOM 2646 H2 TIP3 2919 4.399 11.777 -18.696 0.417 1.000 -ATOM 2647 OH2 TIP3 2922 -8.486 12.235 -3.257 -0.834 1.520 -ATOM 2648 H1 TIP3 2922 -9.093 11.695 -3.750 0.417 1.000 -ATOM 2649 H2 TIP3 2922 -7.613 11.824 -3.274 0.417 1.000 -ATOM 2650 OH2 TIP3 2923 10.302 14.690 -7.785 -0.834 1.520 -ATOM 2651 H1 TIP3 2923 10.568 13.747 -7.852 0.417 1.000 -ATOM 2652 H2 TIP3 2923 9.350 14.665 -8.018 0.417 1.000 -ATOM 2653 OH2 TIP3 2925 -3.754 18.545 -8.100 -0.834 1.520 -ATOM 2654 H1 TIP3 2925 -4.529 18.979 -8.513 0.417 1.000 -ATOM 2655 H2 TIP3 2925 -3.381 19.257 -7.562 0.417 1.000 -ATOM 2656 OH2 TIP3 2926 -7.176 6.812 5.474 -0.834 1.520 -ATOM 2657 H1 TIP3 2926 -6.305 7.072 5.817 0.417 1.000 -ATOM 2658 H2 TIP3 2926 -7.100 5.883 5.335 0.417 1.000 -ATOM 2659 OH2 TIP3 2927 0.360 18.907 -10.832 -0.834 1.520 -ATOM 2660 H1 TIP3 2927 -0.330 18.507 -11.359 0.417 1.000 -ATOM 2661 H2 TIP3 2927 1.196 18.705 -11.355 0.417 1.000 -ATOM 2662 OH2 TIP3 2930 3.339 19.789 13.361 -0.834 1.520 -ATOM 2663 H1 TIP3 2930 4.082 19.549 12.752 0.417 1.000 -ATOM 2664 H2 TIP3 2930 3.115 18.890 13.780 0.417 1.000 -ATOM 2665 OH2 TIP3 2941 12.723 18.488 -6.535 -0.834 1.520 -ATOM 2666 H1 TIP3 2941 11.976 18.590 -7.127 0.417 1.000 -ATOM 2667 H2 TIP3 2941 13.229 17.813 -6.991 0.417 1.000 -ATOM 2668 OH2 TIP3 2944 5.815 10.983 -10.743 -0.834 1.520 -ATOM 2669 H1 TIP3 2944 6.628 11.032 -11.271 0.417 1.000 -ATOM 2670 H2 TIP3 2944 5.220 10.934 -11.527 0.417 1.000 -ATOM 2671 OH2 TIP3 2963 1.379 19.620 -13.468 -0.834 1.520 -ATOM 2672 H1 TIP3 2963 0.426 19.562 -13.395 0.417 1.000 -ATOM 2673 H2 TIP3 2963 1.498 19.479 -14.385 0.417 1.000 -ATOM 2674 OH2 TIP3 2968 6.037 16.386 4.824 -0.834 1.520 -ATOM 2675 H1 TIP3 2968 6.954 16.405 5.261 0.417 1.000 -ATOM 2676 H2 TIP3 2968 5.427 16.257 5.519 0.417 1.000 -ATOM 2677 OH2 TIP3 3010 -10.984 -15.914 -11.186 -0.834 1.520 -ATOM 2678 H1 TIP3 3010 -10.623 -14.999 -11.187 0.417 1.000 -ATOM 2679 H2 TIP3 3010 -11.274 -16.259 -10.339 0.417 1.000 -ATOM 2680 OH2 TIP3 3012 -0.545 -18.744 -3.183 -0.834 1.520 -ATOM 2681 H1 TIP3 3012 -0.024 -18.253 -3.745 0.417 1.000 -ATOM 2682 H2 TIP3 3012 -1.430 -18.359 -3.281 0.417 1.000 -ATOM 2683 OH2 TIP3 3016 -7.535 -15.131 6.264 -0.834 1.520 -ATOM 2684 H1 TIP3 3016 -7.270 -15.211 5.350 0.417 1.000 -ATOM 2685 H2 TIP3 3016 -6.778 -15.426 6.728 0.417 1.000 -ATOM 2686 OH2 TIP3 3027 -3.797 -17.798 0.733 -0.834 1.520 -ATOM 2687 H1 TIP3 3027 -4.277 -18.100 -0.057 0.417 1.000 -ATOM 2688 H2 TIP3 3027 -2.853 -17.956 0.493 0.417 1.000 -ATOM 2689 OH2 TIP3 3030 8.773 -10.723 3.205 -0.834 1.520 -ATOM 2690 H1 TIP3 3030 9.544 -11.354 3.079 0.417 1.000 -ATOM 2691 H2 TIP3 3030 9.043 -9.975 2.616 0.417 1.000 -ATOM 2692 OH2 TIP3 3033 2.922 -14.831 19.096 -0.834 1.520 -ATOM 2693 H1 TIP3 3033 3.219 -15.339 18.284 0.417 1.000 -ATOM 2694 H2 TIP3 3033 2.564 -14.047 18.614 0.417 1.000 -ATOM 2695 OH2 TIP3 3037 -1.660 -8.616 13.995 -0.834 1.520 -ATOM 2696 H1 TIP3 3037 -2.470 -8.801 13.453 0.417 1.000 -ATOM 2697 H2 TIP3 3037 -0.929 -9.112 13.559 0.417 1.000 -ATOM 2698 OH2 TIP3 3046 12.383 -11.977 -2.609 -0.834 1.520 -ATOM 2699 H1 TIP3 3046 11.933 -12.490 -3.377 0.417 1.000 -ATOM 2700 H2 TIP3 3046 11.666 -11.638 -2.081 0.417 1.000 -ATOM 2701 OH2 TIP3 3049 -1.047 -17.050 -6.856 -0.834 1.520 -ATOM 2702 H1 TIP3 3049 -1.091 -16.614 -5.981 0.417 1.000 -ATOM 2703 H2 TIP3 3049 -0.364 -17.660 -6.658 0.417 1.000 -ATOM 2704 OH2 TIP3 3050 10.894 -17.039 -4.656 -0.834 1.520 -ATOM 2705 H1 TIP3 3050 10.707 -17.698 -4.003 0.417 1.000 -ATOM 2706 H2 TIP3 3050 10.648 -17.474 -5.511 0.417 1.000 -ATOM 2707 OH2 TIP3 3053 -2.258 -18.096 7.902 -0.834 1.520 -ATOM 2708 H1 TIP3 3053 -1.627 -18.150 7.152 0.417 1.000 -ATOM 2709 H2 TIP3 3053 -3.002 -17.601 7.553 0.417 1.000 -ATOM 2710 OH2 TIP3 3070 -0.838 6.826 -6.278 -0.834 1.520 -ATOM 2711 H1 TIP3 3070 0.048 6.911 -6.581 0.417 1.000 -ATOM 2712 H2 TIP3 3070 -0.828 6.129 -5.645 0.417 1.000 -ATOM 2713 OH2 TIP3 3071 -3.247 -12.027 11.480 -0.834 1.520 -ATOM 2714 H1 TIP3 3071 -2.615 -12.719 11.626 0.417 1.000 -ATOM 2715 H2 TIP3 3071 -4.101 -12.443 11.384 0.417 1.000 -ATOM 2716 OH2 TIP3 3072 -13.561 -14.856 -12.545 -0.834 1.520 -ATOM 2717 H1 TIP3 3072 -12.690 -15.164 -12.163 0.417 1.000 -ATOM 2718 H2 TIP3 3072 -13.879 -14.181 -11.884 0.417 1.000 -ATOM 2719 OH2 TIP3 3073 -1.349 -15.351 -11.579 -0.834 1.520 -ATOM 2720 H1 TIP3 3073 -0.674 -14.678 -11.432 0.417 1.000 -ATOM 2721 H2 TIP3 3073 -1.637 -15.256 -12.507 0.417 1.000 -ATOM 2722 OH2 TIP3 3075 5.503 -17.577 9.355 -0.834 1.520 -ATOM 2723 H1 TIP3 3075 5.815 -17.477 10.265 0.417 1.000 -ATOM 2724 H2 TIP3 3075 5.270 -16.658 9.168 0.417 1.000 -ATOM 2725 OH2 TIP3 3080 -0.560 -7.155 8.739 -0.834 1.520 -ATOM 2726 H1 TIP3 3080 -0.005 -6.889 9.548 0.417 1.000 -ATOM 2727 H2 TIP3 3080 -1.381 -7.120 9.211 0.417 1.000 -ATOM 2728 OH2 TIP3 3085 4.148 -15.531 -18.486 -0.834 1.520 -ATOM 2729 H1 TIP3 3085 3.319 -16.059 -18.560 0.417 1.000 -ATOM 2730 H2 TIP3 3085 4.739 -16.145 -18.019 0.417 1.000 -ATOM 2731 OH2 TIP3 3086 -0.607 -14.241 -18.315 -0.834 1.520 -ATOM 2732 H1 TIP3 3086 -0.998 -15.112 -18.282 0.417 1.000 -ATOM 2733 H2 TIP3 3086 -0.684 -13.918 -17.414 0.417 1.000 -ATOM 2734 OH2 TIP3 3091 -1.363 -11.010 -15.384 -0.834 1.520 -ATOM 2735 H1 TIP3 3091 -2.214 -11.379 -15.487 0.417 1.000 -ATOM 2736 H2 TIP3 3091 -1.406 -10.067 -15.375 0.417 1.000 -ATOM 2737 OH2 TIP3 3092 11.077 -6.160 1.323 -0.834 1.520 -ATOM 2738 H1 TIP3 3092 11.122 -6.696 2.148 0.417 1.000 -ATOM 2739 H2 TIP3 3092 11.515 -5.357 1.528 0.417 1.000 -ATOM 2740 OH2 TIP3 3095 5.917 -11.103 1.213 -0.834 1.520 -ATOM 2741 H1 TIP3 3095 5.210 -11.664 1.602 0.417 1.000 -ATOM 2742 H2 TIP3 3095 5.993 -10.348 1.819 0.417 1.000 -ATOM 2743 OH2 TIP3 3096 -6.669 -15.437 3.416 -0.834 1.520 -ATOM 2744 H1 TIP3 3096 -5.685 -15.228 3.360 0.417 1.000 -ATOM 2745 H2 TIP3 3096 -6.785 -16.322 3.134 0.417 1.000 -ATOM 2746 OH2 TIP3 3097 8.116 -17.558 1.242 -0.834 1.520 -ATOM 2747 H1 TIP3 3097 9.109 -17.560 0.963 0.417 1.000 -ATOM 2748 H2 TIP3 3097 7.651 -17.370 0.470 0.417 1.000 -ATOM 2749 OH2 TIP3 3108 -1.590 -18.027 -11.420 -0.834 1.520 -ATOM 2750 H1 TIP3 3108 -1.342 -17.085 -11.477 0.417 1.000 -ATOM 2751 H2 TIP3 3108 -1.212 -18.433 -12.250 0.417 1.000 -ATOM 2752 OH2 TIP3 3109 2.635 1.010 -17.098 -0.834 1.520 -ATOM 2753 H1 TIP3 3109 2.191 1.343 -17.926 0.417 1.000 -ATOM 2754 H2 TIP3 3109 1.968 0.900 -16.447 0.417 1.000 -ATOM 2755 OH2 TIP3 3111 5.022 -4.978 -13.649 -0.834 1.520 -ATOM 2756 H1 TIP3 3111 5.811 -5.292 -13.043 0.417 1.000 -ATOM 2757 H2 TIP3 3111 4.417 -5.728 -13.596 0.417 1.000 -ATOM 2758 OH2 TIP3 3112 7.034 -6.430 -7.429 -0.834 1.520 -ATOM 2759 H1 TIP3 3112 6.603 -6.608 -6.549 0.417 1.000 -ATOM 2760 H2 TIP3 3112 7.165 -5.453 -7.443 0.417 1.000 -ATOM 2761 OH2 TIP3 3113 2.270 -6.168 2.593 -0.834 1.520 -ATOM 2762 H1 TIP3 3113 1.856 -7.023 2.328 0.417 1.000 -ATOM 2763 H2 TIP3 3113 1.777 -5.963 3.436 0.417 1.000 -ATOM 2764 OH2 TIP3 3114 7.885 -12.638 -6.088 -0.834 1.520 -ATOM 2765 H1 TIP3 3114 7.855 -11.652 -5.985 0.417 1.000 -ATOM 2766 H2 TIP3 3114 7.734 -12.961 -5.175 0.417 1.000 -ATOM 2767 OH2 TIP3 3115 1.606 -9.701 -10.636 -0.834 1.520 -ATOM 2768 H1 TIP3 3115 2.239 -10.380 -10.471 0.417 1.000 -ATOM 2769 H2 TIP3 3115 0.962 -9.778 -9.901 0.417 1.000 -ATOM 2770 OH2 TIP3 3116 9.353 -2.993 -3.791 -0.834 1.520 -ATOM 2771 H1 TIP3 3116 9.824 -2.142 -3.986 0.417 1.000 -ATOM 2772 H2 TIP3 3116 8.983 -2.876 -2.909 0.417 1.000 -ATOM 2773 OH2 TIP3 3119 9.131 -17.734 5.022 -0.834 1.520 -ATOM 2774 H1 TIP3 3119 8.503 -17.550 5.750 0.417 1.000 -ATOM 2775 H2 TIP3 3119 8.526 -18.082 4.334 0.417 1.000 -ATOM 2776 OH2 TIP3 3121 -10.163 -14.878 17.608 -0.834 1.520 -ATOM 2777 H1 TIP3 3121 -10.365 -13.977 17.219 0.417 1.000 -ATOM 2778 H2 TIP3 3121 -9.288 -15.023 17.286 0.417 1.000 -ATOM 2779 OH2 TIP3 3129 4.355 -11.463 -17.874 -0.834 1.520 -ATOM 2780 H1 TIP3 3129 4.816 -11.037 -18.577 0.417 1.000 -ATOM 2781 H2 TIP3 3129 4.086 -12.364 -18.172 0.417 1.000 -ATOM 2782 OH2 TIP3 3131 2.645 -7.781 -16.872 -0.834 1.520 -ATOM 2783 H1 TIP3 3131 1.963 -7.185 -16.501 0.417 1.000 -ATOM 2784 H2 TIP3 3131 2.260 -8.726 -16.685 0.417 1.000 -ATOM 2785 OH2 TIP3 3134 -8.599 1.480 -2.864 -0.834 1.520 -ATOM 2786 H1 TIP3 3134 -8.478 2.112 -2.144 0.417 1.000 -ATOM 2787 H2 TIP3 3134 -8.745 0.672 -2.364 0.417 1.000 -ATOM 2788 OH2 TIP3 3136 -8.713 -18.565 12.202 -0.834 1.520 -ATOM 2789 H1 TIP3 3136 -8.892 -19.166 12.927 0.417 1.000 -ATOM 2790 H2 TIP3 3136 -7.696 -18.588 12.059 0.417 1.000 -ATOM 2791 OH2 TIP3 3138 18.246 -6.323 3.324 -0.834 1.520 -ATOM 2792 H1 TIP3 3138 19.156 -6.048 3.010 0.417 1.000 -ATOM 2793 H2 TIP3 3138 17.828 -6.631 2.503 0.417 1.000 -ATOM 2794 OH2 TIP3 3139 -0.094 -17.234 9.558 -0.834 1.520 -ATOM 2795 H1 TIP3 3139 -0.018 -17.998 10.079 0.417 1.000 -ATOM 2796 H2 TIP3 3139 -0.835 -17.441 8.924 0.417 1.000 -ATOM 2797 OH2 TIP3 3140 4.170 -18.321 1.197 -0.834 1.520 -ATOM 2798 H1 TIP3 3140 4.257 -18.009 2.097 0.417 1.000 -ATOM 2799 H2 TIP3 3140 4.268 -19.244 1.263 0.417 1.000 -ATOM 2800 OH2 TIP3 3142 6.496 -13.441 13.805 -0.834 1.520 -ATOM 2801 H1 TIP3 3142 5.805 -13.694 14.480 0.417 1.000 -ATOM 2802 H2 TIP3 3142 7.375 -13.567 14.338 0.417 1.000 -ATOM 2803 OH2 TIP3 3143 -2.406 -16.456 19.059 -0.834 1.520 -ATOM 2804 H1 TIP3 3143 -3.370 -16.417 18.930 0.417 1.000 -ATOM 2805 H2 TIP3 3143 -2.110 -15.759 18.477 0.417 1.000 -ATOM 2806 OH2 TIP3 3150 -2.209 -7.740 -15.255 -0.834 1.520 -ATOM 2807 H1 TIP3 3150 -2.671 -6.905 -15.387 0.417 1.000 -ATOM 2808 H2 TIP3 3150 -1.996 -7.698 -14.372 0.417 1.000 -ATOM 2809 OH2 TIP3 3152 2.125 -16.538 -9.547 -0.834 1.520 -ATOM 2810 H1 TIP3 3152 1.341 -16.035 -9.153 0.417 1.000 -ATOM 2811 H2 TIP3 3152 2.548 -15.773 -9.979 0.417 1.000 -ATOM 2812 OH2 TIP3 3154 4.178 -8.790 -3.421 -0.834 1.520 -ATOM 2813 H1 TIP3 3154 5.024 -8.602 -2.974 0.417 1.000 -ATOM 2814 H2 TIP3 3154 4.455 -8.963 -4.352 0.417 1.000 -ATOM 2815 OH2 TIP3 3155 5.254 6.275 2.147 -0.834 1.520 -ATOM 2816 H1 TIP3 3155 5.872 6.369 1.396 0.417 1.000 -ATOM 2817 H2 TIP3 3155 5.551 5.476 2.594 0.417 1.000 -ATOM 2818 OH2 TIP3 3156 8.890 2.243 7.795 -0.834 1.520 -ATOM 2819 H1 TIP3 3156 9.114 2.850 7.064 0.417 1.000 -ATOM 2820 H2 TIP3 3156 9.516 1.585 7.824 0.417 1.000 -ATOM 2821 OH2 TIP3 3157 2.023 7.254 -6.788 -0.834 1.520 -ATOM 2822 H1 TIP3 3157 2.008 7.284 -7.723 0.417 1.000 -ATOM 2823 H2 TIP3 3157 2.707 7.959 -6.570 0.417 1.000 -ATOM 2824 OH2 TIP3 3158 -2.116 -3.737 9.508 -0.834 1.520 -ATOM 2825 H1 TIP3 3158 -2.851 -3.277 9.070 0.417 1.000 -ATOM 2826 H2 TIP3 3158 -1.683 -4.042 8.695 0.417 1.000 -ATOM 2827 OH2 TIP3 3160 8.983 -4.584 15.557 -0.834 1.520 -ATOM 2828 H1 TIP3 3160 9.732 -4.083 15.260 0.417 1.000 -ATOM 2829 H2 TIP3 3160 8.272 -3.946 15.423 0.417 1.000 -ATOM 2830 OH2 TIP3 3161 -0.931 -11.228 8.945 -0.834 1.520 -ATOM 2831 H1 TIP3 3161 -0.314 -11.632 9.594 0.417 1.000 -ATOM 2832 H2 TIP3 3161 -1.601 -11.866 8.762 0.417 1.000 -ATOM 2833 OH2 TIP3 3173 -7.924 -15.355 -6.434 -0.834 1.520 -ATOM 2834 H1 TIP3 3173 -8.000 -14.478 -6.852 0.417 1.000 -ATOM 2835 H2 TIP3 3173 -8.173 -15.165 -5.557 0.417 1.000 -ATOM 2836 OH2 TIP3 3174 9.320 -5.897 -3.171 -0.834 1.520 -ATOM 2837 H1 TIP3 3174 9.585 -5.816 -2.215 0.417 1.000 -ATOM 2838 H2 TIP3 3174 9.594 -5.005 -3.568 0.417 1.000 -ATOM 2839 OH2 TIP3 3175 10.419 -2.121 16.837 -0.834 1.520 -ATOM 2840 H1 TIP3 3175 10.268 -2.517 17.712 0.417 1.000 -ATOM 2841 H2 TIP3 3175 9.631 -1.552 16.760 0.417 1.000 -ATOM 2842 OH2 TIP3 3176 16.521 -1.853 -18.889 -0.834 1.520 -ATOM 2843 H1 TIP3 3176 16.496 -0.915 -18.899 0.417 1.000 -ATOM 2844 H2 TIP3 3176 15.815 -2.083 -18.333 0.417 1.000 -ATOM 2845 OH2 TIP3 3177 -10.869 -18.925 -4.159 -0.834 1.520 -ATOM 2846 H1 TIP3 3177 -10.052 -18.537 -4.588 0.417 1.000 -ATOM 2847 H2 TIP3 3177 -10.887 -19.839 -4.536 0.417 1.000 -ATOM 2848 OH2 TIP3 3178 9.503 7.905 4.858 -0.834 1.520 -ATOM 2849 H1 TIP3 3178 9.654 8.084 5.814 0.417 1.000 -ATOM 2850 H2 TIP3 3178 8.893 7.106 4.845 0.417 1.000 -ATOM 2851 OH2 TIP3 3179 -1.752 4.644 0.171 -0.834 1.520 -ATOM 2852 H1 TIP3 3179 -2.174 5.152 -0.539 0.417 1.000 -ATOM 2853 H2 TIP3 3179 -1.836 3.727 -0.164 0.417 1.000 -ATOM 2854 OH2 TIP3 3180 4.663 -1.034 -0.928 -0.834 1.520 -ATOM 2855 H1 TIP3 3180 4.078 -0.751 -1.619 0.417 1.000 -ATOM 2856 H2 TIP3 3180 4.908 -1.975 -1.190 0.417 1.000 -ATOM 2857 OH2 TIP3 3181 -3.661 -8.738 5.272 -0.834 1.520 -ATOM 2858 H1 TIP3 3181 -3.701 -9.359 4.513 0.417 1.000 -ATOM 2859 H2 TIP3 3181 -3.936 -9.341 5.958 0.417 1.000 -ATOM 2860 OH2 TIP3 3182 10.866 4.333 11.715 -0.834 1.520 -ATOM 2861 H1 TIP3 3182 10.291 4.860 11.204 0.417 1.000 -ATOM 2862 H2 TIP3 3182 10.943 3.530 11.132 0.417 1.000 -ATOM 2863 OH2 TIP3 3183 2.338 -11.596 12.676 -0.834 1.520 -ATOM 2864 H1 TIP3 3183 2.496 -12.455 13.182 0.417 1.000 -ATOM 2865 H2 TIP3 3183 3.035 -11.030 12.963 0.417 1.000 -ATOM 2866 OH2 TIP3 3184 -14.095 -4.067 12.791 -0.834 1.520 -ATOM 2867 H1 TIP3 3184 -14.027 -3.328 13.406 0.417 1.000 -ATOM 2868 H2 TIP3 3184 -14.321 -4.839 13.336 0.417 1.000 -ATOM 2869 OH2 TIP3 3187 11.175 -13.295 -7.411 -0.834 1.520 -ATOM 2870 H1 TIP3 3187 11.233 -12.872 -8.324 0.417 1.000 -ATOM 2871 H2 TIP3 3187 10.501 -14.026 -7.611 0.417 1.000 -ATOM 2872 OH2 TIP3 3189 -3.439 -5.988 14.908 -0.834 1.520 -ATOM 2873 H1 TIP3 3189 -4.198 -5.655 15.417 0.417 1.000 -ATOM 2874 H2 TIP3 3189 -3.485 -6.910 14.965 0.417 1.000 -ATOM 2875 OH2 TIP3 3192 3.294 -3.286 -11.647 -0.834 1.520 -ATOM 2876 H1 TIP3 3192 3.759 -2.525 -11.329 0.417 1.000 -ATOM 2877 H2 TIP3 3192 4.011 -3.670 -12.048 0.417 1.000 -ATOM 2878 OH2 TIP3 3193 19.192 7.065 -5.877 -0.834 1.520 -ATOM 2879 H1 TIP3 3193 19.122 6.450 -6.610 0.417 1.000 -ATOM 2880 H2 TIP3 3193 19.538 6.461 -5.188 0.417 1.000 -ATOM 2881 OH2 TIP3 3195 2.513 4.059 -1.016 -0.834 1.520 -ATOM 2882 H1 TIP3 3195 3.107 4.881 -1.044 0.417 1.000 -ATOM 2883 H2 TIP3 3195 1.878 4.220 -0.286 0.417 1.000 -ATOM 2884 OH2 TIP3 3196 -12.306 -11.662 -3.313 -0.834 1.520 -ATOM 2885 H1 TIP3 3196 -12.677 -11.919 -2.492 0.417 1.000 -ATOM 2886 H2 TIP3 3196 -13.009 -11.524 -3.928 0.417 1.000 -ATOM 2887 OH2 TIP3 3197 -4.443 12.531 -2.210 -0.834 1.520 -ATOM 2888 H1 TIP3 3197 -3.542 12.883 -2.545 0.417 1.000 -ATOM 2889 H2 TIP3 3197 -4.760 11.941 -2.968 0.417 1.000 -ATOM 2890 OH2 TIP3 3198 -2.945 -7.061 -0.247 -0.834 1.520 -ATOM 2891 H1 TIP3 3198 -2.961 -8.039 -0.450 0.417 1.000 -ATOM 2892 H2 TIP3 3198 -1.990 -6.871 -0.456 0.417 1.000 -ATOM 2893 OH2 TIP3 3199 11.147 15.582 7.692 -0.834 1.520 -ATOM 2894 H1 TIP3 3199 11.959 16.047 7.697 0.417 1.000 -ATOM 2895 H2 TIP3 3199 11.357 14.665 7.740 0.417 1.000 -ATOM 2896 OH2 TIP3 3200 15.853 4.245 -5.160 -0.834 1.520 -ATOM 2897 H1 TIP3 3200 15.833 3.388 -4.720 0.417 1.000 -ATOM 2898 H2 TIP3 3200 15.889 3.988 -6.115 0.417 1.000 -ATOM 2899 OH2 TIP3 3201 5.032 3.820 12.217 -0.834 1.520 -ATOM 2900 H1 TIP3 3201 4.738 4.411 11.470 0.417 1.000 -ATOM 2901 H2 TIP3 3201 5.931 4.128 12.387 0.417 1.000 -ATOM 2902 OH2 TIP3 3202 5.872 2.902 -1.402 -0.834 1.520 -ATOM 2903 H1 TIP3 3202 6.770 2.404 -1.282 0.417 1.000 -ATOM 2904 H2 TIP3 3202 5.176 2.248 -1.501 0.417 1.000 -ATOM 2905 OH2 TIP3 3203 11.371 0.493 12.276 -0.834 1.520 -ATOM 2906 H1 TIP3 3203 10.719 0.309 11.600 0.417 1.000 -ATOM 2907 H2 TIP3 3203 12.011 1.039 11.867 0.417 1.000 -ATOM 2908 OH2 TIP3 3204 -0.008 9.459 13.269 -0.834 1.520 -ATOM 2909 H1 TIP3 3204 -0.942 9.216 13.497 0.417 1.000 -ATOM 2910 H2 TIP3 3204 0.183 10.155 13.886 0.417 1.000 -ATOM 2911 OH2 TIP3 3205 7.205 -2.704 14.051 -0.834 1.520 -ATOM 2912 H1 TIP3 3205 6.828 -1.978 14.599 0.417 1.000 -ATOM 2913 H2 TIP3 3205 6.431 -2.967 13.469 0.417 1.000 -ATOM 2914 OH2 TIP3 3210 1.944 -9.429 19.387 -0.834 1.520 -ATOM 2915 H1 TIP3 3210 1.370 -9.907 19.974 0.417 1.000 -ATOM 2916 H2 TIP3 3210 2.066 -10.048 18.625 0.417 1.000 -ATOM 2917 OH2 TIP3 3214 4.647 -7.840 -13.525 -0.834 1.520 -ATOM 2918 H1 TIP3 3214 4.753 -8.240 -14.361 0.417 1.000 -ATOM 2919 H2 TIP3 3214 5.517 -7.507 -13.337 0.417 1.000 -ATOM 2920 OH2 TIP3 3215 -0.013 -0.926 -5.059 -0.834 1.520 -ATOM 2921 H1 TIP3 3215 -0.831 -0.652 -4.691 0.417 1.000 -ATOM 2922 H2 TIP3 3215 0.655 -0.477 -4.533 0.417 1.000 -ATOM 2923 OH2 TIP3 3216 4.248 8.156 4.606 -0.834 1.520 -ATOM 2924 H1 TIP3 3216 3.326 8.246 4.557 0.417 1.000 -ATOM 2925 H2 TIP3 3216 4.522 8.264 3.722 0.417 1.000 -ATOM 2926 OH2 TIP3 3218 -8.088 -6.788 -0.274 -0.834 1.520 -ATOM 2927 H1 TIP3 3218 -7.146 -6.775 -0.119 0.417 1.000 -ATOM 2928 H2 TIP3 3218 -8.496 -7.236 0.555 0.417 1.000 -ATOM 2929 OH2 TIP3 3219 1.300 -2.592 3.235 -0.834 1.520 -ATOM 2930 H1 TIP3 3219 0.535 -2.924 2.776 0.417 1.000 -ATOM 2931 H2 TIP3 3219 1.183 -3.037 4.104 0.417 1.000 -ATOM 2932 OH2 TIP3 3220 2.705 14.717 -10.818 -0.834 1.520 -ATOM 2933 H1 TIP3 3220 3.278 15.331 -11.298 0.417 1.000 -ATOM 2934 H2 TIP3 3220 3.304 14.311 -10.142 0.417 1.000 -ATOM 2935 OH2 TIP3 3221 -1.733 1.738 19.016 -0.834 1.520 -ATOM 2936 H1 TIP3 3221 -1.397 2.610 18.851 0.417 1.000 -ATOM 2937 H2 TIP3 3221 -0.911 1.151 18.956 0.417 1.000 -ATOM 2938 OH2 TIP3 3222 6.607 3.205 9.543 -0.834 1.520 -ATOM 2939 H1 TIP3 3222 6.786 4.139 9.271 0.417 1.000 -ATOM 2940 H2 TIP3 3222 7.353 2.697 9.149 0.417 1.000 -ATOM 2941 OH2 TIP3 3223 -14.885 -0.180 2.632 -0.834 1.520 -ATOM 2942 H1 TIP3 3223 -15.730 -0.248 2.092 0.417 1.000 -ATOM 2943 H2 TIP3 3223 -14.200 -0.415 1.996 0.417 1.000 -ATOM 2944 OH2 TIP3 3224 3.721 -1.117 13.019 -0.834 1.520 -ATOM 2945 H1 TIP3 3224 2.924 -0.628 13.254 0.417 1.000 -ATOM 2946 H2 TIP3 3224 4.318 -0.492 12.617 0.417 1.000 -ATOM 2947 OH2 TIP3 3225 17.593 -3.159 17.197 -0.834 1.520 -ATOM 2948 H1 TIP3 3225 16.996 -2.815 17.832 0.417 1.000 -ATOM 2949 H2 TIP3 3225 18.385 -2.745 17.381 0.417 1.000 -ATOM 2950 OH2 TIP3 3226 -7.307 12.804 14.562 -0.834 1.520 -ATOM 2951 H1 TIP3 3226 -7.284 12.558 13.617 0.417 1.000 -ATOM 2952 H2 TIP3 3226 -6.855 12.069 15.024 0.417 1.000 -ATOM 2953 OH2 TIP3 3227 -6.440 -2.066 8.175 -0.834 1.520 -ATOM 2954 H1 TIP3 3227 -6.613 -1.137 8.340 0.417 1.000 -ATOM 2955 H2 TIP3 3227 -5.578 -2.096 8.682 0.417 1.000 -ATOM 2956 OH2 TIP3 3229 6.458 4.748 15.379 -0.834 1.520 -ATOM 2957 H1 TIP3 3229 7.244 4.814 15.919 0.417 1.000 -ATOM 2958 H2 TIP3 3229 5.726 5.082 15.994 0.417 1.000 -ATOM 2959 OH2 TIP3 3233 8.583 10.824 -16.317 -0.834 1.520 -ATOM 2960 H1 TIP3 3233 8.557 10.908 -15.305 0.417 1.000 -ATOM 2961 H2 TIP3 3233 9.160 10.067 -16.388 0.417 1.000 -ATOM 2962 OH2 TIP3 3234 -3.682 2.811 -11.445 -0.834 1.520 -ATOM 2963 H1 TIP3 3234 -3.968 3.275 -10.656 0.417 1.000 -ATOM 2964 H2 TIP3 3234 -2.714 2.916 -11.418 0.417 1.000 -ATOM 2965 OH2 TIP3 3236 -7.386 7.273 -6.304 -0.834 1.520 -ATOM 2966 H1 TIP3 3236 -6.876 7.950 -6.693 0.417 1.000 -ATOM 2967 H2 TIP3 3236 -7.932 7.765 -5.707 0.417 1.000 -ATOM 2968 OH2 TIP3 3237 1.939 1.100 -4.672 -0.834 1.520 -ATOM 2969 H1 TIP3 3237 2.635 0.640 -5.179 0.417 1.000 -ATOM 2970 H2 TIP3 3237 2.375 1.374 -3.820 0.417 1.000 -ATOM 2971 OH2 TIP3 3238 7.007 5.179 -0.237 -0.834 1.520 -ATOM 2972 H1 TIP3 3238 6.673 4.409 -0.768 0.417 1.000 -ATOM 2973 H2 TIP3 3238 7.930 5.173 -0.543 0.417 1.000 -ATOM 2974 OH2 TIP3 3239 8.419 15.932 -3.784 -0.834 1.520 -ATOM 2975 H1 TIP3 3239 9.084 16.176 -4.443 0.417 1.000 -ATOM 2976 H2 TIP3 3239 7.622 16.176 -4.151 0.417 1.000 -ATOM 2977 OH2 TIP3 3240 -4.214 8.405 -0.705 -0.834 1.520 -ATOM 2978 H1 TIP3 3240 -4.857 9.196 -0.625 0.417 1.000 -ATOM 2979 H2 TIP3 3240 -4.275 8.200 -1.660 0.417 1.000 -ATOM 2980 OH2 TIP3 3241 0.882 11.566 -12.500 -0.834 1.520 -ATOM 2981 H1 TIP3 3241 1.771 11.259 -12.636 0.417 1.000 -ATOM 2982 H2 TIP3 3241 1.048 12.516 -12.610 0.417 1.000 -ATOM 2983 OH2 TIP3 3242 -1.210 -0.672 -0.896 -0.834 1.520 -ATOM 2984 H1 TIP3 3242 -1.736 -0.728 -0.114 0.417 1.000 -ATOM 2985 H2 TIP3 3242 -1.414 -1.472 -1.402 0.417 1.000 -ATOM 2986 OH2 TIP3 3243 9.487 11.469 -5.683 -0.834 1.520 -ATOM 2987 H1 TIP3 3243 8.967 12.221 -5.467 0.417 1.000 -ATOM 2988 H2 TIP3 3243 9.536 10.898 -4.878 0.417 1.000 -ATOM 2989 OH2 TIP3 3244 -0.713 2.590 -11.270 -0.834 1.520 -ATOM 2990 H1 TIP3 3244 -0.232 2.291 -11.966 0.417 1.000 -ATOM 2991 H2 TIP3 3244 -0.677 1.826 -10.633 0.417 1.000 -ATOM 2992 OH2 TIP3 3245 -10.000 -5.207 9.822 -0.834 1.520 -ATOM 2993 H1 TIP3 3245 -10.878 -5.274 9.406 0.417 1.000 -ATOM 2994 H2 TIP3 3245 -10.180 -4.696 10.640 0.417 1.000 -ATOM 2995 OH2 TIP3 3246 -0.780 -4.326 15.479 -0.834 1.520 -ATOM 2996 H1 TIP3 3246 -0.321 -4.929 14.897 0.417 1.000 -ATOM 2997 H2 TIP3 3246 -1.641 -4.608 15.439 0.417 1.000 -ATOM 2998 OH2 TIP3 3247 -4.823 7.294 6.773 -0.834 1.520 -ATOM 2999 H1 TIP3 3247 -4.781 6.636 7.565 0.417 1.000 -ATOM 3000 H2 TIP3 3247 -3.965 7.115 6.274 0.417 1.000 -ATOM 3001 OH2 TIP3 3257 6.173 6.160 -17.953 -0.834 1.520 -ATOM 3002 H1 TIP3 3257 5.814 7.030 -18.388 0.417 1.000 -ATOM 3003 H2 TIP3 3257 7.180 6.313 -18.001 0.417 1.000 -ATOM 3004 OH2 TIP3 3258 4.149 -1.112 -13.467 -0.834 1.520 -ATOM 3005 H1 TIP3 3258 4.021 -0.834 -14.399 0.417 1.000 -ATOM 3006 H2 TIP3 3258 5.032 -0.767 -13.278 0.417 1.000 -ATOM 3007 OH2 TIP3 3261 2.392 6.765 7.367 -0.834 1.520 -ATOM 3008 H1 TIP3 3261 1.649 7.484 7.268 0.417 1.000 -ATOM 3009 H2 TIP3 3261 2.874 7.108 8.071 0.417 1.000 -ATOM 3010 OH2 TIP3 3262 -4.796 3.340 -8.871 -0.834 1.520 -ATOM 3011 H1 TIP3 3262 -5.433 3.666 -8.159 0.417 1.000 -ATOM 3012 H2 TIP3 3262 -3.964 3.766 -8.618 0.417 1.000 -ATOM 3013 OH2 TIP3 3263 2.974 -8.613 5.453 -0.834 1.520 -ATOM 3014 H1 TIP3 3263 2.750 -7.707 5.160 0.417 1.000 -ATOM 3015 H2 TIP3 3263 2.131 -8.896 5.792 0.417 1.000 -ATOM 3016 OH2 TIP3 3264 -3.114 16.905 7.161 -0.834 1.520 -ATOM 3017 H1 TIP3 3264 -3.594 16.962 6.323 0.417 1.000 -ATOM 3018 H2 TIP3 3264 -3.702 17.368 7.757 0.417 1.000 -ATOM 3019 OH2 TIP3 3265 3.208 14.407 5.395 -0.834 1.520 -ATOM 3020 H1 TIP3 3265 4.083 13.970 5.343 0.417 1.000 -ATOM 3021 H2 TIP3 3265 2.947 14.231 6.346 0.417 1.000 -ATOM 3022 OH2 TIP3 3266 12.701 2.303 18.307 -0.834 1.520 -ATOM 3023 H1 TIP3 3266 12.114 1.754 18.844 0.417 1.000 -ATOM 3024 H2 TIP3 3266 13.510 1.724 18.221 0.417 1.000 -ATOM 3025 OH2 TIP3 3274 6.353 1.381 -15.560 -0.834 1.520 -ATOM 3026 H1 TIP3 3274 5.914 0.546 -15.729 0.417 1.000 -ATOM 3027 H2 TIP3 3274 5.689 1.985 -15.148 0.417 1.000 -ATOM 3028 OH2 TIP3 3280 5.090 2.311 -9.209 -0.834 1.520 -ATOM 3029 H1 TIP3 3280 5.958 2.594 -9.665 0.417 1.000 -ATOM 3030 H2 TIP3 3280 5.437 1.952 -8.332 0.417 1.000 -ATOM 3031 OH2 TIP3 3282 9.435 8.189 -8.513 -0.834 1.520 -ATOM 3032 H1 TIP3 3282 9.147 9.086 -8.564 0.417 1.000 -ATOM 3033 H2 TIP3 3282 9.190 7.885 -7.613 0.417 1.000 -ATOM 3034 OH2 TIP3 3283 3.782 19.218 -6.907 -0.834 1.520 -ATOM 3035 H1 TIP3 3283 3.139 19.036 -7.637 0.417 1.000 -ATOM 3036 H2 TIP3 3283 4.011 18.329 -6.606 0.417 1.000 -ATOM 3037 OH2 TIP3 3284 5.829 15.646 -1.832 -0.834 1.520 -ATOM 3038 H1 TIP3 3284 6.530 15.401 -1.148 0.417 1.000 -ATOM 3039 H2 TIP3 3284 5.718 16.638 -1.656 0.417 1.000 -ATOM 3040 OH2 TIP3 3285 15.307 15.122 2.062 -0.834 1.520 -ATOM 3041 H1 TIP3 3285 14.845 14.314 1.710 0.417 1.000 -ATOM 3042 H2 TIP3 3285 14.612 15.547 2.606 0.417 1.000 -ATOM 3043 OH2 TIP3 3286 15.633 2.799 8.763 -0.834 1.520 -ATOM 3044 H1 TIP3 3286 15.279 3.676 8.900 0.417 1.000 -ATOM 3045 H2 TIP3 3286 15.497 2.405 9.622 0.417 1.000 -ATOM 3046 OH2 TIP3 3287 -17.255 8.967 9.795 -0.834 1.520 -ATOM 3047 H1 TIP3 3287 -18.187 8.948 10.040 0.417 1.000 -ATOM 3048 H2 TIP3 3287 -16.968 9.865 10.120 0.417 1.000 -ATOM 3049 OH2 TIP3 3291 5.296 2.140 18.214 -0.834 1.520 -ATOM 3050 H1 TIP3 3291 5.098 2.097 17.242 0.417 1.000 -ATOM 3051 H2 TIP3 3291 6.213 2.144 18.202 0.417 1.000 -ATOM 3052 OH2 TIP3 3296 12.370 -0.997 -18.176 -0.834 1.520 -ATOM 3053 H1 TIP3 3296 12.660 -1.227 -19.123 0.417 1.000 -ATOM 3054 H2 TIP3 3296 11.974 -0.091 -18.275 0.417 1.000 -ATOM 3055 OH2 TIP3 3298 7.743 17.380 -14.522 -0.834 1.520 -ATOM 3056 H1 TIP3 3298 8.278 18.222 -14.380 0.417 1.000 -ATOM 3057 H2 TIP3 3298 7.645 17.266 -15.494 0.417 1.000 -ATOM 3058 OH2 TIP3 3301 12.733 10.590 -10.624 -0.834 1.520 -ATOM 3059 H1 TIP3 3301 12.538 10.142 -11.436 0.417 1.000 -ATOM 3060 H2 TIP3 3301 13.111 9.846 -10.097 0.417 1.000 -ATOM 3061 OH2 TIP3 3302 4.767 7.580 -15.480 -0.834 1.520 -ATOM 3062 H1 TIP3 3302 4.390 6.725 -15.689 0.417 1.000 -ATOM 3063 H2 TIP3 3302 4.787 7.986 -16.355 0.417 1.000 -ATOM 3064 OH2 TIP3 3303 -5.830 3.047 0.478 -0.834 1.520 -ATOM 3065 H1 TIP3 3303 -4.985 2.883 0.902 0.417 1.000 -ATOM 3066 H2 TIP3 3303 -6.243 2.177 0.579 0.417 1.000 -ATOM 3067 OH2 TIP3 3304 -6.837 0.489 0.636 -0.834 1.520 -ATOM 3068 H1 TIP3 3304 -7.550 0.171 0.104 0.417 1.000 -ATOM 3069 H2 TIP3 3304 -6.780 -0.125 1.393 0.417 1.000 -ATOM 3070 OH2 TIP3 3305 -3.720 1.031 7.412 -0.834 1.520 -ATOM 3071 H1 TIP3 3305 -4.659 1.271 7.560 0.417 1.000 -ATOM 3072 H2 TIP3 3305 -3.720 1.124 6.419 0.417 1.000 -ATOM 3073 OH2 TIP3 3306 6.330 6.152 9.299 -0.834 1.520 -ATOM 3074 H1 TIP3 3306 5.913 6.992 9.061 0.417 1.000 -ATOM 3075 H2 TIP3 3306 5.617 5.760 9.754 0.417 1.000 -ATOM 3076 OH2 TIP3 3307 8.097 9.556 12.589 -0.834 1.520 -ATOM 3077 H1 TIP3 3307 8.754 9.669 11.895 0.417 1.000 -ATOM 3078 H2 TIP3 3307 8.513 9.950 13.310 0.417 1.000 -ATOM 3079 OH2 TIP3 3308 9.510 18.708 -0.676 -0.834 1.520 -ATOM 3080 H1 TIP3 3308 10.347 19.166 -0.983 0.417 1.000 -ATOM 3081 H2 TIP3 3308 9.207 18.357 -1.520 0.417 1.000 -ATOM 3082 OH2 TIP3 3310 -6.944 11.407 18.941 -0.834 1.520 -ATOM 3083 H1 TIP3 3310 -7.190 11.307 19.873 0.417 1.000 -ATOM 3084 H2 TIP3 3310 -6.290 10.737 18.787 0.417 1.000 -ATOM 3085 OH2 TIP3 3317 12.713 6.595 -17.591 -0.834 1.520 -ATOM 3086 H1 TIP3 3317 13.443 6.598 -18.204 0.417 1.000 -ATOM 3087 H2 TIP3 3317 12.159 5.868 -17.831 0.417 1.000 -ATOM 3088 OH2 TIP3 3319 2.940 14.912 -17.316 -0.834 1.520 -ATOM 3089 H1 TIP3 3319 3.335 14.036 -17.466 0.417 1.000 -ATOM 3090 H2 TIP3 3319 2.084 14.834 -17.682 0.417 1.000 -ATOM 3091 OH2 TIP3 3321 2.821 14.248 -5.771 -0.834 1.520 -ATOM 3092 H1 TIP3 3321 2.847 13.705 -4.945 0.417 1.000 -ATOM 3093 H2 TIP3 3321 2.283 15.020 -5.359 0.417 1.000 -ATOM 3094 OH2 TIP3 3322 0.476 15.705 -15.355 -0.834 1.520 -ATOM 3095 H1 TIP3 3322 -0.320 15.570 -15.913 0.417 1.000 -ATOM 3096 H2 TIP3 3322 0.828 16.523 -15.698 0.417 1.000 -ATOM 3097 OH2 TIP3 3325 14.105 16.903 7.844 -0.834 1.520 -ATOM 3098 H1 TIP3 3325 14.244 17.892 7.722 0.417 1.000 -ATOM 3099 H2 TIP3 3325 14.912 16.594 7.383 0.417 1.000 -ATOM 3100 OH2 TIP3 3326 1.948 15.554 -2.109 -0.834 1.520 -ATOM 3101 H1 TIP3 3326 2.717 15.377 -1.590 0.417 1.000 -ATOM 3102 H2 TIP3 3326 1.530 16.190 -1.504 0.417 1.000 -ATOM 3103 OH2 TIP3 3327 -8.740 17.650 9.834 -0.834 1.520 -ATOM 3104 H1 TIP3 3327 -8.171 18.387 9.997 0.417 1.000 -ATOM 3105 H2 TIP3 3327 -8.734 17.189 10.668 0.417 1.000 -ATOM 3106 OH2 TIP3 3331 2.641 3.390 8.573 -0.834 1.520 -ATOM 3107 H1 TIP3 3331 1.932 3.613 7.913 0.417 1.000 -ATOM 3108 H2 TIP3 3331 3.462 3.561 8.011 0.417 1.000 -ATOM 3109 OH2 TIP3 3341 0.039 14.865 -11.770 -0.834 1.520 -ATOM 3110 H1 TIP3 3341 0.969 14.652 -11.619 0.417 1.000 -ATOM 3111 H2 TIP3 3341 -0.410 14.352 -11.049 0.417 1.000 -ATOM 3112 OH2 TIP3 3342 -6.120 12.413 -10.947 -0.834 1.520 -ATOM 3113 H1 TIP3 3342 -6.887 12.809 -10.546 0.417 1.000 -ATOM 3114 H2 TIP3 3342 -6.460 11.667 -11.547 0.417 1.000 -ATOM 3115 OH2 TIP3 3344 3.196 18.709 -11.576 -0.834 1.520 -ATOM 3116 H1 TIP3 3344 3.539 17.839 -11.882 0.417 1.000 -ATOM 3117 H2 TIP3 3344 2.601 19.066 -12.325 0.417 1.000 -ATOM 3118 OH2 TIP3 3346 11.502 13.556 9.930 -0.834 1.520 -ATOM 3119 H1 TIP3 3346 10.719 13.799 10.505 0.417 1.000 -ATOM 3120 H2 TIP3 3346 12.094 14.329 9.973 0.417 1.000 -ATOM 3121 OH2 TIP3 3347 3.824 8.288 1.326 -0.834 1.520 -ATOM 3122 H1 TIP3 3347 3.081 7.755 1.061 0.417 1.000 -ATOM 3123 H2 TIP3 3347 4.386 7.611 1.752 0.417 1.000 -ATOM 3124 OH2 TIP3 3348 11.386 9.854 0.289 -0.834 1.520 -ATOM 3125 H1 TIP3 3348 11.241 9.291 1.089 0.417 1.000 -ATOM 3126 H2 TIP3 3348 10.965 10.697 0.583 0.417 1.000 -ATOM 3127 OH2 TIP3 3349 -4.743 15.885 1.557 -0.834 1.520 -ATOM 3128 H1 TIP3 3349 -5.635 16.151 1.787 0.417 1.000 -ATOM 3129 H2 TIP3 3349 -4.867 15.206 0.896 0.417 1.000 -ATOM 3130 OH2 TIP3 3354 8.719 3.045 14.191 -0.834 1.520 -ATOM 3131 H1 TIP3 3354 9.021 3.376 15.032 0.417 1.000 -ATOM 3132 H2 TIP3 3354 8.093 3.809 13.941 0.417 1.000 -ATOM 3133 OH2 TIP3 3355 7.584 18.273 13.328 -0.834 1.520 -ATOM 3134 H1 TIP3 3355 8.182 17.595 13.635 0.417 1.000 -ATOM 3135 H2 TIP3 3355 7.542 18.939 14.090 0.417 1.000 -ATOM 3136 OH2 TIP3 3360 -6.296 14.221 -18.664 -0.834 1.520 -ATOM 3137 H1 TIP3 3360 -7.201 13.899 -18.594 0.417 1.000 -ATOM 3138 H2 TIP3 3360 -6.435 15.045 -19.002 0.417 1.000 -ATOM 3139 OH2 TIP3 3361 16.938 12.388 -12.789 -0.834 1.520 -ATOM 3140 H1 TIP3 3361 16.351 12.372 -13.508 0.417 1.000 -ATOM 3141 H2 TIP3 3361 16.380 11.959 -12.054 0.417 1.000 -ATOM 3142 OH2 TIP3 3362 15.592 19.396 -5.750 -0.834 1.520 -ATOM 3143 H1 TIP3 3362 15.721 18.731 -5.066 0.417 1.000 -ATOM 3144 H2 TIP3 3362 14.608 19.476 -5.822 0.417 1.000 -ATOM 3145 OH2 TIP3 3364 4.484 16.412 -7.049 -0.834 1.520 -ATOM 3146 H1 TIP3 3364 4.485 16.471 -8.026 0.417 1.000 -ATOM 3147 H2 TIP3 3364 4.158 15.531 -6.932 0.417 1.000 -ATOM 3148 OH2 TIP3 3365 -5.278 11.521 3.300 -0.834 1.520 -ATOM 3149 H1 TIP3 3365 -5.073 11.386 2.378 0.417 1.000 -ATOM 3150 H2 TIP3 3365 -5.063 12.455 3.478 0.417 1.000 -ATOM 3151 OH2 TIP3 3367 1.063 7.441 0.605 -0.834 1.520 -ATOM 3152 H1 TIP3 3367 0.963 7.681 -0.336 0.417 1.000 -ATOM 3153 H2 TIP3 3367 0.342 7.928 0.966 0.417 1.000 -ATOM 3154 OH2 TIP3 3369 11.035 9.187 18.107 -0.834 1.520 -ATOM 3155 H1 TIP3 3369 11.918 8.994 17.751 0.417 1.000 -ATOM 3156 H2 TIP3 3369 10.832 9.960 17.584 0.417 1.000 -ATOM 3157 OH2 TIP3 3381 -3.343 18.461 -13.027 -0.834 1.520 -ATOM 3158 H1 TIP3 3381 -2.652 17.883 -12.653 0.417 1.000 -ATOM 3159 H2 TIP3 3381 -2.867 19.239 -13.300 0.417 1.000 -ATOM 3160 OH2 TIP3 3382 -3.963 10.640 -18.572 -0.834 1.520 -ATOM 3161 H1 TIP3 3382 -3.743 9.742 -18.476 0.417 1.000 -ATOM 3162 H2 TIP3 3382 -4.109 10.862 -17.613 0.417 1.000 -ATOM 3163 OH2 TIP3 3386 -7.440 16.914 -1.482 -0.834 1.520 -ATOM 3164 H1 TIP3 3386 -7.689 16.841 -0.540 0.417 1.000 -ATOM 3165 H2 TIP3 3386 -6.828 16.216 -1.656 0.417 1.000 -ATOM 3166 OH2 TIP3 3390 3.102 17.270 9.478 -0.834 1.520 -ATOM 3167 H1 TIP3 3390 2.345 16.778 9.860 0.417 1.000 -ATOM 3168 H2 TIP3 3390 3.430 17.711 10.304 0.417 1.000 -ATOM 3169 OH2 TIP3 3402 9.449 12.516 -18.554 -0.834 1.520 -ATOM 3170 H1 TIP3 3402 8.981 11.946 -17.918 0.417 1.000 -ATOM 3171 H2 TIP3 3402 9.079 12.287 -19.363 0.417 1.000 -ATOM 3172 OH2 TIP3 3407 12.538 16.315 -13.204 -0.834 1.520 -ATOM 3173 H1 TIP3 3407 11.589 16.133 -13.445 0.417 1.000 -ATOM 3174 H2 TIP3 3407 12.745 16.978 -13.943 0.417 1.000 -ATOM 3175 OH2 TIP3 3408 5.857 9.295 -8.119 -0.834 1.520 -ATOM 3176 H1 TIP3 3408 5.568 9.647 -8.984 0.417 1.000 -ATOM 3177 H2 TIP3 3408 6.103 8.399 -8.327 0.417 1.000 -ATOM 3178 OH2 TIP3 3426 -4.258 -18.175 -10.226 -0.834 1.520 -ATOM 3179 H1 TIP3 3426 -3.301 -18.446 -10.271 0.417 1.000 -ATOM 3180 H2 TIP3 3426 -4.751 -18.826 -9.629 0.417 1.000 -ATOM 3181 OH2 TIP3 3429 12.174 18.309 -15.121 -0.834 1.520 -ATOM 3182 H1 TIP3 3429 11.952 19.107 -15.632 0.417 1.000 -ATOM 3183 H2 TIP3 3429 12.026 18.641 -14.203 0.417 1.000 -ATOM 3184 OH2 TIP3 3434 3.636 -17.881 13.250 -0.834 1.520 -ATOM 3185 H1 TIP3 3434 3.720 -18.455 14.027 0.417 1.000 -ATOM 3186 H2 TIP3 3434 2.745 -17.597 13.252 0.417 1.000 -ATOM 3187 OH2 TIP3 3442 -3.430 -6.877 -18.044 -0.834 1.520 -ATOM 3188 H1 TIP3 3442 -2.520 -6.979 -18.452 0.417 1.000 -ATOM 3189 H2 TIP3 3442 -3.718 -5.904 -18.338 0.417 1.000 -ATOM 3190 OH2 TIP3 3447 -8.684 -17.727 -12.044 -0.834 1.520 -ATOM 3191 H1 TIP3 3447 -8.609 -18.642 -11.849 0.417 1.000 -ATOM 3192 H2 TIP3 3447 -9.577 -17.521 -11.819 0.417 1.000 -ATOM 3193 OH2 TIP3 3474 7.662 -18.594 11.356 -0.834 1.520 -ATOM 3194 H1 TIP3 3474 8.156 -18.449 10.505 0.417 1.000 -ATOM 3195 H2 TIP3 3474 8.399 -18.468 12.020 0.417 1.000 -ATOM 3196 OH2 TIP3 3476 10.937 -19.461 3.258 -0.834 1.520 -ATOM 3197 H1 TIP3 3476 11.561 -18.920 2.840 0.417 1.000 -ATOM 3198 H2 TIP3 3476 10.746 -19.011 4.107 0.417 1.000 -ATOM 3199 OH2 TIP3 3484 6.929 -17.058 -8.449 -0.834 1.520 -ATOM 3200 H1 TIP3 3484 7.470 -17.669 -8.955 0.417 1.000 -ATOM 3201 H2 TIP3 3484 6.250 -17.632 -8.048 0.417 1.000 -ATOM 3202 OH2 TIP3 3496 -1.365 -14.560 17.484 -0.834 1.520 -ATOM 3203 H1 TIP3 3496 -0.699 -13.859 17.377 0.417 1.000 -ATOM 3204 H2 TIP3 3496 -2.066 -14.222 16.946 0.417 1.000 -ATOM 3205 OH2 TIP3 3511 15.030 -9.953 -19.026 -0.834 1.520 -ATOM 3206 H1 TIP3 3511 15.212 -9.882 -18.080 0.417 1.000 -ATOM 3207 H2 TIP3 3511 14.099 -10.210 -19.053 0.417 1.000 -ATOM 3208 OH2 TIP3 3513 11.120 -7.431 -0.992 -0.834 1.520 -ATOM 3209 H1 TIP3 3513 11.055 -6.939 -0.104 0.417 1.000 -ATOM 3210 H2 TIP3 3513 11.846 -7.013 -1.468 0.417 1.000 -ATOM 3211 OH2 TIP3 3526 0.597 -5.368 -18.938 -0.834 1.520 -ATOM 3212 H1 TIP3 3526 1.521 -5.203 -18.586 0.417 1.000 -ATOM 3213 H2 TIP3 3526 0.147 -5.910 -18.280 0.417 1.000 -ATOM 3214 OH2 TIP3 3527 -1.662 -9.030 -9.881 -0.834 1.520 -ATOM 3215 H1 TIP3 3527 -0.912 -9.437 -9.468 0.417 1.000 -ATOM 3216 H2 TIP3 3527 -1.689 -9.409 -10.783 0.417 1.000 -ATOM 3217 OH2 TIP3 3533 16.855 -16.550 -15.932 -0.834 1.520 -ATOM 3218 H1 TIP3 3533 16.377 -17.127 -16.496 0.417 1.000 -ATOM 3219 H2 TIP3 3533 17.457 -16.152 -16.610 0.417 1.000 -ATOM 3220 OH2 TIP3 3534 1.664 -8.200 -7.213 -0.834 1.520 -ATOM 3221 H1 TIP3 3534 1.444 -7.476 -7.781 0.417 1.000 -ATOM 3222 H2 TIP3 3534 2.536 -8.468 -7.528 0.417 1.000 -ATOM 3223 OH2 TIP3 3537 -6.172 -9.878 13.931 -0.834 1.520 -ATOM 3224 H1 TIP3 3537 -6.340 -9.113 14.448 0.417 1.000 -ATOM 3225 H2 TIP3 3537 -6.555 -9.618 13.104 0.417 1.000 -ATOM 3226 OH2 TIP3 3545 -9.593 -13.351 -11.112 -0.834 1.520 -ATOM 3227 H1 TIP3 3545 -10.190 -12.785 -10.614 0.417 1.000 -ATOM 3228 H2 TIP3 3545 -8.923 -13.583 -10.453 0.417 1.000 -ATOM 3229 OH2 TIP3 3548 -2.183 -7.240 -12.578 -0.834 1.520 -ATOM 3230 H1 TIP3 3548 -1.894 -7.340 -11.612 0.417 1.000 -ATOM 3231 H2 TIP3 3548 -2.840 -6.517 -12.553 0.417 1.000 -ATOM 3232 OH2 TIP3 3554 -0.662 -10.156 -12.476 -0.834 1.520 -ATOM 3233 H1 TIP3 3554 -0.464 -10.789 -13.212 0.417 1.000 -ATOM 3234 H2 TIP3 3554 0.226 -9.867 -12.171 0.417 1.000 -ATOM 3235 OH2 TIP3 3555 8.615 -15.272 -3.578 -0.834 1.520 -ATOM 3236 H1 TIP3 3555 8.225 -16.019 -4.153 0.417 1.000 -ATOM 3237 H2 TIP3 3555 9.456 -15.164 -4.049 0.417 1.000 -ATOM 3238 OH2 TIP3 3556 1.245 -11.884 3.968 -0.834 1.520 -ATOM 3239 H1 TIP3 3556 1.257 -11.460 4.803 0.417 1.000 -ATOM 3240 H2 TIP3 3556 0.394 -12.328 3.868 0.417 1.000 -ATOM 3241 OH2 TIP3 3557 1.166 -4.178 6.322 -0.834 1.520 -ATOM 3242 H1 TIP3 3557 0.234 -3.995 6.686 0.417 1.000 -ATOM 3243 H2 TIP3 3557 1.754 -3.895 7.059 0.417 1.000 -ATOM 3244 OH2 TIP3 3558 9.568 -9.476 11.315 -0.834 1.520 -ATOM 3245 H1 TIP3 3558 9.760 -9.233 10.405 0.417 1.000 -ATOM 3246 H2 TIP3 3558 9.048 -10.308 11.270 0.417 1.000 -ATOM 3247 OH2 TIP3 3561 12.369 -14.725 10.147 -0.834 1.520 -ATOM 3248 H1 TIP3 3561 11.932 -13.978 9.735 0.417 1.000 -ATOM 3249 H2 TIP3 3561 13.298 -14.623 9.839 0.417 1.000 -ATOM 3250 OH2 TIP3 3563 14.432 -13.795 16.075 -0.834 1.520 -ATOM 3251 H1 TIP3 3563 15.229 -13.972 15.624 0.417 1.000 -ATOM 3252 H2 TIP3 3563 14.534 -12.793 16.324 0.417 1.000 -ATOM 3253 OH2 TIP3 3569 8.012 -14.434 -10.411 -0.834 1.520 -ATOM 3254 H1 TIP3 3569 8.394 -15.312 -10.312 0.417 1.000 -ATOM 3255 H2 TIP3 3569 8.330 -14.152 -11.287 0.417 1.000 -ATOM 3256 OH2 TIP3 3573 5.331 -10.120 -15.621 -0.834 1.520 -ATOM 3257 H1 TIP3 3573 5.003 -10.588 -16.448 0.417 1.000 -ATOM 3258 H2 TIP3 3573 5.326 -10.861 -14.956 0.417 1.000 -ATOM 3259 OH2 TIP3 3575 0.692 -1.258 -7.867 -0.834 1.520 -ATOM 3260 H1 TIP3 3575 0.174 -1.419 -7.053 0.417 1.000 -ATOM 3261 H2 TIP3 3575 0.895 -2.180 -8.145 0.417 1.000 -ATOM 3262 OH2 TIP3 3576 8.824 -10.422 14.277 -0.834 1.520 -ATOM 3263 H1 TIP3 3576 9.395 -11.161 14.092 0.417 1.000 -ATOM 3264 H2 TIP3 3576 8.903 -9.892 13.539 0.417 1.000 -ATOM 3265 OH2 TIP3 3579 12.304 -14.975 12.794 -0.834 1.520 -ATOM 3266 H1 TIP3 3579 13.262 -14.898 13.108 0.417 1.000 -ATOM 3267 H2 TIP3 3579 12.441 -15.135 11.819 0.417 1.000 -ATOM 3268 OH2 TIP3 3580 3.911 -3.110 16.592 -0.834 1.520 -ATOM 3269 H1 TIP3 3580 4.082 -3.804 15.963 0.417 1.000 -ATOM 3270 H2 TIP3 3580 3.767 -3.685 17.335 0.417 1.000 -ATOM 3271 OH2 TIP3 3582 12.381 -6.189 13.041 -0.834 1.520 -ATOM 3272 H1 TIP3 3582 12.766 -5.332 13.086 0.417 1.000 -ATOM 3273 H2 TIP3 3582 12.213 -6.361 13.965 0.417 1.000 -ATOM 3274 OH2 TIP3 3586 1.378 -6.976 18.454 -0.834 1.520 -ATOM 3275 H1 TIP3 3586 0.547 -7.171 17.981 0.417 1.000 -ATOM 3276 H2 TIP3 3586 1.598 -7.782 18.914 0.417 1.000 -ATOM 3277 OH2 TIP3 3592 -1.489 17.143 -11.665 -0.834 1.520 -ATOM 3278 H1 TIP3 3592 -0.930 16.307 -11.849 0.417 1.000 -ATOM 3279 H2 TIP3 3592 -1.793 16.991 -10.695 0.417 1.000 -ATOM 3280 OH2 TIP3 3593 12.013 -7.181 -18.277 -0.834 1.520 -ATOM 3281 H1 TIP3 3593 12.460 -6.480 -17.745 0.417 1.000 -ATOM 3282 H2 TIP3 3593 11.701 -7.823 -17.646 0.417 1.000 -ATOM 3283 OH2 TIP3 3595 3.999 -5.659 -8.781 -0.834 1.520 -ATOM 3284 H1 TIP3 3595 3.278 -5.411 -9.279 0.417 1.000 -ATOM 3285 H2 TIP3 3595 4.589 -4.919 -8.951 0.417 1.000 -ATOM 3286 OH2 TIP3 3596 -12.426 -0.580 -15.283 -0.834 1.520 -ATOM 3287 H1 TIP3 3596 -12.296 -0.665 -16.321 0.417 1.000 -ATOM 3288 H2 TIP3 3596 -12.030 0.255 -15.043 0.417 1.000 -ATOM 3289 OH2 TIP3 3597 -0.426 0.666 -9.283 -0.834 1.520 -ATOM 3290 H1 TIP3 3597 0.069 -0.098 -8.966 0.417 1.000 -ATOM 3291 H2 TIP3 3597 -1.173 0.684 -8.672 0.417 1.000 -ATOM 3292 OH2 TIP3 3599 6.427 -13.259 -0.696 -0.834 1.520 -ATOM 3293 H1 TIP3 3599 5.883 -13.835 -0.134 0.417 1.000 -ATOM 3294 H2 TIP3 3599 6.265 -12.402 -0.281 0.417 1.000 -ATOM 3295 OH2 TIP3 3600 3.864 0.095 5.624 -0.834 1.520 -ATOM 3296 H1 TIP3 3600 3.843 -0.333 6.488 0.417 1.000 -ATOM 3297 H2 TIP3 3600 4.751 0.351 5.601 0.417 1.000 -ATOM 3298 OH2 TIP3 3601 6.333 -0.644 10.407 -0.834 1.520 -ATOM 3299 H1 TIP3 3601 5.560 -0.189 9.912 0.417 1.000 -ATOM 3300 H2 TIP3 3601 6.320 -0.091 11.252 0.417 1.000 -ATOM 3301 OH2 TIP3 3603 0.844 -9.177 7.657 -0.834 1.520 -ATOM 3302 H1 TIP3 3603 0.261 -9.923 7.795 0.417 1.000 -ATOM 3303 H2 TIP3 3603 0.406 -8.447 8.084 0.417 1.000 -ATOM 3304 OH2 TIP3 3604 10.960 -5.317 17.453 -0.834 1.520 -ATOM 3305 H1 TIP3 3604 11.745 -5.605 16.912 0.417 1.000 -ATOM 3306 H2 TIP3 3604 10.257 -5.140 16.781 0.417 1.000 -ATOM 3307 OH2 TIP3 3612 7.212 -14.449 -18.038 -0.834 1.520 -ATOM 3308 H1 TIP3 3612 6.802 -14.880 -17.376 0.417 1.000 -ATOM 3309 H2 TIP3 3612 7.823 -13.884 -17.577 0.417 1.000 -ATOM 3310 OH2 TIP3 3614 3.131 -1.015 -6.319 -0.834 1.520 -ATOM 3311 H1 TIP3 3614 2.287 -1.216 -6.795 0.417 1.000 -ATOM 3312 H2 TIP3 3614 3.593 -1.855 -6.348 0.417 1.000 -ATOM 3313 OH2 TIP3 3615 4.227 -3.502 -6.350 -0.834 1.520 -ATOM 3314 H1 TIP3 3615 4.060 -4.209 -5.784 0.417 1.000 -ATOM 3315 H2 TIP3 3615 4.818 -3.853 -7.021 0.417 1.000 -ATOM 3316 OH2 TIP3 3617 9.059 10.470 6.160 -0.834 1.520 -ATOM 3317 H1 TIP3 3617 9.043 10.109 7.068 0.417 1.000 -ATOM 3318 H2 TIP3 3617 8.226 10.093 5.792 0.417 1.000 -ATOM 3319 OH2 TIP3 3618 -9.550 -4.558 7.143 -0.834 1.520 -ATOM 3320 H1 TIP3 3618 -9.362 -4.757 8.031 0.417 1.000 -ATOM 3321 H2 TIP3 3618 -9.376 -3.591 7.099 0.417 1.000 -ATOM 3322 OH2 TIP3 3619 -2.063 -15.343 -8.797 -0.834 1.520 -ATOM 3323 H1 TIP3 3619 -2.082 -16.078 -8.121 0.417 1.000 -ATOM 3324 H2 TIP3 3619 -2.296 -15.827 -9.585 0.417 1.000 -ATOM 3325 OH2 TIP3 3620 3.458 -8.491 8.295 -0.834 1.520 -ATOM 3326 H1 TIP3 3620 3.834 -9.124 7.676 0.417 1.000 -ATOM 3327 H2 TIP3 3620 2.483 -8.681 8.283 0.417 1.000 -ATOM 3328 OH2 TIP3 3621 12.515 -3.794 6.473 -0.834 1.520 -ATOM 3329 H1 TIP3 3621 12.822 -4.094 7.292 0.417 1.000 -ATOM 3330 H2 TIP3 3621 12.601 -2.845 6.532 0.417 1.000 -ATOM 3331 OH2 TIP3 3622 11.843 -19.549 11.115 -0.834 1.520 -ATOM 3332 H1 TIP3 3622 12.030 -19.834 11.998 0.417 1.000 -ATOM 3333 H2 TIP3 3622 12.739 -19.295 10.767 0.417 1.000 -ATOM 3334 OH2 TIP3 3623 11.529 -13.787 -4.755 -0.834 1.520 -ATOM 3335 H1 TIP3 3623 11.986 -14.649 -4.637 0.417 1.000 -ATOM 3336 H2 TIP3 3623 11.168 -13.887 -5.657 0.417 1.000 -ATOM 3337 OH2 TIP3 3625 -0.068 10.597 10.791 -0.834 1.520 -ATOM 3338 H1 TIP3 3625 -0.133 10.286 11.647 0.417 1.000 -ATOM 3339 H2 TIP3 3625 -0.870 10.352 10.345 0.417 1.000 -ATOM 3340 OH2 TIP3 3626 0.151 -10.032 12.291 -0.834 1.520 -ATOM 3341 H1 TIP3 3626 0.891 -10.666 12.484 0.417 1.000 -ATOM 3342 H2 TIP3 3626 0.624 -9.166 12.268 0.417 1.000 -ATOM 3343 OH2 TIP3 3627 -2.624 -8.100 18.779 -0.834 1.520 -ATOM 3344 H1 TIP3 3627 -1.963 -8.189 19.498 0.417 1.000 -ATOM 3345 H2 TIP3 3627 -3.193 -8.844 18.913 0.417 1.000 -ATOM 3346 OH2 TIP3 3628 1.703 -2.991 14.150 -0.834 1.520 -ATOM 3347 H1 TIP3 3628 2.047 -3.918 14.071 0.417 1.000 -ATOM 3348 H2 TIP3 3628 2.343 -2.490 13.690 0.417 1.000 -ATOM 3349 OH2 TIP3 3633 7.510 2.709 -10.593 -0.834 1.520 -ATOM 3350 H1 TIP3 3633 8.180 2.143 -10.210 0.417 1.000 -ATOM 3351 H2 TIP3 3633 8.048 3.575 -10.668 0.417 1.000 -ATOM 3352 OH2 TIP3 3634 8.834 9.646 -3.470 -0.834 1.520 -ATOM 3353 H1 TIP3 3634 8.945 9.168 -2.616 0.417 1.000 -ATOM 3354 H2 TIP3 3634 7.869 9.694 -3.620 0.417 1.000 -ATOM 3355 OH2 TIP3 3636 10.680 3.011 -16.453 -0.834 1.520 -ATOM 3356 H1 TIP3 3636 10.863 3.667 -15.780 0.417 1.000 -ATOM 3357 H2 TIP3 3636 10.122 2.449 -15.860 0.417 1.000 -ATOM 3358 OH2 TIP3 3638 9.991 8.121 -12.768 -0.834 1.520 -ATOM 3359 H1 TIP3 3638 9.530 8.721 -12.161 0.417 1.000 -ATOM 3360 H2 TIP3 3638 10.596 7.688 -12.130 0.417 1.000 -ATOM 3361 OH2 TIP3 3639 9.518 -0.807 1.553 -0.834 1.520 -ATOM 3362 H1 TIP3 3639 8.577 -0.843 1.744 0.417 1.000 -ATOM 3363 H2 TIP3 3639 9.949 -1.501 2.148 0.417 1.000 -ATOM 3364 OH2 TIP3 3640 -1.059 3.457 10.901 -0.834 1.520 -ATOM 3365 H1 TIP3 3640 -1.658 4.220 10.616 0.417 1.000 -ATOM 3366 H2 TIP3 3640 -0.697 3.144 10.063 0.417 1.000 -ATOM 3367 OH2 TIP3 3641 -1.605 -4.534 -5.785 -0.834 1.520 -ATOM 3368 H1 TIP3 3641 -0.751 -5.012 -5.934 0.417 1.000 -ATOM 3369 H2 TIP3 3641 -1.957 -4.900 -4.975 0.417 1.000 -ATOM 3370 OH2 TIP3 3642 6.227 -9.871 7.843 -0.834 1.520 -ATOM 3371 H1 TIP3 3642 6.036 -8.980 7.661 0.417 1.000 -ATOM 3372 H2 TIP3 3642 7.022 -10.012 7.355 0.417 1.000 -ATOM 3373 OH2 TIP3 3643 5.868 -10.137 11.056 -0.834 1.520 -ATOM 3374 H1 TIP3 3643 5.641 -9.497 10.437 0.417 1.000 -ATOM 3375 H2 TIP3 3643 5.435 -9.850 11.915 0.417 1.000 -ATOM 3376 OH2 TIP3 3650 -7.746 -0.324 -17.771 -0.834 1.520 -ATOM 3377 H1 TIP3 3650 -7.322 0.538 -17.642 0.417 1.000 -ATOM 3378 H2 TIP3 3650 -7.885 -0.465 -18.750 0.417 1.000 -ATOM 3379 OH2 TIP3 3651 -3.114 3.849 -18.438 -0.834 1.520 -ATOM 3380 H1 TIP3 3651 -2.274 4.125 -18.958 0.417 1.000 -ATOM 3381 H2 TIP3 3651 -3.749 4.508 -18.750 0.417 1.000 -ATOM 3382 OH2 TIP3 3653 0.421 -11.489 -5.429 -0.834 1.520 -ATOM 3383 H1 TIP3 3653 0.722 -11.750 -4.559 0.417 1.000 -ATOM 3384 H2 TIP3 3653 -0.085 -10.715 -5.240 0.417 1.000 -ATOM 3385 OH2 TIP3 3657 13.560 -4.859 2.959 -0.834 1.520 -ATOM 3386 H1 TIP3 3657 13.604 -3.944 3.209 0.417 1.000 -ATOM 3387 H2 TIP3 3657 13.626 -5.397 3.811 0.417 1.000 -ATOM 3388 OH2 TIP3 3658 13.349 -2.064 3.595 -0.834 1.520 -ATOM 3389 H1 TIP3 3658 13.408 -1.620 4.471 0.417 1.000 -ATOM 3390 H2 TIP3 3658 14.053 -1.597 3.056 0.417 1.000 -ATOM 3391 OH2 TIP3 3659 -2.799 12.642 -4.810 -0.834 1.520 -ATOM 3392 H1 TIP3 3659 -2.209 13.341 -5.189 0.417 1.000 -ATOM 3393 H2 TIP3 3659 -2.245 12.224 -4.113 0.417 1.000 -ATOM 3394 OH2 TIP3 3660 -5.964 -12.270 -13.356 -0.834 1.520 -ATOM 3395 H1 TIP3 3660 -5.642 -12.862 -12.654 0.417 1.000 -ATOM 3396 H2 TIP3 3660 -6.114 -11.411 -12.877 0.417 1.000 -ATOM 3397 OH2 TIP3 3661 -11.976 3.598 -2.565 -0.834 1.520 -ATOM 3398 H1 TIP3 3661 -11.098 3.477 -2.956 0.417 1.000 -ATOM 3399 H2 TIP3 3661 -12.350 4.418 -2.883 0.417 1.000 -ATOM 3400 OH2 TIP3 3662 -1.094 -9.315 -4.907 -0.834 1.520 -ATOM 3401 H1 TIP3 3662 -1.480 -8.805 -5.617 0.417 1.000 -ATOM 3402 H2 TIP3 3662 -1.727 -10.004 -4.728 0.417 1.000 -ATOM 3403 OH2 TIP3 3663 15.988 -1.510 15.037 -0.834 1.520 -ATOM 3404 H1 TIP3 3663 15.252 -1.110 15.531 0.417 1.000 -ATOM 3405 H2 TIP3 3663 16.749 -1.311 15.667 0.417 1.000 -ATOM 3406 OH2 TIP3 3664 16.697 11.319 7.188 -0.834 1.520 -ATOM 3407 H1 TIP3 3664 17.468 11.942 6.968 0.417 1.000 -ATOM 3408 H2 TIP3 3664 16.113 11.982 7.478 0.417 1.000 -ATOM 3409 OH2 TIP3 3665 -16.498 -1.262 6.015 -0.834 1.520 -ATOM 3410 H1 TIP3 3665 -15.958 -0.566 6.414 0.417 1.000 -ATOM 3411 H2 TIP3 3665 -16.785 -0.812 5.221 0.417 1.000 -ATOM 3412 OH2 TIP3 3674 10.470 -1.289 -16.235 -0.834 1.520 -ATOM 3413 H1 TIP3 3674 11.181 -1.546 -16.789 0.417 1.000 -ATOM 3414 H2 TIP3 3674 9.687 -1.279 -16.766 0.417 1.000 -ATOM 3415 OH2 TIP3 3675 5.926 9.198 -3.389 -0.834 1.520 -ATOM 3416 H1 TIP3 3675 5.471 8.950 -2.552 0.417 1.000 -ATOM 3417 H2 TIP3 3675 6.067 8.349 -3.828 0.417 1.000 -ATOM 3418 OH2 TIP3 3677 -1.703 13.419 -13.656 -0.834 1.520 -ATOM 3419 H1 TIP3 3677 -1.947 14.034 -14.380 0.417 1.000 -ATOM 3420 H2 TIP3 3677 -0.938 13.788 -13.230 0.417 1.000 -ATOM 3421 OH2 TIP3 3678 14.802 2.107 6.297 -0.834 1.520 -ATOM 3422 H1 TIP3 3678 13.985 2.571 6.115 0.417 1.000 -ATOM 3423 H2 TIP3 3678 15.066 2.359 7.253 0.417 1.000 -ATOM 3424 OH2 TIP3 3680 10.034 -5.650 5.943 -0.834 1.520 -ATOM 3425 H1 TIP3 3680 9.652 -4.714 6.018 0.417 1.000 -ATOM 3426 H2 TIP3 3680 10.910 -5.497 6.214 0.417 1.000 -ATOM 3427 OH2 TIP3 3681 12.093 18.549 -19.160 -0.834 1.520 -ATOM 3428 H1 TIP3 3681 12.906 18.958 -18.839 0.417 1.000 -ATOM 3429 H2 TIP3 3681 11.546 18.598 -18.361 0.417 1.000 -ATOM 3430 OH2 TIP3 3682 8.651 -7.404 2.449 -0.834 1.520 -ATOM 3431 H1 TIP3 3682 9.290 -7.786 3.072 0.417 1.000 -ATOM 3432 H2 TIP3 3682 7.869 -7.890 2.508 0.417 1.000 -ATOM 3433 OH2 TIP3 3683 -8.822 16.778 18.226 -0.834 1.520 -ATOM 3434 H1 TIP3 3683 -8.780 15.842 18.508 0.417 1.000 -ATOM 3435 H2 TIP3 3683 -7.966 17.155 18.555 0.417 1.000 -ATOM 3436 OH2 TIP3 3684 6.505 0.722 6.381 -0.834 1.520 -ATOM 3437 H1 TIP3 3684 7.423 0.915 6.251 0.417 1.000 -ATOM 3438 H2 TIP3 3684 6.508 0.422 7.279 0.417 1.000 -ATOM 3439 OH2 TIP3 3685 -2.028 6.015 14.219 -0.834 1.520 -ATOM 3440 H1 TIP3 3685 -2.554 5.249 14.270 0.417 1.000 -ATOM 3441 H2 TIP3 3685 -2.631 6.802 13.987 0.417 1.000 -ATOM 3442 OH2 TIP3 3686 18.803 0.448 19.090 -0.834 1.520 -ATOM 3443 H1 TIP3 3686 17.883 0.432 19.103 0.417 1.000 -ATOM 3444 H2 TIP3 3686 19.035 -0.371 19.547 0.417 1.000 -ATOM 3445 OH2 TIP3 3687 -14.094 12.297 15.892 -0.834 1.520 -ATOM 3446 H1 TIP3 3687 -14.111 11.416 16.358 0.417 1.000 -ATOM 3447 H2 TIP3 3687 -14.296 12.007 14.983 0.417 1.000 -ATOM 3448 OH2 TIP3 3688 4.952 6.251 6.578 -0.834 1.520 -ATOM 3449 H1 TIP3 3688 4.751 7.051 6.086 0.417 1.000 -ATOM 3450 H2 TIP3 3688 4.062 6.040 6.932 0.417 1.000 -ATOM 3451 OH2 TIP3 3693 8.780 6.524 -17.444 -0.834 1.520 -ATOM 3452 H1 TIP3 3693 9.484 7.192 -17.481 0.417 1.000 -ATOM 3453 H2 TIP3 3693 8.952 6.125 -16.582 0.417 1.000 -ATOM 3454 OH2 TIP3 3697 0.584 9.083 -10.742 -0.834 1.520 -ATOM 3455 H1 TIP3 3697 0.206 9.670 -9.996 0.417 1.000 -ATOM 3456 H2 TIP3 3697 1.495 9.378 -10.905 0.417 1.000 -ATOM 3457 OH2 TIP3 3698 4.169 11.178 -12.907 -0.834 1.520 -ATOM 3458 H1 TIP3 3698 4.122 11.962 -13.524 0.417 1.000 -ATOM 3459 H2 TIP3 3698 3.761 10.528 -13.519 0.417 1.000 -ATOM 3460 OH2 TIP3 3700 13.724 6.470 -8.627 -0.834 1.520 -ATOM 3461 H1 TIP3 3700 13.880 5.569 -8.976 0.417 1.000 -ATOM 3462 H2 TIP3 3700 13.190 6.279 -7.832 0.417 1.000 -ATOM 3463 OH2 TIP3 3701 15.573 0.568 -7.601 -0.834 1.520 -ATOM 3464 H1 TIP3 3701 15.495 -0.091 -8.311 0.417 1.000 -ATOM 3465 H2 TIP3 3701 16.536 0.645 -7.501 0.417 1.000 -ATOM 3466 OH2 TIP3 3702 -10.840 15.087 -2.911 -0.834 1.520 -ATOM 3467 H1 TIP3 3702 -11.107 14.303 -3.482 0.417 1.000 -ATOM 3468 H2 TIP3 3702 -11.489 15.788 -3.081 0.417 1.000 -ATOM 3469 OH2 TIP3 3703 0.942 4.743 1.022 -0.834 1.520 -ATOM 3470 H1 TIP3 3703 0.045 4.484 0.827 0.417 1.000 -ATOM 3471 H2 TIP3 3703 0.951 5.726 0.788 0.417 1.000 -ATOM 3472 OH2 TIP3 3704 -7.979 -2.156 11.021 -0.834 1.520 -ATOM 3473 H1 TIP3 3704 -7.608 -1.226 11.010 0.417 1.000 -ATOM 3474 H2 TIP3 3704 -8.319 -2.211 11.918 0.417 1.000 -ATOM 3475 OH2 TIP3 3705 13.481 13.909 0.236 -0.834 1.520 -ATOM 3476 H1 TIP3 3705 13.407 13.374 1.086 0.417 1.000 -ATOM 3477 H2 TIP3 3705 13.571 13.236 -0.419 0.417 1.000 -ATOM 3478 OH2 TIP3 3706 -2.728 13.927 9.206 -0.834 1.520 -ATOM 3479 H1 TIP3 3706 -2.543 13.467 8.331 0.417 1.000 -ATOM 3480 H2 TIP3 3706 -3.644 13.784 9.311 0.417 1.000 -ATOM 3481 OH2 TIP3 3707 7.535 5.870 5.374 -0.834 1.520 -ATOM 3482 H1 TIP3 3707 7.116 5.050 5.042 0.417 1.000 -ATOM 3483 H2 TIP3 3707 6.762 6.449 5.486 0.417 1.000 -ATOM 3484 OH2 TIP3 3708 -3.740 7.219 1.916 -0.834 1.520 -ATOM 3485 H1 TIP3 3708 -4.489 6.653 1.903 0.417 1.000 -ATOM 3486 H2 TIP3 3708 -3.649 7.594 0.992 0.417 1.000 -ATOM 3487 OH2 TIP3 3709 16.983 10.438 17.869 -0.834 1.520 -ATOM 3488 H1 TIP3 3709 16.826 9.559 18.168 0.417 1.000 -ATOM 3489 H2 TIP3 3709 16.427 10.984 18.393 0.417 1.000 -ATOM 3490 OH2 TIP3 3710 19.749 3.431 12.417 -0.834 1.520 -ATOM 3491 H1 TIP3 3710 19.132 2.941 12.963 0.417 1.000 -ATOM 3492 H2 TIP3 3710 19.514 3.210 11.550 0.417 1.000 -ATOM 3493 OH2 TIP3 3718 -0.356 4.996 -19.477 -0.834 1.520 -ATOM 3494 H1 TIP3 3718 -0.243 5.535 -18.635 0.417 1.000 -ATOM 3495 H2 TIP3 3718 0.557 4.741 -19.711 0.417 1.000 -ATOM 3496 OH2 TIP3 3719 12.066 13.024 -17.447 -0.834 1.520 -ATOM 3497 H1 TIP3 3719 11.853 13.167 -16.490 0.417 1.000 -ATOM 3498 H2 TIP3 3719 11.146 12.995 -17.901 0.417 1.000 -ATOM 3499 OH2 TIP3 3720 3.390 9.506 -6.870 -0.834 1.520 -ATOM 3500 H1 TIP3 3720 4.282 9.326 -7.288 0.417 1.000 -ATOM 3501 H2 TIP3 3720 2.986 10.210 -7.391 0.417 1.000 -ATOM 3502 OH2 TIP3 3722 8.287 9.686 -11.030 -0.834 1.520 -ATOM 3503 H1 TIP3 3722 8.048 9.997 -10.130 0.417 1.000 -ATOM 3504 H2 TIP3 3722 7.596 8.964 -11.101 0.417 1.000 -ATOM 3505 OH2 TIP3 3723 -8.666 6.903 -8.696 -0.834 1.520 -ATOM 3506 H1 TIP3 3723 -9.233 7.696 -8.424 0.417 1.000 -ATOM 3507 H2 TIP3 3723 -8.209 6.796 -7.911 0.417 1.000 -ATOM 3508 OH2 TIP3 3724 5.139 10.800 2.203 -0.834 1.520 -ATOM 3509 H1 TIP3 3724 5.778 10.185 2.537 0.417 1.000 -ATOM 3510 H2 TIP3 3724 4.555 10.169 1.700 0.417 1.000 -ATOM 3511 OH2 TIP3 3725 5.658 11.400 7.140 -0.834 1.520 -ATOM 3512 H1 TIP3 3725 4.862 11.443 7.677 0.417 1.000 -ATOM 3513 H2 TIP3 3725 6.368 11.246 7.826 0.417 1.000 -ATOM 3514 OH2 TIP3 3727 17.428 1.222 -1.442 -0.834 1.520 -ATOM 3515 H1 TIP3 3727 17.988 1.972 -1.282 0.417 1.000 -ATOM 3516 H2 TIP3 3727 16.732 1.392 -0.820 0.417 1.000 -ATOM 3517 OH2 TIP3 3728 -12.129 5.057 4.016 -0.834 1.520 -ATOM 3518 H1 TIP3 3728 -12.639 5.718 3.480 0.417 1.000 -ATOM 3519 H2 TIP3 3728 -11.901 4.344 3.402 0.417 1.000 -ATOM 3520 OH2 TIP3 3729 8.465 -0.262 19.336 -0.834 1.520 -ATOM 3521 H1 TIP3 3729 7.950 -0.884 19.864 0.417 1.000 -ATOM 3522 H2 TIP3 3729 8.248 -0.539 18.432 0.417 1.000 -ATOM 3523 OH2 TIP3 3730 14.434 16.027 18.498 -0.834 1.520 -ATOM 3524 H1 TIP3 3730 15.301 15.898 18.847 0.417 1.000 -ATOM 3525 H2 TIP3 3730 14.103 16.711 19.082 0.417 1.000 -ATOM 3526 OH2 TIP3 3731 0.523 11.177 15.364 -0.834 1.520 -ATOM 3527 H1 TIP3 3731 0.219 12.049 15.727 0.417 1.000 -ATOM 3528 H2 TIP3 3731 1.480 11.276 15.419 0.417 1.000 -ATOM 3529 OH2 TIP3 3736 -4.840 -3.683 17.828 -0.834 1.520 -ATOM 3530 H1 TIP3 3736 -4.151 -4.249 18.258 0.417 1.000 -ATOM 3531 H2 TIP3 3736 -4.328 -3.179 17.194 0.417 1.000 -ATOM 3532 OH2 TIP3 3737 -2.150 18.594 -16.699 -0.834 1.520 -ATOM 3533 H1 TIP3 3737 -2.657 19.365 -17.033 0.417 1.000 -ATOM 3534 H2 TIP3 3737 -2.801 17.884 -16.797 0.417 1.000 -ATOM 3535 OH2 TIP3 3740 3.323 9.785 -10.197 -0.834 1.520 -ATOM 3536 H1 TIP3 3740 4.151 10.268 -10.381 0.417 1.000 -ATOM 3537 H2 TIP3 3740 3.301 9.193 -10.864 0.417 1.000 -ATOM 3538 OH2 TIP3 3743 6.993 15.288 0.879 -0.834 1.520 -ATOM 3539 H1 TIP3 3743 6.493 16.117 1.214 0.417 1.000 -ATOM 3540 H2 TIP3 3743 6.584 14.547 1.322 0.417 1.000 -ATOM 3541 OH2 TIP3 3745 -2.593 5.737 5.400 -0.834 1.520 -ATOM 3542 H1 TIP3 3745 -2.392 5.784 4.485 0.417 1.000 -ATOM 3543 H2 TIP3 3745 -1.997 5.061 5.697 0.417 1.000 -ATOM 3544 OH2 TIP3 3746 -1.845 16.925 9.762 -0.834 1.520 -ATOM 3545 H1 TIP3 3746 -2.238 16.448 9.069 0.417 1.000 -ATOM 3546 H2 TIP3 3746 -1.293 17.585 9.292 0.417 1.000 -ATOM 3547 OH2 TIP3 3747 11.049 14.599 4.966 -0.834 1.520 -ATOM 3548 H1 TIP3 3747 10.611 15.284 5.511 0.417 1.000 -ATOM 3549 H2 TIP3 3747 10.546 14.658 4.099 0.417 1.000 -ATOM 3550 OH2 TIP3 3749 7.095 13.829 9.788 -0.834 1.520 -ATOM 3551 H1 TIP3 3749 6.154 14.022 9.709 0.417 1.000 -ATOM 3552 H2 TIP3 3749 7.132 12.848 9.690 0.417 1.000 -ATOM 3553 OH2 TIP3 3751 16.188 -1.598 19.026 -0.834 1.520 -ATOM 3554 H1 TIP3 3751 16.729 -1.821 19.805 0.417 1.000 -ATOM 3555 H2 TIP3 3751 15.286 -1.683 19.326 0.417 1.000 -ATOM 3556 OH2 TIP3 3753 -4.888 9.781 18.252 -0.834 1.520 -ATOM 3557 H1 TIP3 3753 -4.108 9.858 17.589 0.417 1.000 -ATOM 3558 H2 TIP3 3753 -4.441 9.570 19.142 0.417 1.000 -ATOM 3559 OH2 TIP3 3757 13.974 2.808 -17.829 -0.834 1.520 -ATOM 3560 H1 TIP3 3757 14.889 3.172 -17.879 0.417 1.000 -ATOM 3561 H2 TIP3 3757 13.813 2.805 -16.890 0.417 1.000 -ATOM 3562 OH2 TIP3 3761 -0.892 11.667 -2.919 -0.834 1.520 -ATOM 3563 H1 TIP3 3761 -1.396 11.241 -2.230 0.417 1.000 -ATOM 3564 H2 TIP3 3761 -0.380 12.420 -2.436 0.417 1.000 -ATOM 3565 OH2 TIP3 3762 12.961 16.077 -17.240 -0.834 1.520 -ATOM 3566 H1 TIP3 3762 13.235 15.952 -16.317 0.417 1.000 -ATOM 3567 H2 TIP3 3762 11.991 15.792 -17.268 0.417 1.000 -ATOM 3568 OH2 TIP3 3764 -8.006 15.054 -13.253 -0.834 1.520 -ATOM 3569 H1 TIP3 3764 -7.587 15.009 -14.151 0.417 1.000 -ATOM 3570 H2 TIP3 3764 -7.656 15.913 -12.919 0.417 1.000 -ATOM 3571 OH2 TIP3 3766 6.321 12.780 12.842 -0.834 1.520 -ATOM 3572 H1 TIP3 3766 5.775 12.338 12.142 0.417 1.000 -ATOM 3573 H2 TIP3 3766 6.386 13.680 12.475 0.417 1.000 -ATOM 3574 OH2 TIP3 3767 5.196 17.913 11.742 -0.834 1.520 -ATOM 3575 H1 TIP3 3767 6.056 18.105 12.100 0.417 1.000 -ATOM 3576 H2 TIP3 3767 4.976 17.080 12.265 0.417 1.000 -ATOM 3577 OH2 TIP3 3770 10.039 12.865 1.378 -0.834 1.520 -ATOM 3578 H1 TIP3 3770 9.710 12.646 0.494 0.417 1.000 -ATOM 3579 H2 TIP3 3770 9.669 13.778 1.524 0.417 1.000 -ATOM 3580 OH2 TIP3 3771 10.814 15.270 15.396 -0.834 1.520 -ATOM 3581 H1 TIP3 3771 10.991 15.798 14.658 0.417 1.000 -ATOM 3582 H2 TIP3 3771 11.342 15.731 16.033 0.417 1.000 -ATOM 3583 OH2 TIP3 3776 0.228 17.963 -18.198 -0.834 1.520 -ATOM 3584 H1 TIP3 3776 -0.629 18.319 -17.904 0.417 1.000 -ATOM 3585 H2 TIP3 3776 0.139 17.007 -18.337 0.417 1.000 -ATOM 3586 OH2 TIP3 3779 6.637 16.087 -18.996 -0.834 1.520 -ATOM 3587 H1 TIP3 3779 7.498 16.252 -19.407 0.417 1.000 -ATOM 3588 H2 TIP3 3779 6.017 16.028 -19.745 0.417 1.000 -ATOM 3589 OH2 TIP3 3782 8.481 11.362 3.178 -0.834 1.520 -ATOM 3590 H1 TIP3 3782 9.115 11.898 2.672 0.417 1.000 -ATOM 3591 H2 TIP3 3782 8.051 12.015 3.779 0.417 1.000 -ATOM 3592 OH2 TIP3 3786 18.592 18.819 -4.876 -0.834 1.520 -ATOM 3593 H1 TIP3 3786 18.085 18.482 -4.102 0.417 1.000 -ATOM 3594 H2 TIP3 3786 19.458 18.516 -4.519 0.417 1.000 -ATOM 3595 OH2 TIP3 3787 1.899 1.156 4.376 -0.834 1.520 -ATOM 3596 H1 TIP3 3787 2.735 0.786 4.748 0.417 1.000 -ATOM 3597 H2 TIP3 3787 2.058 2.130 4.308 0.417 1.000 -ATOM 3598 OH2 TIP3 3788 -4.347 11.558 10.925 -0.834 1.520 -ATOM 3599 H1 TIP3 3788 -4.052 11.753 11.873 0.417 1.000 -ATOM 3600 H2 TIP3 3788 -5.113 12.079 10.837 0.417 1.000 -ATOM 3601 OH2 TIP3 3789 8.509 15.644 13.685 -0.834 1.520 -ATOM 3602 H1 TIP3 3789 9.225 15.098 13.985 0.417 1.000 -ATOM 3603 H2 TIP3 3789 7.910 15.868 14.500 0.417 1.000 -ATOM 3604 OH2 TIP3 3790 1.536 16.060 2.084 -0.834 1.520 -ATOM 3605 H1 TIP3 3790 0.892 16.677 2.538 0.417 1.000 -ATOM 3606 H2 TIP3 3790 1.559 15.350 2.741 0.417 1.000 -ATOM 3607 OH2 TIP3 3792 6.590 9.316 5.618 -0.834 1.520 -ATOM 3608 H1 TIP3 3792 6.197 10.093 6.064 0.417 1.000 -ATOM 3609 H2 TIP3 3792 5.854 8.815 5.258 0.417 1.000 -ATOM 3610 OH2 TIP3 3793 13.738 15.564 15.836 -0.834 1.520 -ATOM 3611 H1 TIP3 3793 13.875 15.700 16.760 0.417 1.000 -ATOM 3612 H2 TIP3 3793 14.687 15.318 15.462 0.417 1.000 -ATOM 3613 OH2 TIP3 3796 0.923 17.067 12.534 -0.834 1.520 -ATOM 3614 H1 TIP3 3796 0.951 16.521 11.751 0.417 1.000 -ATOM 3615 H2 TIP3 3796 0.543 16.553 13.240 0.417 1.000 -ATOM 3616 OH2 TIP3 3801 14.969 16.609 -19.485 -0.834 1.520 -ATOM 3617 H1 TIP3 3801 14.822 17.562 -19.310 0.417 1.000 -ATOM 3618 H2 TIP3 3801 14.532 16.181 -18.769 0.417 1.000 -ATOM 3619 OH2 TIP3 3814 3.934 16.036 13.741 -0.834 1.520 -ATOM 3620 H1 TIP3 3814 3.190 15.530 13.372 0.417 1.000 -ATOM 3621 H2 TIP3 3814 3.532 16.661 14.417 0.417 1.000 -ATOM 3622 OH2 TIP3 3821 13.010 6.672 -12.664 -0.834 1.520 -ATOM 3623 H1 TIP3 3821 12.982 7.638 -12.578 0.417 1.000 -ATOM 3624 H2 TIP3 3821 12.347 6.374 -12.045 0.417 1.000 -ATOM 3625 OH2 TIP3 3829 12.231 10.996 -6.292 -0.834 1.520 -ATOM 3626 H1 TIP3 3829 11.331 11.344 -6.120 0.417 1.000 -ATOM 3627 H2 TIP3 3829 12.051 10.275 -6.944 0.417 1.000 -ATOM 3628 OH2 TIP3 3833 6.348 18.122 9.123 -0.834 1.520 -ATOM 3629 H1 TIP3 3833 7.110 17.449 9.118 0.417 1.000 -ATOM 3630 H2 TIP3 3833 5.977 17.917 9.990 0.417 1.000 -ATOM 3631 OH2 TIP3 3834 2.904 3.633 14.112 -0.834 1.520 -ATOM 3632 H1 TIP3 3834 1.945 3.842 13.956 0.417 1.000 -ATOM 3633 H2 TIP3 3834 3.299 3.749 13.233 0.417 1.000 -ATOM 3634 OH2 TIP3 3872 4.418 13.938 10.661 -0.834 1.520 -ATOM 3635 H1 TIP3 3872 3.952 14.846 10.630 0.417 1.000 -ATOM 3636 H2 TIP3 3872 3.716 13.327 11.027 0.417 1.000 -ATOM 3637 OH2 TIP3 3892 11.246 13.527 -2.479 -0.834 1.520 -ATOM 3638 H1 TIP3 3892 11.898 12.901 -2.121 0.417 1.000 -ATOM 3639 H2 TIP3 3892 10.392 13.003 -2.459 0.417 1.000 -ATOM 3640 OH2 TIP3 3924 2.436 -6.837 13.707 -0.834 1.520 -ATOM 3641 H1 TIP3 3924 2.654 -7.154 12.787 0.417 1.000 -ATOM 3642 H2 TIP3 3924 1.437 -6.628 13.598 0.417 1.000 -ATOM 3643 OH2 TIP3 3925 2.567 -19.240 -4.911 -0.834 1.520 -ATOM 3644 H1 TIP3 3925 3.323 -19.105 -4.332 0.417 1.000 -ATOM 3645 H2 TIP3 3925 2.175 -18.298 -4.915 0.417 1.000 -ATOM 3646 OH2 TIP3 3931 10.847 -10.906 -13.051 -0.834 1.520 -ATOM 3647 H1 TIP3 3931 10.536 -10.501 -12.215 0.417 1.000 -ATOM 3648 H2 TIP3 3931 11.760 -11.088 -12.731 0.417 1.000 -ATOM 3649 OH2 TIP3 3933 0.520 -14.297 -8.575 -0.834 1.520 -ATOM 3650 H1 TIP3 3933 -0.250 -14.841 -8.280 0.417 1.000 -ATOM 3651 H2 TIP3 3933 0.178 -13.791 -9.402 0.417 1.000 -ATOM 3652 OH2 TIP3 3935 -2.154 -10.960 5.906 -0.834 1.520 -ATOM 3653 H1 TIP3 3935 -2.245 -11.755 5.370 0.417 1.000 -ATOM 3654 H2 TIP3 3935 -1.296 -10.640 5.724 0.417 1.000 -ATOM 3655 OH2 TIP3 3938 8.079 -10.311 19.229 -0.834 1.520 -ATOM 3656 H1 TIP3 3938 7.342 -9.777 18.926 0.417 1.000 -ATOM 3657 H2 TIP3 3938 8.575 -10.398 18.386 0.417 1.000 -ATOM 3658 OH2 TIP3 3951 0.969 -18.875 -10.175 -0.834 1.520 -ATOM 3659 H1 TIP3 3951 1.514 -18.160 -9.758 0.417 1.000 -ATOM 3660 H2 TIP3 3951 0.448 -18.367 -10.822 0.417 1.000 -ATOM 3661 OH2 TIP3 3957 17.252 -4.235 12.061 -0.834 1.520 -ATOM 3662 H1 TIP3 3957 17.786 -5.004 11.783 0.417 1.000 -ATOM 3663 H2 TIP3 3957 17.778 -3.936 12.830 0.417 1.000 -ATOM 3664 OH2 TIP3 3974 8.638 -14.902 -0.868 -0.834 1.520 -ATOM 3665 H1 TIP3 3974 8.603 -15.162 -1.789 0.417 1.000 -ATOM 3666 H2 TIP3 3974 7.854 -14.352 -0.783 0.417 1.000 -ATOM 3667 OH2 TIP3 3975 11.657 -12.587 -10.331 -0.834 1.520 -ATOM 3668 H1 TIP3 3975 11.102 -13.101 -10.955 0.417 1.000 -ATOM 3669 H2 TIP3 3975 11.276 -11.690 -10.218 0.417 1.000 -ATOM 3670 OH2 TIP3 3976 -2.483 -8.142 -6.990 -0.834 1.520 -ATOM 3671 H1 TIP3 3976 -2.360 -8.227 -7.961 0.417 1.000 -ATOM 3672 H2 TIP3 3976 -2.711 -7.219 -6.870 0.417 1.000 -ATOM 3673 OH2 TIP3 3977 -11.100 -12.690 -8.710 -0.834 1.520 -ATOM 3674 H1 TIP3 3977 -11.261 -13.294 -7.922 0.417 1.000 -ATOM 3675 H2 TIP3 3977 -10.445 -11.997 -8.469 0.417 1.000 -ATOM 3676 OH2 TIP3 3982 6.085 -17.763 16.922 -0.834 1.520 -ATOM 3677 H1 TIP3 3982 6.912 -17.705 16.416 0.417 1.000 -ATOM 3678 H2 TIP3 3982 5.808 -18.656 16.647 0.417 1.000 -ATOM 3679 OH2 TIP3 3986 7.820 -17.527 -19.066 -0.834 1.520 -ATOM 3680 H1 TIP3 3986 8.525 -16.831 -19.113 0.417 1.000 -ATOM 3681 H2 TIP3 3986 7.193 -17.001 -18.501 0.417 1.000 -ATOM 3682 OH2 TIP3 3991 -2.790 -16.954 -3.228 -0.834 1.520 -ATOM 3683 H1 TIP3 3991 -3.225 -16.377 -3.908 0.417 1.000 -ATOM 3684 H2 TIP3 3991 -2.319 -16.271 -2.745 0.417 1.000 -ATOM 3685 OH2 TIP3 3992 8.814 -13.094 -12.626 -0.834 1.520 -ATOM 3686 H1 TIP3 3992 8.585 -12.163 -12.441 0.417 1.000 -ATOM 3687 H2 TIP3 3992 7.928 -13.425 -12.813 0.417 1.000 -ATOM 3688 OH2 TIP3 3995 0.736 -3.581 -1.447 -0.834 1.520 -ATOM 3689 H1 TIP3 3995 0.764 -3.671 -2.443 0.417 1.000 -ATOM 3690 H2 TIP3 3995 1.696 -3.517 -1.213 0.417 1.000 -ATOM 3691 OH2 TIP3 3996 -0.049 -13.567 -15.694 -0.834 1.520 -ATOM 3692 H1 TIP3 3996 -0.404 -12.598 -15.541 0.417 1.000 -ATOM 3693 H2 TIP3 3996 -0.446 -14.069 -14.972 0.417 1.000 -ATOM 3694 OH2 TIP3 3997 12.718 -14.652 7.053 -0.834 1.520 -ATOM 3695 H1 TIP3 3997 13.603 -14.981 6.921 0.417 1.000 -ATOM 3696 H2 TIP3 3997 12.922 -13.638 6.971 0.417 1.000 -ATOM 3697 OH2 TIP3 3998 15.440 -7.081 9.100 -0.834 1.520 -ATOM 3698 H1 TIP3 3998 14.838 -7.743 8.881 0.417 1.000 -ATOM 3699 H2 TIP3 3998 14.992 -6.594 9.885 0.417 1.000 -ATOM 3700 OH2 TIP3 3999 9.861 -16.864 18.399 -0.834 1.520 -ATOM 3701 H1 TIP3 3999 9.833 -17.832 18.395 0.417 1.000 -ATOM 3702 H2 TIP3 3999 10.588 -16.686 17.801 0.417 1.000 -ATOM 3703 OH2 TIP3 4000 13.135 -3.562 9.141 -0.834 1.520 -ATOM 3704 H1 TIP3 4000 13.619 -4.080 9.751 0.417 1.000 -ATOM 3705 H2 TIP3 4000 12.247 -3.589 9.491 0.417 1.000 -ATOM 3706 OH2 TIP3 4002 16.528 -13.601 18.790 -0.834 1.520 -ATOM 3707 H1 TIP3 4002 16.534 -14.037 17.936 0.417 1.000 -ATOM 3708 H2 TIP3 4002 17.180 -12.868 18.599 0.417 1.000 -ATOM 3709 OH2 TIP3 4008 12.422 -6.895 15.788 -0.834 1.520 -ATOM 3710 H1 TIP3 4008 11.988 -7.688 16.179 0.417 1.000 -ATOM 3711 H2 TIP3 4008 13.416 -7.040 15.895 0.417 1.000 -ATOM 3712 OH2 TIP3 4009 1.334 -12.778 -3.130 -0.834 1.520 -ATOM 3713 H1 TIP3 4009 1.033 -13.557 -2.561 0.417 1.000 -ATOM 3714 H2 TIP3 4009 2.137 -12.517 -2.756 0.417 1.000 -ATOM 3715 OH2 TIP3 4010 13.590 4.057 -9.656 -0.834 1.520 -ATOM 3716 H1 TIP3 4010 14.102 3.354 -10.072 0.417 1.000 -ATOM 3717 H2 TIP3 4010 12.721 3.865 -10.077 0.417 1.000 -ATOM 3718 OH2 TIP3 4012 -10.505 -5.584 -18.021 -0.834 1.520 -ATOM 3719 H1 TIP3 4012 -9.646 -5.797 -18.452 0.417 1.000 -ATOM 3720 H2 TIP3 4012 -10.835 -6.434 -17.901 0.417 1.000 -ATOM 3721 OH2 TIP3 4014 10.874 -18.934 -9.095 -0.834 1.520 -ATOM 3722 H1 TIP3 4014 10.395 -19.783 -8.954 0.417 1.000 -ATOM 3723 H2 TIP3 4014 10.290 -18.455 -9.664 0.417 1.000 -ATOM 3724 OH2 TIP3 4015 5.364 -18.735 -12.866 -0.834 1.520 -ATOM 3725 H1 TIP3 4015 4.665 -19.036 -12.210 0.417 1.000 -ATOM 3726 H2 TIP3 4015 5.826 -19.522 -12.955 0.417 1.000 -ATOM 3727 OH2 TIP3 4016 8.064 -3.052 -11.241 -0.834 1.520 -ATOM 3728 H1 TIP3 4016 8.687 -3.318 -10.573 0.417 1.000 -ATOM 3729 H2 TIP3 4016 8.126 -3.743 -11.911 0.417 1.000 -ATOM 3730 OH2 TIP3 4017 3.065 -15.697 -6.374 -0.834 1.520 -ATOM 3731 H1 TIP3 4017 3.694 -14.912 -6.437 0.417 1.000 -ATOM 3732 H2 TIP3 4017 3.274 -16.119 -7.215 0.417 1.000 -ATOM 3733 OH2 TIP3 4018 10.995 -8.500 3.703 -0.834 1.520 -ATOM 3734 H1 TIP3 4018 10.653 -9.321 4.022 0.417 1.000 -ATOM 3735 H2 TIP3 4018 11.942 -8.744 3.491 0.417 1.000 -ATOM 3736 OH2 TIP3 4019 1.576 -8.932 15.249 -0.834 1.520 -ATOM 3737 H1 TIP3 4019 1.856 -8.125 14.811 0.417 1.000 -ATOM 3738 H2 TIP3 4019 0.857 -8.663 15.816 0.417 1.000 -ATOM 3739 OH2 TIP3 4020 -1.606 2.097 15.921 -0.834 1.520 -ATOM 3740 H1 TIP3 4020 -1.872 1.729 16.726 0.417 1.000 -ATOM 3741 H2 TIP3 4020 -0.753 2.630 16.127 0.417 1.000 -ATOM 3742 OH2 TIP3 4021 10.622 -13.934 0.635 -0.834 1.520 -ATOM 3743 H1 TIP3 4021 10.281 -13.753 1.496 0.417 1.000 -ATOM 3744 H2 TIP3 4021 9.861 -14.147 0.054 0.417 1.000 -ATOM 3745 OH2 TIP3 4022 14.702 -11.815 -0.918 -0.834 1.520 -ATOM 3746 H1 TIP3 4022 14.386 -12.520 -0.405 0.417 1.000 -ATOM 3747 H2 TIP3 4022 14.028 -11.782 -1.689 0.417 1.000 -ATOM 3748 OH2 TIP3 4033 -4.631 16.264 -14.389 -0.834 1.520 -ATOM 3749 H1 TIP3 4033 -4.414 16.956 -13.783 0.417 1.000 -ATOM 3750 H2 TIP3 4033 -4.630 15.505 -13.834 0.417 1.000 -ATOM 3751 OH2 TIP3 4035 6.318 -13.975 -12.652 -0.834 1.520 -ATOM 3752 H1 TIP3 4035 6.091 -14.638 -12.062 0.417 1.000 -ATOM 3753 H2 TIP3 4035 5.538 -13.834 -13.227 0.417 1.000 -ATOM 3754 OH2 TIP3 4036 -6.395 -14.647 -0.720 -0.834 1.520 -ATOM 3755 H1 TIP3 4036 -6.342 -15.473 -1.188 0.417 1.000 -ATOM 3756 H2 TIP3 4036 -7.312 -14.633 -0.484 0.417 1.000 -ATOM 3757 OH2 TIP3 4037 -0.057 -11.459 -18.909 -0.834 1.520 -ATOM 3758 H1 TIP3 4037 -0.292 -12.409 -18.731 0.417 1.000 -ATOM 3759 H2 TIP3 4037 -0.863 -10.967 -18.795 0.417 1.000 -ATOM 3760 OH2 TIP3 4038 3.521 11.765 8.560 -0.834 1.520 -ATOM 3761 H1 TIP3 4038 3.477 11.852 9.555 0.417 1.000 -ATOM 3762 H2 TIP3 4038 2.667 12.153 8.282 0.417 1.000 -ATOM 3763 OH2 TIP3 4039 -0.516 -14.181 1.991 -0.834 1.520 -ATOM 3764 H1 TIP3 4039 -0.814 -13.826 2.828 0.417 1.000 -ATOM 3765 H2 TIP3 4039 -0.266 -13.368 1.445 0.417 1.000 -ATOM 3766 OH2 TIP3 4041 5.896 -14.636 8.742 -0.834 1.520 -ATOM 3767 H1 TIP3 4041 6.865 -14.591 8.639 0.417 1.000 -ATOM 3768 H2 TIP3 4041 5.662 -13.782 9.195 0.417 1.000 -ATOM 3769 OH2 TIP3 4046 5.468 -9.041 18.390 -0.834 1.520 -ATOM 3770 H1 TIP3 4046 5.292 -8.146 18.137 0.417 1.000 -ATOM 3771 H2 TIP3 4046 4.747 -9.595 18.029 0.417 1.000 -ATOM 3772 OH2 TIP3 4047 4.494 -5.204 14.953 -0.834 1.520 -ATOM 3773 H1 TIP3 4047 5.297 -5.596 14.521 0.417 1.000 -ATOM 3774 H2 TIP3 4047 3.764 -5.588 14.441 0.417 1.000 -ATOM 3775 OH2 TIP3 4053 17.225 -10.527 -13.145 -0.834 1.520 -ATOM 3776 H1 TIP3 4053 16.967 -11.229 -13.761 0.417 1.000 -ATOM 3777 H2 TIP3 4053 16.399 -10.177 -12.786 0.417 1.000 -ATOM 3778 OH2 TIP3 4054 12.874 5.033 -3.059 -0.834 1.520 -ATOM 3779 H1 TIP3 4054 13.783 4.696 -3.140 0.417 1.000 -ATOM 3780 H2 TIP3 4054 12.868 5.147 -2.082 0.417 1.000 -ATOM 3781 OH2 TIP3 4055 7.765 0.981 -19.146 -0.834 1.520 -ATOM 3782 H1 TIP3 4055 7.191 0.959 -19.961 0.417 1.000 -ATOM 3783 H2 TIP3 4055 7.432 1.832 -18.752 0.417 1.000 -ATOM 3784 OH2 TIP3 4056 10.722 -0.680 -4.476 -0.834 1.520 -ATOM 3785 H1 TIP3 4056 11.315 -0.019 -4.094 0.417 1.000 -ATOM 3786 H2 TIP3 4056 11.095 -0.738 -5.376 0.417 1.000 -ATOM 3787 OH2 TIP3 4057 14.612 2.300 -12.985 -0.834 1.520 -ATOM 3788 H1 TIP3 4057 14.494 1.817 -13.831 0.417 1.000 -ATOM 3789 H2 TIP3 4057 14.500 3.235 -13.236 0.417 1.000 -ATOM 3790 OH2 TIP3 4059 3.112 6.630 -4.085 -0.834 1.520 -ATOM 3791 H1 TIP3 4059 2.633 6.888 -4.904 0.417 1.000 -ATOM 3792 H2 TIP3 4059 3.826 6.040 -4.348 0.417 1.000 -ATOM 3793 OH2 TIP3 4060 15.161 -2.571 -6.877 -0.834 1.520 -ATOM 3794 H1 TIP3 4060 15.258 -3.527 -6.987 0.417 1.000 -ATOM 3795 H2 TIP3 4060 15.162 -2.327 -7.852 0.417 1.000 -ATOM 3796 OH2 TIP3 4062 8.951 -18.557 8.480 -0.834 1.520 -ATOM 3797 H1 TIP3 4062 9.851 -18.163 8.465 0.417 1.000 -ATOM 3798 H2 TIP3 4062 8.799 -18.820 7.540 0.417 1.000 -ATOM 3799 OH2 TIP3 4064 18.327 5.035 -1.685 -0.834 1.520 -ATOM 3800 H1 TIP3 4064 18.846 5.491 -1.050 0.417 1.000 -ATOM 3801 H2 TIP3 4064 18.154 4.160 -1.397 0.417 1.000 -ATOM 3802 OH2 TIP3 4065 -0.212 -6.172 13.553 -0.834 1.520 -ATOM 3803 H1 TIP3 4065 -0.433 -5.383 12.946 0.417 1.000 -ATOM 3804 H2 TIP3 4065 -0.946 -6.745 13.502 0.417 1.000 -ATOM 3805 OH2 TIP3 4066 5.637 8.363 17.002 -0.834 1.520 -ATOM 3806 H1 TIP3 4066 5.026 8.071 17.718 0.417 1.000 -ATOM 3807 H2 TIP3 4066 6.414 8.745 17.464 0.417 1.000 -ATOM 3808 OH2 TIP3 4074 -12.666 -2.027 -12.910 -0.834 1.520 -ATOM 3809 H1 TIP3 4074 -12.429 -1.610 -13.800 0.417 1.000 -ATOM 3810 H2 TIP3 4074 -13.467 -2.556 -13.115 0.417 1.000 -ATOM 3811 OH2 TIP3 4076 6.108 -3.939 -8.361 -0.834 1.520 -ATOM 3812 H1 TIP3 4076 6.183 -3.416 -9.193 0.417 1.000 -ATOM 3813 H2 TIP3 4076 6.317 -3.316 -7.699 0.417 1.000 -ATOM 3814 OH2 TIP3 4077 -6.088 -8.960 -2.617 -0.834 1.520 -ATOM 3815 H1 TIP3 4077 -6.087 -9.068 -3.577 0.417 1.000 -ATOM 3816 H2 TIP3 4077 -6.388 -8.065 -2.482 0.417 1.000 -ATOM 3817 OH2 TIP3 4079 -3.025 -2.427 5.147 -0.834 1.520 -ATOM 3818 H1 TIP3 4079 -3.222 -1.571 5.632 0.417 1.000 -ATOM 3819 H2 TIP3 4079 -3.822 -2.680 4.650 0.417 1.000 -ATOM 3820 OH2 TIP3 4080 8.662 7.102 13.839 -0.834 1.520 -ATOM 3821 H1 TIP3 4080 8.504 8.001 13.610 0.417 1.000 -ATOM 3822 H2 TIP3 4080 9.019 6.810 13.024 0.417 1.000 -ATOM 3823 OH2 TIP3 4081 1.807 -0.308 1.956 -0.834 1.520 -ATOM 3824 H1 TIP3 4081 1.892 -1.071 2.570 0.417 1.000 -ATOM 3825 H2 TIP3 4081 1.560 0.390 2.634 0.417 1.000 -ATOM 3826 OH2 TIP3 4082 6.226 -10.810 14.878 -0.834 1.520 -ATOM 3827 H1 TIP3 4082 6.258 -11.728 14.962 0.417 1.000 -ATOM 3828 H2 TIP3 4082 7.135 -10.576 14.667 0.417 1.000 -ATOM 3829 OH2 TIP3 4083 4.469 5.918 -1.441 -0.834 1.520 -ATOM 3830 H1 TIP3 4083 4.369 6.179 -2.406 0.417 1.000 -ATOM 3831 H2 TIP3 4083 5.495 6.011 -1.365 0.417 1.000 -ATOM 3832 OH2 TIP3 4084 11.780 -11.246 5.299 -0.834 1.520 -ATOM 3833 H1 TIP3 4084 12.565 -11.144 4.723 0.417 1.000 -ATOM 3834 H2 TIP3 4084 12.088 -11.048 6.204 0.417 1.000 -ATOM 3835 OH2 TIP3 4085 2.776 3.126 18.490 -0.834 1.520 -ATOM 3836 H1 TIP3 4085 2.530 3.297 19.414 0.417 1.000 -ATOM 3837 H2 TIP3 4085 3.724 2.831 18.576 0.417 1.000 -ATOM 3838 OH2 TIP3 4093 12.300 10.502 -14.924 -0.834 1.520 -ATOM 3839 H1 TIP3 4093 12.005 10.159 -15.743 0.417 1.000 -ATOM 3840 H2 TIP3 4093 11.914 11.375 -14.817 0.417 1.000 -ATOM 3841 OH2 TIP3 4096 13.515 -0.385 5.948 -0.834 1.520 -ATOM 3842 H1 TIP3 4096 13.676 -0.628 6.851 0.417 1.000 -ATOM 3843 H2 TIP3 4096 14.031 0.424 5.802 0.417 1.000 -ATOM 3844 OH2 TIP3 4097 1.975 10.136 -16.634 -0.834 1.520 -ATOM 3845 H1 TIP3 4097 1.739 9.870 -15.758 0.417 1.000 -ATOM 3846 H2 TIP3 4097 1.767 11.134 -16.723 0.417 1.000 -ATOM 3847 OH2 TIP3 4098 13.985 -7.680 -11.033 -0.834 1.520 -ATOM 3848 H1 TIP3 4098 13.589 -7.939 -10.182 0.417 1.000 -ATOM 3849 H2 TIP3 4098 14.317 -8.492 -11.470 0.417 1.000 -ATOM 3850 OH2 TIP3 4099 10.533 -10.235 -1.252 -0.834 1.520 -ATOM 3851 H1 TIP3 4099 10.567 -9.300 -1.058 0.417 1.000 -ATOM 3852 H2 TIP3 4099 9.591 -10.461 -1.351 0.417 1.000 -ATOM 3853 OH2 TIP3 4102 -4.275 4.795 7.901 -0.834 1.520 -ATOM 3854 H1 TIP3 4102 -4.818 4.055 7.722 0.417 1.000 -ATOM 3855 H2 TIP3 4102 -3.748 4.835 7.062 0.417 1.000 -ATOM 3856 OH2 TIP3 4103 12.539 -3.322 12.531 -0.834 1.520 -ATOM 3857 H1 TIP3 4103 11.809 -2.734 12.809 0.417 1.000 -ATOM 3858 H2 TIP3 4103 13.199 -3.256 13.220 0.417 1.000 -ATOM 3859 OH2 TIP3 4104 -2.720 -5.813 2.328 -0.834 1.520 -ATOM 3860 H1 TIP3 4104 -3.074 -6.151 1.493 0.417 1.000 -ATOM 3861 H2 TIP3 4104 -1.809 -6.180 2.308 0.417 1.000 -ATOM 3862 OH2 TIP3 4105 7.964 9.704 18.059 -0.834 1.520 -ATOM 3863 H1 TIP3 4105 8.117 10.373 18.705 0.417 1.000 -ATOM 3864 H2 TIP3 4105 8.792 9.595 17.687 0.417 1.000 -ATOM 3865 OH2 TIP3 4111 5.610 -0.911 15.594 -0.834 1.520 -ATOM 3866 H1 TIP3 4111 4.892 -0.302 15.373 0.417 1.000 -ATOM 3867 H2 TIP3 4111 5.107 -1.675 15.959 0.417 1.000 -ATOM 3868 OH2 TIP3 4116 8.314 11.034 -13.488 -0.834 1.520 -ATOM 3869 H1 TIP3 4116 8.977 10.813 -12.830 0.417 1.000 -ATOM 3870 H2 TIP3 4116 7.711 10.233 -13.413 0.417 1.000 -ATOM 3871 OH2 TIP3 4120 18.872 10.165 -7.349 -0.834 1.520 -ATOM 3872 H1 TIP3 4120 19.333 9.322 -7.181 0.417 1.000 -ATOM 3873 H2 TIP3 4120 19.365 10.598 -8.107 0.417 1.000 -ATOM 3874 OH2 TIP3 4121 8.897 -1.486 -8.849 -0.834 1.520 -ATOM 3875 H1 TIP3 4121 8.880 -1.932 -8.002 0.417 1.000 -ATOM 3876 H2 TIP3 4121 7.887 -1.323 -8.982 0.417 1.000 -ATOM 3877 OH2 TIP3 4122 12.032 2.534 9.832 -0.834 1.520 -ATOM 3878 H1 TIP3 4122 12.926 2.262 9.985 0.417 1.000 -ATOM 3879 H2 TIP3 4122 11.952 2.477 8.841 0.417 1.000 -ATOM 3880 OH2 TIP3 4123 18.641 8.747 -3.397 -0.834 1.520 -ATOM 3881 H1 TIP3 4123 17.669 8.714 -3.558 0.417 1.000 -ATOM 3882 H2 TIP3 4123 18.986 8.413 -4.231 0.417 1.000 -ATOM 3883 OH2 TIP3 4127 8.501 2.159 11.404 -0.834 1.520 -ATOM 3884 H1 TIP3 4127 8.956 2.452 12.204 0.417 1.000 -ATOM 3885 H2 TIP3 4127 7.774 2.841 11.233 0.417 1.000 -ATOM 3886 OH2 TIP3 4138 8.044 -1.600 -17.478 -0.834 1.520 -ATOM 3887 H1 TIP3 4138 7.927 -0.870 -18.225 0.417 1.000 -ATOM 3888 H2 TIP3 4138 7.159 -1.823 -17.185 0.417 1.000 -ATOM 3889 OH2 TIP3 4139 6.481 7.553 -10.971 -0.834 1.520 -ATOM 3890 H1 TIP3 4139 6.004 7.381 -10.096 0.417 1.000 -ATOM 3891 H2 TIP3 4139 5.929 7.078 -11.618 0.417 1.000 -ATOM 3892 OH2 TIP3 4140 8.903 12.212 -1.010 -0.834 1.520 -ATOM 3893 H1 TIP3 4140 8.815 11.966 -1.916 0.417 1.000 -ATOM 3894 H2 TIP3 4140 8.006 12.124 -0.704 0.417 1.000 -ATOM 3895 OH2 TIP3 4141 1.720 0.988 -11.947 -0.834 1.520 -ATOM 3896 H1 TIP3 4141 2.147 0.491 -11.220 0.417 1.000 -ATOM 3897 H2 TIP3 4141 2.486 1.373 -12.378 0.417 1.000 -ATOM 3898 OH2 TIP3 4142 19.270 5.575 -17.443 -0.834 1.520 -ATOM 3899 H1 TIP3 4142 18.738 4.855 -17.786 0.417 1.000 -ATOM 3900 H2 TIP3 4142 18.629 6.323 -17.615 0.417 1.000 -ATOM 3901 OH2 TIP3 4143 6.601 1.149 -7.345 -0.834 1.520 -ATOM 3902 H1 TIP3 4143 7.129 1.882 -7.020 0.417 1.000 -ATOM 3903 H2 TIP3 4143 6.906 0.393 -6.862 0.417 1.000 -ATOM 3904 OH2 TIP3 4144 11.096 -13.224 3.657 -0.834 1.520 -ATOM 3905 H1 TIP3 4144 11.988 -13.476 3.265 0.417 1.000 -ATOM 3906 H2 TIP3 4144 11.323 -12.607 4.336 0.417 1.000 -ATOM 3907 OH2 TIP3 4146 12.044 8.291 6.730 -0.834 1.520 -ATOM 3908 H1 TIP3 4146 12.897 8.113 6.127 0.417 1.000 -ATOM 3909 H2 TIP3 4146 11.822 9.248 6.625 0.417 1.000 -ATOM 3910 OH2 TIP3 4147 4.689 17.948 7.004 -0.834 1.520 -ATOM 3911 H1 TIP3 4147 5.333 17.874 7.739 0.417 1.000 -ATOM 3912 H2 TIP3 4147 3.892 17.654 7.383 0.417 1.000 -ATOM 3913 OH2 TIP3 4148 10.853 11.643 16.882 -0.834 1.520 -ATOM 3914 H1 TIP3 4148 10.367 12.511 16.824 0.417 1.000 -ATOM 3915 H2 TIP3 4148 11.707 11.950 17.265 0.417 1.000 -ATOM 3916 OH2 TIP3 4150 3.171 11.918 15.414 -0.834 1.520 -ATOM 3917 H1 TIP3 4150 3.217 11.076 14.972 0.417 1.000 -ATOM 3918 H2 TIP3 4150 4.123 12.244 15.353 0.417 1.000 -ATOM 3919 OH2 TIP3 4151 14.251 2.876 14.281 -0.834 1.520 -ATOM 3920 H1 TIP3 4151 14.147 1.926 14.259 0.417 1.000 -ATOM 3921 H2 TIP3 4151 13.377 3.250 14.123 0.417 1.000 -ATOM 3922 OH2 TIP3 4157 7.107 8.478 -14.016 -0.834 1.520 -ATOM 3923 H1 TIP3 4157 7.630 7.674 -14.261 0.417 1.000 -ATOM 3924 H2 TIP3 4157 6.224 8.217 -14.144 0.417 1.000 -ATOM 3925 OH2 TIP3 4158 4.943 19.812 -16.720 -0.834 1.520 -ATOM 3926 H1 TIP3 4158 4.840 18.876 -16.851 0.417 1.000 -ATOM 3927 H2 TIP3 4158 5.901 19.929 -16.832 0.417 1.000 -ATOM 3928 OH2 TIP3 4161 11.156 4.433 -18.883 -0.834 1.520 -ATOM 3929 H1 TIP3 4161 10.846 4.181 -17.998 0.417 1.000 -ATOM 3930 H2 TIP3 4161 11.896 3.831 -18.923 0.417 1.000 -ATOM 3931 OH2 TIP3 4162 0.504 11.104 3.859 -0.834 1.520 -ATOM 3932 H1 TIP3 4162 0.195 11.056 4.816 0.417 1.000 -ATOM 3933 H2 TIP3 4162 0.136 10.246 3.526 0.417 1.000 -ATOM 3934 OH2 TIP3 4163 0.735 -0.181 7.128 -0.834 1.520 -ATOM 3935 H1 TIP3 4163 -0.115 -0.007 7.429 0.417 1.000 -ATOM 3936 H2 TIP3 4163 0.766 0.363 6.302 0.417 1.000 -ATOM 3937 OH2 TIP3 4165 9.874 8.123 -1.393 -0.834 1.520 -ATOM 3938 H1 TIP3 4165 9.015 8.213 -0.949 0.417 1.000 -ATOM 3939 H2 TIP3 4165 10.498 8.465 -0.767 0.417 1.000 -ATOM 3940 OH2 TIP3 4166 15.533 4.218 16.427 -0.834 1.520 -ATOM 3941 H1 TIP3 4166 14.911 4.824 15.962 0.417 1.000 -ATOM 3942 H2 TIP3 4166 15.288 3.372 16.001 0.417 1.000 -ATOM 3943 OH2 TIP3 4167 5.634 13.114 5.143 -0.834 1.520 -ATOM 3944 H1 TIP3 4167 6.549 13.396 5.248 0.417 1.000 -ATOM 3945 H2 TIP3 4167 5.585 12.459 5.932 0.417 1.000 -ATOM 3946 OH2 TIP3 4168 15.325 19.232 14.039 -0.834 1.520 -ATOM 3947 H1 TIP3 4168 16.210 18.867 14.030 0.417 1.000 -ATOM 3948 H2 TIP3 4168 15.402 19.820 14.803 0.417 1.000 -ATOM 3949 OH2 TIP3 4179 6.844 3.498 -18.022 -0.834 1.520 -ATOM 3950 H1 TIP3 4179 6.643 4.419 -17.863 0.417 1.000 -ATOM 3951 H2 TIP3 4179 6.537 3.018 -17.213 0.417 1.000 -ATOM 3952 OH2 TIP3 4181 5.540 10.998 -16.668 -0.834 1.520 -ATOM 3953 H1 TIP3 4181 5.672 11.950 -16.477 0.417 1.000 -ATOM 3954 H2 TIP3 4181 6.411 10.658 -16.461 0.417 1.000 -ATOM 3955 OH2 TIP3 4184 3.350 5.426 -17.351 -0.834 1.520 -ATOM 3956 H1 TIP3 4184 4.136 5.667 -17.925 0.417 1.000 -ATOM 3957 H2 TIP3 4184 2.685 6.158 -17.650 0.417 1.000 -ATOM 3958 OH2 TIP3 4185 1.361 6.625 11.578 -0.834 1.520 -ATOM 3959 H1 TIP3 4185 1.071 5.884 12.149 0.417 1.000 -ATOM 3960 H2 TIP3 4185 0.794 7.382 11.851 0.417 1.000 -ATOM 3961 OH2 TIP3 4186 8.010 3.657 -6.705 -0.834 1.520 -ATOM 3962 H1 TIP3 4186 8.334 3.472 -5.800 0.417 1.000 -ATOM 3963 H2 TIP3 4186 8.782 3.742 -7.168 0.417 1.000 -ATOM 3964 OH2 TIP3 4188 0.036 13.982 19.637 -0.834 1.520 -ATOM 3965 H1 TIP3 4188 0.203 14.913 19.756 0.417 1.000 -ATOM 3966 H2 TIP3 4188 0.714 13.737 18.982 0.417 1.000 -ATOM 3967 OH2 TIP3 4191 17.828 8.861 1.960 -0.834 1.520 -ATOM 3968 H1 TIP3 4191 17.815 9.267 1.103 0.417 1.000 -ATOM 3969 H2 TIP3 4191 17.384 9.537 2.444 0.417 1.000 -ATOM 3970 OH2 TIP3 4198 14.961 18.217 -15.090 -0.834 1.520 -ATOM 3971 H1 TIP3 4198 15.628 18.919 -15.326 0.417 1.000 -ATOM 3972 H2 TIP3 4198 14.123 18.595 -15.436 0.417 1.000 -ATOM 3973 OH2 TIP3 4201 16.903 3.552 -16.985 -0.834 1.520 -ATOM 3974 H1 TIP3 4201 17.054 3.149 -16.144 0.417 1.000 -ATOM 3975 H2 TIP3 4201 16.843 4.518 -16.796 0.417 1.000 -ATOM 3976 OH2 TIP3 4202 4.020 3.447 -11.354 -0.834 1.520 -ATOM 3977 H1 TIP3 4202 4.595 3.186 -10.658 0.417 1.000 -ATOM 3978 H2 TIP3 4202 3.148 3.534 -10.859 0.417 1.000 -ATOM 3979 OH2 TIP3 4208 16.040 18.645 10.137 -0.834 1.520 -ATOM 3980 H1 TIP3 4208 15.818 18.251 9.289 0.417 1.000 -ATOM 3981 H2 TIP3 4208 16.743 18.081 10.424 0.417 1.000 -ATOM 3982 OH2 TIP3 4209 17.866 16.382 10.694 -0.834 1.520 -ATOM 3983 H1 TIP3 4209 16.987 16.068 10.527 0.417 1.000 -ATOM 3984 H2 TIP3 4209 18.004 16.114 11.611 0.417 1.000 -ATOM 3985 OH2 TIP3 4211 13.191 19.588 12.121 -0.834 1.520 -ATOM 3986 H1 TIP3 4211 13.688 19.512 11.276 0.417 1.000 -ATOM 3987 H2 TIP3 4211 13.852 19.654 12.886 0.417 1.000 -ATOM 3988 OH2 TIP3 4215 5.341 14.047 15.175 -0.834 1.520 -ATOM 3989 H1 TIP3 4215 5.027 14.819 14.579 0.417 1.000 -ATOM 3990 H2 TIP3 4215 5.786 13.510 14.502 0.417 1.000 -ATOM 3991 OH2 TIP3 4219 -4.887 14.268 -12.565 -0.834 1.520 -ATOM 3992 H1 TIP3 4219 -5.450 13.507 -12.345 0.417 1.000 -ATOM 3993 H2 TIP3 4219 -4.811 14.702 -11.685 0.417 1.000 -ATOM 3994 OH2 TIP3 4225 10.575 16.188 -5.603 -0.834 1.520 -ATOM 3995 H1 TIP3 4225 10.493 15.571 -6.392 0.417 1.000 -ATOM 3996 H2 TIP3 4225 10.725 17.080 -6.020 0.417 1.000 -ATOM 3997 OH2 TIP3 4231 9.922 16.955 11.148 -0.834 1.520 -ATOM 3998 H1 TIP3 4231 10.733 16.825 11.611 0.417 1.000 -ATOM 3999 H2 TIP3 4231 9.251 16.787 11.827 0.417 1.000 -ATOM 4000 OH2 TIP3 4235 15.712 12.959 18.833 -0.834 1.520 -ATOM 4001 H1 TIP3 4235 16.574 13.215 19.229 0.417 1.000 -ATOM 4002 H2 TIP3 4235 15.344 13.862 18.696 0.417 1.000 -ATOM 4003 OH2 TIP3 4243 -2.746 8.667 -5.944 -0.834 1.520 -ATOM 4004 H1 TIP3 4243 -2.138 9.322 -5.840 0.417 1.000 -ATOM 4005 H2 TIP3 4243 -2.223 7.880 -6.124 0.417 1.000 -ATOM 4006 OH2 TIP3 4247 7.357 16.032 -11.843 -0.834 1.520 -ATOM 4007 H1 TIP3 4247 7.873 15.271 -11.480 0.417 1.000 -ATOM 4008 H2 TIP3 4247 7.529 15.967 -12.836 0.417 1.000 -ATOM 4009 OH2 TIP3 4251 17.050 15.793 0.041 -0.834 1.520 -ATOM 4010 H1 TIP3 4251 16.956 14.986 -0.518 0.417 1.000 -ATOM 4011 H2 TIP3 4251 16.506 15.560 0.846 0.417 1.000 -ATOM 4012 OH2 TIP3 4266 11.616 19.099 -12.332 -0.834 1.520 -ATOM 4013 H1 TIP3 4266 10.929 18.497 -12.078 0.417 1.000 -ATOM 4014 H2 TIP3 4266 11.948 19.297 -11.435 0.417 1.000 -ATOM 4015 OH2 TIP3 4273 4.693 13.537 2.244 -0.834 1.520 -ATOM 4016 H1 TIP3 4273 4.931 12.583 2.306 0.417 1.000 -ATOM 4017 H2 TIP3 4273 4.874 13.826 3.118 0.417 1.000 -ATOM 4018 OH2 TIP3 4287 -7.859 12.047 -6.794 -0.834 1.520 -ATOM 4019 H1 TIP3 4287 -7.801 12.594 -7.663 0.417 1.000 -ATOM 4020 H2 TIP3 4287 -6.883 12.148 -6.520 0.417 1.000 -ATOM 4021 OH2 TIP3 4304 17.274 16.637 -13.285 -0.834 1.520 -ATOM 4022 H1 TIP3 4304 16.350 17.009 -13.199 0.417 1.000 -ATOM 4023 H2 TIP3 4304 17.787 17.175 -12.693 0.417 1.000 -ATOM 4024 OH2 TIP3 4307 14.858 15.098 -14.371 -0.834 1.520 -ATOM 4025 H1 TIP3 4307 14.077 15.462 -14.005 0.417 1.000 -ATOM 4026 H2 TIP3 4307 15.510 15.851 -14.611 0.417 1.000 -ATOM 4027 OH2 TIP3 4315 2.279 12.287 11.129 -0.834 1.520 -ATOM 4028 H1 TIP3 4315 1.427 12.216 10.699 0.417 1.000 -ATOM 4029 H2 TIP3 4315 2.341 11.392 11.600 0.417 1.000 -ATOM 4030 OH2 TIP3 4356 3.384 -13.603 -0.594 -0.834 1.520 -ATOM 4031 H1 TIP3 4356 3.481 -13.468 0.329 0.417 1.000 -ATOM 4032 H2 TIP3 4356 2.511 -14.056 -0.582 0.417 1.000 -ATOM 4033 OH2 TIP3 4380 -1.964 -18.062 4.191 -0.834 1.520 -ATOM 4034 H1 TIP3 4380 -1.228 -18.081 4.829 0.417 1.000 -ATOM 4035 H2 TIP3 4380 -1.577 -18.545 3.463 0.417 1.000 -ATOM 4036 OH2 TIP3 4394 3.400 -11.608 -9.697 -0.834 1.520 -ATOM 4037 H1 TIP3 4394 4.178 -12.174 -9.711 0.417 1.000 -ATOM 4038 H2 TIP3 4394 3.008 -11.779 -8.782 0.417 1.000 -ATOM 4039 OH2 TIP3 4396 5.172 -12.191 9.494 -0.834 1.520 -ATOM 4040 H1 TIP3 4396 5.176 -11.534 10.186 0.417 1.000 -ATOM 4041 H2 TIP3 4396 5.535 -11.703 8.743 0.417 1.000 -ATOM 4042 OH2 TIP3 4414 10.332 -15.308 -15.952 -0.834 1.520 -ATOM 4043 H1 TIP3 4414 10.893 -16.060 -15.604 0.417 1.000 -ATOM 4044 H2 TIP3 4414 9.553 -15.176 -15.369 0.417 1.000 -ATOM 4045 OH2 TIP3 4417 5.132 -6.845 -1.162 -0.834 1.520 -ATOM 4046 H1 TIP3 4417 4.699 -5.934 -1.280 0.417 1.000 -ATOM 4047 H2 TIP3 4417 4.810 -7.123 -0.285 0.417 1.000 -ATOM 4048 OH2 TIP3 4419 5.503 -17.247 -3.035 -0.834 1.520 -ATOM 4049 H1 TIP3 4419 5.005 -16.406 -3.081 0.417 1.000 -ATOM 4050 H2 TIP3 4419 5.901 -17.218 -3.914 0.417 1.000 -ATOM 4051 OH2 TIP3 4421 9.489 -15.226 11.331 -0.834 1.520 -ATOM 4052 H1 TIP3 4421 10.368 -15.260 11.733 0.417 1.000 -ATOM 4053 H2 TIP3 4421 9.461 -14.616 10.529 0.417 1.000 -ATOM 4054 OH2 TIP3 4422 18.173 -16.870 12.614 -0.834 1.520 -ATOM 4055 H1 TIP3 4422 18.948 -16.846 13.185 0.417 1.000 -ATOM 4056 H2 TIP3 4422 17.924 -15.926 12.518 0.417 1.000 -ATOM 4057 OH2 TIP3 4432 15.217 -1.522 -9.399 -0.834 1.520 -ATOM 4058 H1 TIP3 4432 14.477 -0.993 -9.739 0.417 1.000 -ATOM 4059 H2 TIP3 4432 15.647 -1.909 -10.229 0.417 1.000 -ATOM 4060 OH2 TIP3 4434 16.697 -14.491 -12.843 -0.834 1.520 -ATOM 4061 H1 TIP3 4434 16.091 -15.196 -12.606 0.417 1.000 -ATOM 4062 H2 TIP3 4434 16.834 -14.033 -12.010 0.417 1.000 -ATOM 4063 OH2 TIP3 4437 9.655 -11.328 -18.476 -0.834 1.520 -ATOM 4064 H1 TIP3 4437 9.762 -11.373 -17.509 0.417 1.000 -ATOM 4065 H2 TIP3 4437 9.214 -10.489 -18.681 0.417 1.000 -ATOM 4066 OH2 TIP3 4438 13.579 -1.716 -0.439 -0.834 1.520 -ATOM 4067 H1 TIP3 4438 14.100 -0.964 -0.016 0.417 1.000 -ATOM 4068 H2 TIP3 4438 14.046 -2.482 -0.164 0.417 1.000 -ATOM 4069 OH2 TIP3 4441 16.930 -17.526 10.084 -0.834 1.520 -ATOM 4070 H1 TIP3 4441 17.319 -17.311 10.943 0.417 1.000 -ATOM 4071 H2 TIP3 4441 17.488 -18.263 9.698 0.417 1.000 -ATOM 4072 OH2 TIP3 4442 12.062 -10.642 8.946 -0.834 1.520 -ATOM 4073 H1 TIP3 4442 11.398 -11.189 9.447 0.417 1.000 -ATOM 4074 H2 TIP3 4442 12.665 -10.420 9.672 0.417 1.000 -ATOM 4075 OH2 TIP3 4443 15.166 -7.503 16.394 -0.834 1.520 -ATOM 4076 H1 TIP3 4443 15.812 -6.773 16.164 0.417 1.000 -ATOM 4077 H2 TIP3 4443 14.925 -7.382 17.288 0.417 1.000 -ATOM 4078 OH2 TIP3 4455 7.445 -15.199 -14.707 -0.834 1.520 -ATOM 4079 H1 TIP3 4455 7.476 -16.017 -14.163 0.417 1.000 -ATOM 4080 H2 TIP3 4455 7.046 -14.540 -14.139 0.417 1.000 -ATOM 4081 OH2 TIP3 4456 9.751 -8.283 8.837 -0.834 1.520 -ATOM 4082 H1 TIP3 4456 9.421 -8.425 7.903 0.417 1.000 -ATOM 4083 H2 TIP3 4456 9.205 -7.506 9.067 0.417 1.000 -ATOM 4084 OH2 TIP3 4457 16.162 7.874 -7.021 -0.834 1.520 -ATOM 4085 H1 TIP3 4457 17.054 7.642 -6.800 0.417 1.000 -ATOM 4086 H2 TIP3 4457 15.784 7.060 -7.081 0.417 1.000 -ATOM 4087 OH2 TIP3 4461 11.618 -16.667 0.526 -0.834 1.520 -ATOM 4088 H1 TIP3 4461 11.142 -15.894 0.926 0.417 1.000 -ATOM 4089 H2 TIP3 4461 12.225 -16.274 -0.122 0.417 1.000 -ATOM 4090 OH2 TIP3 4462 14.034 -9.533 10.525 -0.834 1.520 -ATOM 4091 H1 TIP3 4462 14.991 -9.644 10.300 0.417 1.000 -ATOM 4092 H2 TIP3 4462 14.089 -8.835 11.275 0.417 1.000 -ATOM 4093 OH2 TIP3 4465 17.907 -12.350 10.036 -0.834 1.520 -ATOM 4094 H1 TIP3 4465 17.462 -11.513 10.175 0.417 1.000 -ATOM 4095 H2 TIP3 4465 17.511 -12.533 9.159 0.417 1.000 -ATOM 4096 OH2 TIP3 4466 18.553 -13.311 5.369 -0.834 1.520 -ATOM 4097 H1 TIP3 4466 18.108 -13.949 4.739 0.417 1.000 -ATOM 4098 H2 TIP3 4466 19.112 -13.875 5.953 0.417 1.000 -ATOM 4099 OH2 TIP3 4473 17.331 -7.317 -18.582 -0.834 1.520 -ATOM 4100 H1 TIP3 4473 16.873 -7.395 -19.420 0.417 1.000 -ATOM 4101 H2 TIP3 4473 17.504 -6.322 -18.536 0.417 1.000 -ATOM 4102 OH2 TIP3 4474 13.250 12.565 -12.865 -0.834 1.520 -ATOM 4103 H1 TIP3 4474 13.340 11.623 -12.647 0.417 1.000 -ATOM 4104 H2 TIP3 4474 12.707 12.922 -12.188 0.417 1.000 -ATOM 4105 OH2 TIP3 4477 13.966 -14.428 -15.275 -0.834 1.520 -ATOM 4106 H1 TIP3 4477 14.760 -14.591 -15.796 0.417 1.000 -ATOM 4107 H2 TIP3 4477 13.593 -15.326 -14.961 0.417 1.000 -ATOM 4108 OH2 TIP3 4479 12.349 -7.984 -8.548 -0.834 1.520 -ATOM 4109 H1 TIP3 4479 11.652 -8.383 -7.971 0.417 1.000 -ATOM 4110 H2 TIP3 4479 13.149 -8.074 -7.996 0.417 1.000 -ATOM 4111 OH2 TIP3 4480 1.457 -0.096 -1.151 -0.834 1.520 -ATOM 4112 H1 TIP3 4480 0.517 -0.113 -1.045 0.417 1.000 -ATOM 4113 H2 TIP3 4480 1.748 0.201 -0.225 0.417 1.000 -ATOM 4114 OH2 TIP3 4483 18.557 0.554 15.616 -0.834 1.520 -ATOM 4115 H1 TIP3 4483 17.932 0.767 14.896 0.417 1.000 -ATOM 4116 H2 TIP3 4483 18.884 1.395 15.886 0.417 1.000 -ATOM 4117 OH2 TIP3 4484 1.289 4.440 6.231 -0.834 1.520 -ATOM 4118 H1 TIP3 4484 1.646 4.235 5.374 0.417 1.000 -ATOM 4119 H2 TIP3 4484 1.743 5.233 6.585 0.417 1.000 -ATOM 4120 OH2 TIP3 4485 -0.996 -18.120 12.785 -0.834 1.520 -ATOM 4121 H1 TIP3 4485 -1.571 -18.243 11.981 0.417 1.000 -ATOM 4122 H2 TIP3 4485 -0.699 -19.007 13.010 0.417 1.000 -ATOM 4123 OH2 TIP3 4496 13.027 2.407 -7.441 -0.834 1.520 -ATOM 4124 H1 TIP3 4496 12.840 1.573 -7.933 0.417 1.000 -ATOM 4125 H2 TIP3 4496 13.395 2.972 -8.121 0.417 1.000 -ATOM 4126 OH2 TIP3 4497 1.477 18.729 -8.303 -0.834 1.520 -ATOM 4127 H1 TIP3 4497 1.458 18.840 -9.294 0.417 1.000 -ATOM 4128 H2 TIP3 4497 0.942 17.904 -8.111 0.417 1.000 -ATOM 4129 OH2 TIP3 4498 3.539 -4.333 11.422 -0.834 1.520 -ATOM 4130 H1 TIP3 4498 4.312 -3.756 11.445 0.417 1.000 -ATOM 4131 H2 TIP3 4498 2.967 -3.738 10.954 0.417 1.000 -ATOM 4132 OH2 TIP3 4499 17.198 -5.556 -4.175 -0.834 1.520 -ATOM 4133 H1 TIP3 4499 16.753 -5.273 -3.323 0.417 1.000 -ATOM 4134 H2 TIP3 4499 18.019 -5.096 -4.196 0.417 1.000 -ATOM 4135 OH2 TIP3 4500 18.648 -9.065 -16.791 -0.834 1.520 -ATOM 4136 H1 TIP3 4500 18.213 -8.491 -17.462 0.417 1.000 -ATOM 4137 H2 TIP3 4500 18.113 -9.113 -15.992 0.417 1.000 -ATOM 4138 OH2 TIP3 4501 -5.318 -8.666 -5.612 -0.834 1.520 -ATOM 4139 H1 TIP3 4501 -4.764 -8.059 -6.124 0.417 1.000 -ATOM 4140 H2 TIP3 4501 -5.734 -9.317 -6.237 0.417 1.000 -ATOM 4141 OH2 TIP3 4503 4.235 8.471 14.535 -0.834 1.520 -ATOM 4142 H1 TIP3 4503 3.499 8.104 14.977 0.417 1.000 -ATOM 4143 H2 TIP3 4503 4.770 8.494 15.356 0.417 1.000 -ATOM 4144 OH2 TIP3 4509 8.680 -13.583 15.453 -0.834 1.520 -ATOM 4145 H1 TIP3 4509 9.288 -12.944 15.767 0.417 1.000 -ATOM 4146 H2 TIP3 4509 8.525 -14.153 16.240 0.417 1.000 -ATOM 4147 OH2 TIP3 4513 16.686 -4.537 -14.481 -0.834 1.520 -ATOM 4148 H1 TIP3 4513 15.907 -5.023 -14.424 0.417 1.000 -ATOM 4149 H2 TIP3 4513 17.050 -4.941 -15.339 0.417 1.000 -ATOM 4150 OH2 TIP3 4515 -7.586 -10.996 -6.091 -0.834 1.520 -ATOM 4151 H1 TIP3 4515 -8.477 -11.069 -5.816 0.417 1.000 -ATOM 4152 H2 TIP3 4515 -7.625 -10.234 -6.714 0.417 1.000 -ATOM 4153 OH2 TIP3 4516 5.948 5.182 -12.605 -0.834 1.520 -ATOM 4154 H1 TIP3 4516 5.997 4.870 -13.514 0.417 1.000 -ATOM 4155 H2 TIP3 4516 5.233 4.634 -12.130 0.417 1.000 -ATOM 4156 OH2 TIP3 4518 18.146 8.444 -12.676 -0.834 1.520 -ATOM 4157 H1 TIP3 4518 18.822 8.278 -13.319 0.417 1.000 -ATOM 4158 H2 TIP3 4518 18.298 9.354 -12.307 0.417 1.000 -ATOM 4159 OH2 TIP3 4519 -0.929 -2.722 -18.619 -0.834 1.520 -ATOM 4160 H1 TIP3 4519 -1.109 -2.940 -19.564 0.417 1.000 -ATOM 4161 H2 TIP3 4519 -0.115 -3.219 -18.491 0.417 1.000 -ATOM 4162 OH2 TIP3 4520 15.355 2.251 2.902 -0.834 1.520 -ATOM 4163 H1 TIP3 4520 15.943 1.654 3.397 0.417 1.000 -ATOM 4164 H2 TIP3 4520 15.163 3.005 3.523 0.417 1.000 -ATOM 4165 OH2 TIP3 4523 3.954 -7.885 1.190 -0.834 1.520 -ATOM 4166 H1 TIP3 4523 4.341 -8.397 1.865 0.417 1.000 -ATOM 4167 H2 TIP3 4523 3.309 -7.316 1.623 0.417 1.000 -ATOM 4168 OH2 TIP3 4524 10.071 -8.509 -4.229 -0.834 1.520 -ATOM 4169 H1 TIP3 4524 9.660 -7.590 -4.115 0.417 1.000 -ATOM 4170 H2 TIP3 4524 9.290 -9.095 -4.125 0.417 1.000 -ATOM 4171 OH2 TIP3 4536 11.495 0.117 -11.470 -0.834 1.520 -ATOM 4172 H1 TIP3 4536 11.284 0.364 -12.364 0.417 1.000 -ATOM 4173 H2 TIP3 4536 12.453 0.257 -11.456 0.417 1.000 -ATOM 4174 OH2 TIP3 4537 1.619 3.461 -9.753 -0.834 1.520 -ATOM 4175 H1 TIP3 4537 1.079 3.002 -10.402 0.417 1.000 -ATOM 4176 H2 TIP3 4537 1.571 2.891 -8.929 0.417 1.000 -ATOM 4177 OH2 TIP3 4538 10.990 4.095 -13.875 -0.834 1.520 -ATOM 4178 H1 TIP3 4538 10.920 3.621 -12.993 0.417 1.000 -ATOM 4179 H2 TIP3 4538 11.910 3.868 -14.115 0.417 1.000 -ATOM 4180 OH2 TIP3 4539 11.215 2.123 4.084 -0.834 1.520 -ATOM 4181 H1 TIP3 4539 11.124 2.307 3.136 0.417 1.000 -ATOM 4182 H2 TIP3 4539 11.570 2.978 4.423 0.417 1.000 -ATOM 4183 OH2 TIP3 4540 1.263 16.061 -8.655 -0.834 1.520 -ATOM 4184 H1 TIP3 4540 1.685 16.021 -9.517 0.417 1.000 -ATOM 4185 H2 TIP3 4540 0.886 15.164 -8.555 0.417 1.000 -ATOM 4186 OH2 TIP3 4541 13.538 0.062 14.310 -0.834 1.520 -ATOM 4187 H1 TIP3 4541 12.714 -0.002 13.872 0.417 1.000 -ATOM 4188 H2 TIP3 4541 13.228 -0.287 15.171 0.417 1.000 -ATOM 4189 OH2 TIP3 4543 1.784 -1.228 16.445 -0.834 1.520 -ATOM 4190 H1 TIP3 4543 2.589 -1.711 16.608 0.417 1.000 -ATOM 4191 H2 TIP3 4543 1.535 -1.595 15.600 0.417 1.000 -ATOM 4192 OH2 TIP3 4545 16.643 16.724 7.014 -0.834 1.520 -ATOM 4193 H1 TIP3 4545 16.487 16.247 6.224 0.417 1.000 -ATOM 4194 H2 TIP3 4545 17.378 17.320 6.753 0.417 1.000 -ATOM 4195 OH2 TIP3 4549 18.869 -4.390 14.321 -0.834 1.520 -ATOM 4196 H1 TIP3 4549 18.991 -3.706 15.026 0.417 1.000 -ATOM 4197 H2 TIP3 4549 19.652 -4.905 14.400 0.417 1.000 -ATOM 4198 OH2 TIP3 4551 10.956 17.978 16.943 -0.834 1.520 -ATOM 4199 H1 TIP3 4551 11.185 18.227 16.008 0.417 1.000 -ATOM 4200 H2 TIP3 4551 11.668 18.417 17.549 0.417 1.000 -ATOM 4201 OH2 TIP3 4553 2.736 5.421 -14.182 -0.834 1.520 -ATOM 4202 H1 TIP3 4553 2.831 4.722 -14.918 0.417 1.000 -ATOM 4203 H2 TIP3 4553 1.816 5.685 -14.148 0.417 1.000 -ATOM 4204 OH2 TIP3 4558 17.616 2.220 -14.417 -0.834 1.520 -ATOM 4205 H1 TIP3 4558 18.165 1.700 -14.918 0.417 1.000 -ATOM 4206 H2 TIP3 4558 16.925 1.607 -14.167 0.417 1.000 -ATOM 4207 OH2 TIP3 4559 -3.681 4.159 -13.925 -0.834 1.520 -ATOM 4208 H1 TIP3 4559 -3.767 3.434 -13.225 0.417 1.000 -ATOM 4209 H2 TIP3 4559 -3.686 4.950 -13.338 0.417 1.000 -ATOM 4210 OH2 TIP3 4560 15.504 5.791 -0.107 -0.834 1.520 -ATOM 4211 H1 TIP3 4560 15.552 5.869 -1.034 0.417 1.000 -ATOM 4212 H2 TIP3 4560 15.133 6.668 0.099 0.417 1.000 -ATOM 4213 OH2 TIP3 4561 14.553 -1.863 -16.906 -0.834 1.520 -ATOM 4214 H1 TIP3 4561 13.885 -1.466 -17.499 0.417 1.000 -ATOM 4215 H2 TIP3 4561 14.059 -2.536 -16.426 0.417 1.000 -ATOM 4216 OH2 TIP3 4562 16.051 1.549 -4.253 -0.834 1.520 -ATOM 4217 H1 TIP3 4562 16.255 1.107 -5.080 0.417 1.000 -ATOM 4218 H2 TIP3 4562 16.833 1.449 -3.640 0.417 1.000 -ATOM 4219 OH2 TIP3 4563 18.207 12.168 -9.292 -0.834 1.520 -ATOM 4220 H1 TIP3 4563 18.067 12.816 -8.530 0.417 1.000 -ATOM 4221 H2 TIP3 4563 17.394 11.692 -9.219 0.417 1.000 -ATOM 4222 OH2 TIP3 4564 12.982 6.177 2.803 -0.834 1.520 -ATOM 4223 H1 TIP3 4564 12.584 5.651 3.506 0.417 1.000 -ATOM 4224 H2 TIP3 4564 13.497 6.805 3.320 0.417 1.000 -ATOM 4225 OH2 TIP3 4565 5.352 13.771 -3.849 -0.834 1.520 -ATOM 4226 H1 TIP3 4565 4.521 13.423 -3.587 0.417 1.000 -ATOM 4227 H2 TIP3 4565 5.594 14.435 -3.108 0.417 1.000 -ATOM 4228 OH2 TIP3 4566 13.839 9.446 17.961 -0.834 1.520 -ATOM 4229 H1 TIP3 4566 14.468 9.338 18.585 0.417 1.000 -ATOM 4230 H2 TIP3 4566 13.581 10.371 18.122 0.417 1.000 -ATOM 4231 OH2 TIP3 4567 1.876 8.147 15.900 -0.834 1.520 -ATOM 4232 H1 TIP3 4567 1.471 7.689 16.573 0.417 1.000 -ATOM 4233 H2 TIP3 4567 1.293 8.795 15.666 0.417 1.000 -ATOM 4234 OH2 TIP3 4568 11.686 4.015 14.228 -0.834 1.520 -ATOM 4235 H1 TIP3 4568 11.010 4.071 14.907 0.417 1.000 -ATOM 4236 H2 TIP3 4568 11.263 4.222 13.320 0.417 1.000 -ATOM 4237 OH2 TIP3 4569 11.683 -3.200 -6.633 -0.834 1.520 -ATOM 4238 H1 TIP3 4569 12.318 -2.620 -6.224 0.417 1.000 -ATOM 4239 H2 TIP3 4569 11.964 -3.242 -7.618 0.417 1.000 -ATOM 4240 OH2 TIP3 4574 13.189 -1.652 16.419 -0.834 1.520 -ATOM 4241 H1 TIP3 4574 13.381 -2.579 16.463 0.417 1.000 -ATOM 4242 H2 TIP3 4574 12.287 -1.545 16.721 0.417 1.000 -ATOM 4243 OH2 TIP3 4578 3.418 7.184 -11.936 -0.834 1.520 -ATOM 4244 H1 TIP3 4578 3.266 6.649 -11.124 0.417 1.000 -ATOM 4245 H2 TIP3 4578 3.361 6.508 -12.646 0.417 1.000 -ATOM 4246 OH2 TIP3 4581 19.486 -1.804 -8.135 -0.834 1.520 -ATOM 4247 H1 TIP3 4581 19.797 -1.290 -7.392 0.417 1.000 -ATOM 4248 H2 TIP3 4581 19.728 -2.737 -7.866 0.417 1.000 -ATOM 4249 OH2 TIP3 4582 4.820 -1.079 -16.483 -0.834 1.520 -ATOM 4250 H1 TIP3 4582 3.987 -0.765 -16.882 0.417 1.000 -ATOM 4251 H2 TIP3 4582 4.810 -2.035 -16.689 0.417 1.000 -ATOM 4252 OH2 TIP3 4585 18.295 2.659 10.005 -0.834 1.520 -ATOM 4253 H1 TIP3 4585 18.196 2.250 9.129 0.417 1.000 -ATOM 4254 H2 TIP3 4585 17.557 3.254 10.066 0.417 1.000 -ATOM 4255 OH2 TIP3 4587 9.475 6.956 11.202 -0.834 1.520 -ATOM 4256 H1 TIP3 4587 10.155 7.521 11.557 0.417 1.000 -ATOM 4257 H2 TIP3 4587 9.508 7.116 10.262 0.417 1.000 -ATOM 4258 OH2 TIP3 4588 6.245 3.672 4.162 -0.834 1.520 -ATOM 4259 H1 TIP3 4588 6.070 3.578 3.176 0.417 1.000 -ATOM 4260 H2 TIP3 4588 6.837 2.892 4.382 0.417 1.000 -ATOM 4261 OH2 TIP3 4592 8.091 6.947 16.769 -0.834 1.520 -ATOM 4262 H1 TIP3 4592 7.135 6.953 16.658 0.417 1.000 -ATOM 4263 H2 TIP3 4592 8.386 7.119 15.833 0.417 1.000 -ATOM 4264 OH2 TIP3 4599 17.291 7.648 -18.152 -0.834 1.520 -ATOM 4265 H1 TIP3 4599 16.437 8.105 -18.052 0.417 1.000 -ATOM 4266 H2 TIP3 4599 17.939 8.329 -18.400 0.417 1.000 -ATOM 4267 OH2 TIP3 4600 17.000 10.922 -16.293 -0.834 1.520 -ATOM 4268 H1 TIP3 4600 17.827 11.075 -15.857 0.417 1.000 -ATOM 4269 H2 TIP3 4600 16.406 11.698 -16.077 0.417 1.000 -ATOM 4270 OH2 TIP3 4605 11.347 8.907 3.122 -0.834 1.520 -ATOM 4271 H1 TIP3 4605 10.519 8.665 3.592 0.417 1.000 -ATOM 4272 H2 TIP3 4605 11.822 8.024 3.151 0.417 1.000 -ATOM 4273 OH2 TIP3 4606 6.291 -3.276 4.473 -0.834 1.520 -ATOM 4274 H1 TIP3 4606 5.444 -3.323 3.993 0.417 1.000 -ATOM 4275 H2 TIP3 4606 6.927 -3.732 3.904 0.417 1.000 -ATOM 4276 OH2 TIP3 4607 17.015 -2.493 5.985 -0.834 1.520 -ATOM 4277 H1 TIP3 4607 17.239 -2.097 6.919 0.417 1.000 -ATOM 4278 H2 TIP3 4607 17.779 -2.999 5.777 0.417 1.000 -ATOM 4279 OH2 TIP3 4608 2.145 13.333 17.529 -0.834 1.520 -ATOM 4280 H1 TIP3 4608 1.979 12.515 18.001 0.417 1.000 -ATOM 4281 H2 TIP3 4608 2.590 13.056 16.741 0.417 1.000 -ATOM 4282 OH2 TIP3 4623 7.223 19.014 -6.033 -0.834 1.520 -ATOM 4283 H1 TIP3 4623 6.743 19.594 -5.397 0.417 1.000 -ATOM 4284 H2 TIP3 4623 6.850 18.084 -5.856 0.417 1.000 -ATOM 4285 OH2 TIP3 4625 5.350 4.745 -6.566 -0.834 1.520 -ATOM 4286 H1 TIP3 4625 6.202 4.228 -6.613 0.417 1.000 -ATOM 4287 H2 TIP3 4625 5.022 4.517 -5.689 0.417 1.000 -ATOM 4288 OH2 TIP3 4626 -1.263 3.393 6.234 -0.834 1.520 -ATOM 4289 H1 TIP3 4626 -1.210 2.937 7.094 0.417 1.000 -ATOM 4290 H2 TIP3 4626 -0.374 3.733 6.125 0.417 1.000 -ATOM 4291 OH2 TIP3 4627 12.361 16.430 -3.441 -0.834 1.520 -ATOM 4292 H1 TIP3 4627 11.788 16.299 -2.730 0.417 1.000 -ATOM 4293 H2 TIP3 4627 11.832 16.094 -4.210 0.417 1.000 -ATOM 4294 OH2 TIP3 4628 19.527 6.045 -11.367 -0.834 1.520 -ATOM 4295 H1 TIP3 4628 18.938 5.260 -11.381 0.417 1.000 -ATOM 4296 H2 TIP3 4628 19.052 6.684 -11.897 0.417 1.000 -ATOM 4297 OH2 TIP3 4630 7.211 10.812 9.615 -0.834 1.520 -ATOM 4298 H1 TIP3 4630 6.789 10.309 10.269 0.417 1.000 -ATOM 4299 H2 TIP3 4630 7.824 10.221 9.210 0.417 1.000 -ATOM 4300 OH2 TIP3 4633 11.767 19.278 7.157 -0.834 1.520 -ATOM 4301 H1 TIP3 4633 12.726 19.564 7.038 0.417 1.000 -ATOM 4302 H2 TIP3 4633 11.646 19.012 8.054 0.417 1.000 -ATOM 4303 OH2 TIP3 4641 11.046 13.069 -14.847 -0.834 1.520 -ATOM 4304 H1 TIP3 4641 11.689 13.175 -14.057 0.417 1.000 -ATOM 4305 H2 TIP3 4641 10.211 13.605 -14.686 0.417 1.000 -ATOM 4306 OH2 TIP3 4645 8.675 13.919 -10.250 -0.834 1.520 -ATOM 4307 H1 TIP3 4645 8.333 12.994 -10.233 0.417 1.000 -ATOM 4308 H2 TIP3 4645 8.157 14.335 -9.591 0.417 1.000 -ATOM 4309 OH2 TIP3 4649 -1.297 8.268 5.613 -0.834 1.520 -ATOM 4310 H1 TIP3 4649 -1.706 7.411 5.851 0.417 1.000 -ATOM 4311 H2 TIP3 4649 -2.019 8.752 5.155 0.417 1.000 -ATOM 4312 OH2 TIP3 4653 13.095 15.980 10.504 -0.834 1.520 -ATOM 4313 H1 TIP3 4653 13.123 16.489 9.727 0.417 1.000 -ATOM 4314 H2 TIP3 4653 14.024 15.716 10.530 0.417 1.000 -ATOM 4315 OH2 TIP3 4654 -2.599 4.980 19.403 -0.834 1.520 -ATOM 4316 H1 TIP3 4654 -1.645 5.096 19.237 0.417 1.000 -ATOM 4317 H2 TIP3 4654 -3.031 5.296 18.591 0.417 1.000 -ATOM 4318 OH2 TIP3 4663 6.521 7.229 -5.307 -0.834 1.520 -ATOM 4319 H1 TIP3 4663 7.351 7.069 -4.827 0.417 1.000 -ATOM 4320 H2 TIP3 4663 6.583 6.483 -5.937 0.417 1.000 -ATOM 4321 OH2 TIP3 4668 12.950 19.024 -3.862 -0.834 1.520 -ATOM 4322 H1 TIP3 4668 12.841 18.104 -3.603 0.417 1.000 -ATOM 4323 H2 TIP3 4668 12.767 18.892 -4.826 0.417 1.000 -ATOM 4324 OH2 TIP3 4669 -1.709 14.973 11.665 -0.834 1.520 -ATOM 4325 H1 TIP3 4669 -1.975 14.247 11.144 0.417 1.000 -ATOM 4326 H2 TIP3 4669 -1.833 15.703 11.016 0.417 1.000 -ATOM 4327 OH2 TIP3 4672 15.569 14.734 10.645 -0.834 1.520 -ATOM 4328 H1 TIP3 4672 15.624 13.978 11.267 0.417 1.000 -ATOM 4329 H2 TIP3 4672 15.623 14.307 9.760 0.417 1.000 -ATOM 4330 OH2 TIP3 4677 11.446 19.237 14.364 -0.834 1.520 -ATOM 4331 H1 TIP3 4677 12.163 19.684 13.928 0.417 1.000 -ATOM 4332 H2 TIP3 4677 11.222 18.514 13.754 0.417 1.000 -ATOM 4333 OH2 TIP3 4685 12.972 13.480 -7.140 -0.834 1.520 -ATOM 4334 H1 TIP3 4685 12.983 12.627 -6.655 0.417 1.000 -ATOM 4335 H2 TIP3 4685 12.533 13.298 -7.993 0.417 1.000 -ATOM 4336 OH2 TIP3 4687 19.317 17.395 -7.048 -0.834 1.520 -ATOM 4337 H1 TIP3 4687 19.031 17.760 -6.186 0.417 1.000 -ATOM 4338 H2 TIP3 4687 19.054 18.127 -7.599 0.417 1.000 -ATOM 4339 OH2 TIP3 4692 8.687 19.611 17.304 -0.834 1.520 -ATOM 4340 H1 TIP3 4692 9.114 20.000 18.070 0.417 1.000 -ATOM 4341 H2 TIP3 4692 9.403 19.024 16.970 0.417 1.000 -ATOM 4342 OH2 TIP3 4706 5.944 13.478 -6.492 -0.834 1.520 -ATOM 4343 H1 TIP3 4706 5.621 13.604 -5.569 0.417 1.000 -ATOM 4344 H2 TIP3 4706 5.947 12.461 -6.527 0.417 1.000 -ATOM 4345 OH2 TIP3 4712 8.709 15.833 6.169 -0.834 1.520 -ATOM 4346 H1 TIP3 4712 9.149 15.672 6.985 0.417 1.000 -ATOM 4347 H2 TIP3 4712 9.141 16.681 5.896 0.417 1.000 -ATOM 4348 OH2 TIP3 4725 19.120 10.964 -11.883 -0.834 1.520 -ATOM 4349 H1 TIP3 4725 19.066 11.439 -10.987 0.417 1.000 -ATOM 4350 H2 TIP3 4725 18.534 11.537 -12.395 0.417 1.000 -ATOM 4351 OH2 TIP3 4732 19.291 14.450 -13.157 -0.834 1.520 -ATOM 4352 H1 TIP3 4732 18.552 14.975 -13.364 0.417 1.000 -ATOM 4353 H2 TIP3 4732 18.950 13.553 -13.314 0.417 1.000 -ATOM 4354 OH2 TIP3 4751 9.941 18.988 -6.723 -0.834 1.520 -ATOM 4355 H1 TIP3 4751 9.993 19.950 -6.895 0.417 1.000 -ATOM 4356 H2 TIP3 4751 8.990 18.865 -6.474 0.417 1.000 -ATOM 4357 OH2 TIP3 4787 16.528 10.978 -19.727 -0.834 1.520 -ATOM 4358 H1 TIP3 4787 16.655 11.907 -19.596 0.417 1.000 -ATOM 4359 H2 TIP3 4787 17.409 10.582 -19.468 0.417 1.000 -ATOM 4360 OH2 TIP3 4797 6.084 -12.396 4.020 -0.834 1.520 -ATOM 4361 H1 TIP3 4797 6.375 -11.741 3.400 0.417 1.000 -ATOM 4362 H2 TIP3 4797 6.866 -12.894 4.289 0.417 1.000 -ATOM 4363 OH2 TIP3 4798 -0.315 -19.138 2.352 -0.834 1.520 -ATOM 4364 H1 TIP3 4798 0.261 -18.505 2.737 0.417 1.000 -ATOM 4365 H2 TIP3 4798 -0.496 -18.701 1.487 0.417 1.000 -ATOM 4366 OH2 TIP3 4800 16.815 -19.359 15.056 -0.834 1.520 -ATOM 4367 H1 TIP3 4800 16.177 -18.755 14.675 0.417 1.000 -ATOM 4368 H2 TIP3 4800 17.254 -18.790 15.687 0.417 1.000 -ATOM 4369 OH2 TIP3 4801 6.954 -15.501 12.059 -0.834 1.520 -ATOM 4370 H1 TIP3 4801 7.894 -15.679 11.823 0.417 1.000 -ATOM 4371 H2 TIP3 4801 7.130 -14.661 12.490 0.417 1.000 -ATOM 4372 OH2 TIP3 4809 -4.102 -16.707 -18.352 -0.834 1.520 -ATOM 4373 H1 TIP3 4809 -4.163 -16.023 -17.641 0.417 1.000 -ATOM 4374 H2 TIP3 4809 -4.935 -17.204 -18.211 0.417 1.000 -ATOM 4375 OH2 TIP3 4814 10.181 -15.917 3.019 -0.834 1.520 -ATOM 4376 H1 TIP3 4814 11.052 -15.903 3.484 0.417 1.000 -ATOM 4377 H2 TIP3 4814 9.710 -16.569 3.539 0.417 1.000 -ATOM 4378 OH2 TIP3 4815 6.942 -17.643 6.825 -0.834 1.520 -ATOM 4379 H1 TIP3 4815 7.237 -17.643 7.694 0.417 1.000 -ATOM 4380 H2 TIP3 4815 6.453 -16.824 6.797 0.417 1.000 -ATOM 4381 OH2 TIP3 4820 14.901 -16.361 2.978 -0.834 1.520 -ATOM 4382 H1 TIP3 4820 14.587 -17.266 2.878 0.417 1.000 -ATOM 4383 H2 TIP3 4820 14.202 -15.983 3.577 0.417 1.000 -ATOM 4384 OH2 TIP3 4822 14.066 -18.958 4.537 -0.834 1.520 -ATOM 4385 H1 TIP3 4822 13.373 -19.364 4.102 0.417 1.000 -ATOM 4386 H2 TIP3 4822 13.669 -18.607 5.389 0.417 1.000 -ATOM 4387 OH2 TIP3 4834 14.338 -17.051 -19.090 -0.834 1.520 -ATOM 4388 H1 TIP3 4834 15.061 -16.382 -19.191 0.417 1.000 -ATOM 4389 H2 TIP3 4834 13.640 -16.569 -18.852 0.417 1.000 -ATOM 4390 OH2 TIP3 4835 7.681 -17.533 -13.447 -0.834 1.520 -ATOM 4391 H1 TIP3 4835 7.966 -18.270 -14.010 0.417 1.000 -ATOM 4392 H2 TIP3 4835 6.680 -17.588 -13.407 0.417 1.000 -ATOM 4393 OH2 TIP3 4836 19.678 -19.638 -16.511 -0.834 1.520 -ATOM 4394 H1 TIP3 4836 18.916 -19.672 -17.116 0.417 1.000 -ATOM 4395 H2 TIP3 4836 19.424 -19.064 -15.768 0.417 1.000 -ATOM 4396 OH2 TIP3 4837 0.972 -16.585 2.583 -0.834 1.520 -ATOM 4397 H1 TIP3 4837 1.469 -16.490 3.422 0.417 1.000 -ATOM 4398 H2 TIP3 4837 0.577 -15.762 2.554 0.417 1.000 -ATOM 4399 OH2 TIP3 4844 14.826 -18.690 13.180 -0.834 1.520 -ATOM 4400 H1 TIP3 4844 14.018 -18.883 13.661 0.417 1.000 -ATOM 4401 H2 TIP3 4844 14.653 -19.037 12.277 0.417 1.000 -ATOM 4402 OH2 TIP3 4849 -3.492 -10.422 -12.319 -0.834 1.520 -ATOM 4403 H1 TIP3 4849 -3.756 -10.962 -13.066 0.417 1.000 -ATOM 4404 H2 TIP3 4849 -2.696 -9.979 -12.484 0.417 1.000 -ATOM 4405 OH2 TIP3 4853 11.985 -15.201 -18.696 -0.834 1.520 -ATOM 4406 H1 TIP3 4853 11.753 -15.117 -17.729 0.417 1.000 -ATOM 4407 H2 TIP3 4853 11.077 -15.212 -19.151 0.417 1.000 -ATOM 4408 OH2 TIP3 4855 8.176 -5.568 0.160 -0.834 1.520 -ATOM 4409 H1 TIP3 4855 8.459 -6.493 0.186 0.417 1.000 -ATOM 4410 H2 TIP3 4855 8.243 -5.318 1.086 0.417 1.000 -ATOM 4411 OH2 TIP3 4856 2.237 -16.532 5.032 -0.834 1.520 -ATOM 4412 H1 TIP3 4856 3.140 -16.678 4.668 0.417 1.000 -ATOM 4413 H2 TIP3 4856 2.341 -16.158 5.910 0.417 1.000 -ATOM 4414 OH2 TIP3 4857 0.278 -7.466 -2.928 -0.834 1.520 -ATOM 4415 H1 TIP3 4857 -0.085 -8.071 -3.603 0.417 1.000 -ATOM 4416 H2 TIP3 4857 1.131 -7.948 -2.581 0.417 1.000 -ATOM 4417 OH2 TIP3 4863 15.492 -9.378 0.787 -0.834 1.520 -ATOM 4418 H1 TIP3 4863 14.502 -9.437 0.967 0.417 1.000 -ATOM 4419 H2 TIP3 4863 15.510 -9.719 -0.109 0.417 1.000 -ATOM 4420 OH2 TIP3 4866 9.012 -18.103 13.656 -0.834 1.520 -ATOM 4421 H1 TIP3 4866 9.902 -17.834 13.886 0.417 1.000 -ATOM 4422 H2 TIP3 4866 8.536 -17.314 13.821 0.417 1.000 -ATOM 4423 OH2 TIP3 4872 18.466 3.022 -19.640 -0.834 1.520 -ATOM 4424 H1 TIP3 4872 17.949 3.849 -19.687 0.417 1.000 -ATOM 4425 H2 TIP3 4872 17.859 2.522 -19.124 0.417 1.000 -ATOM 4426 OH2 TIP3 4875 12.252 -16.879 -14.270 -0.834 1.520 -ATOM 4427 H1 TIP3 4875 12.352 -17.136 -13.354 0.417 1.000 -ATOM 4428 H2 TIP3 4875 12.769 -17.581 -14.725 0.417 1.000 -ATOM 4429 OH2 TIP3 4880 15.164 -15.557 6.230 -0.834 1.520 -ATOM 4430 H1 TIP3 4880 15.428 -15.364 5.315 0.417 1.000 -ATOM 4431 H2 TIP3 4880 15.256 -16.516 6.288 0.417 1.000 -ATOM 4432 OH2 TIP3 4881 6.908 -3.729 18.788 -0.834 1.520 -ATOM 4433 H1 TIP3 4881 7.561 -4.201 19.350 0.417 1.000 -ATOM 4434 H2 TIP3 4881 7.116 -4.132 17.910 0.417 1.000 -ATOM 4435 OH2 TIP3 4887 3.580 -16.606 16.850 -0.834 1.520 -ATOM 4436 H1 TIP3 4887 4.442 -17.005 16.956 0.417 1.000 -ATOM 4437 H2 TIP3 4887 3.076 -17.309 16.339 0.417 1.000 -ATOM 4438 OH2 TIP3 4893 19.063 -5.903 -9.481 -0.834 1.520 -ATOM 4439 H1 TIP3 4893 18.356 -5.539 -10.039 0.417 1.000 -ATOM 4440 H2 TIP3 4893 18.874 -5.575 -8.584 0.417 1.000 -ATOM 4441 OH2 TIP3 4896 17.541 -12.996 -2.630 -0.834 1.520 -ATOM 4442 H1 TIP3 4896 17.467 -14.000 -2.570 0.417 1.000 -ATOM 4443 H2 TIP3 4896 16.717 -12.816 -3.094 0.417 1.000 -ATOM 4444 OH2 TIP3 4897 14.708 -10.140 -12.260 -0.834 1.520 -ATOM 4445 H1 TIP3 4897 14.416 -11.033 -12.177 0.417 1.000 -ATOM 4446 H2 TIP3 4897 14.188 -9.835 -12.999 0.417 1.000 -ATOM 4447 OH2 TIP3 4899 6.984 -12.999 -3.420 -0.834 1.520 -ATOM 4448 H1 TIP3 4899 7.702 -13.663 -3.242 0.417 1.000 -ATOM 4449 H2 TIP3 4899 6.454 -12.952 -2.596 0.417 1.000 -ATOM 4450 OH2 TIP3 4902 15.760 -1.047 12.086 -0.834 1.520 -ATOM 4451 H1 TIP3 4902 15.409 -1.089 12.967 0.417 1.000 -ATOM 4452 H2 TIP3 4902 16.073 -1.910 11.954 0.417 1.000 -ATOM 4453 OH2 TIP3 4903 10.925 -12.071 13.169 -0.834 1.520 -ATOM 4454 H1 TIP3 4903 11.834 -12.025 12.689 0.417 1.000 -ATOM 4455 H2 TIP3 4903 10.892 -13.033 13.389 0.417 1.000 -ATOM 4456 OH2 TIP3 4908 11.306 -9.511 17.031 -0.834 1.520 -ATOM 4457 H1 TIP3 4908 11.699 -10.124 17.656 0.417 1.000 -ATOM 4458 H2 TIP3 4908 11.748 -9.807 16.200 0.417 1.000 -ATOM 4459 OH2 TIP3 4915 13.152 -18.032 -11.724 -0.834 1.520 -ATOM 4460 H1 TIP3 4915 12.689 -18.766 -12.103 0.417 1.000 -ATOM 4461 H2 TIP3 4915 13.804 -18.441 -11.091 0.417 1.000 -ATOM 4462 OH2 TIP3 4916 7.810 -6.090 -15.817 -0.834 1.520 -ATOM 4463 H1 TIP3 4916 6.862 -6.324 -15.942 0.417 1.000 -ATOM 4464 H2 TIP3 4916 7.831 -5.361 -15.195 0.417 1.000 -ATOM 4465 OH2 TIP3 4920 15.784 8.837 11.326 -0.834 1.520 -ATOM 4466 H1 TIP3 4920 15.880 8.813 12.330 0.417 1.000 -ATOM 4467 H2 TIP3 4920 16.712 8.805 11.078 0.417 1.000 -ATOM 4468 OH2 TIP3 4922 9.133 -3.754 -7.115 -0.834 1.520 -ATOM 4469 H1 TIP3 4922 9.997 -3.574 -6.746 0.417 1.000 -ATOM 4470 H2 TIP3 4922 8.558 -3.181 -6.645 0.417 1.000 -ATOM 4471 OH2 TIP3 4924 14.087 -16.808 -4.614 -0.834 1.520 -ATOM 4472 H1 TIP3 4924 14.562 -16.864 -5.446 0.417 1.000 -ATOM 4473 H2 TIP3 4924 13.131 -16.814 -4.979 0.417 1.000 -ATOM 4474 OH2 TIP3 4927 12.132 -15.237 16.788 -0.834 1.520 -ATOM 4475 H1 TIP3 4927 12.463 -15.616 17.615 0.417 1.000 -ATOM 4476 H2 TIP3 4927 12.851 -14.679 16.463 0.417 1.000 -ATOM 4477 OH2 TIP3 4936 16.482 -2.803 -11.567 -0.834 1.520 -ATOM 4478 H1 TIP3 4936 16.006 -3.568 -11.905 0.417 1.000 -ATOM 4479 H2 TIP3 4936 17.417 -2.974 -11.853 0.417 1.000 -ATOM 4480 OH2 TIP3 4937 5.885 -16.784 -16.798 -0.834 1.520 -ATOM 4481 H1 TIP3 4937 5.219 -17.371 -16.331 0.417 1.000 -ATOM 4482 H2 TIP3 4937 6.368 -16.371 -16.085 0.417 1.000 -ATOM 4483 OH2 TIP3 4941 8.290 -13.344 7.868 -0.834 1.520 -ATOM 4484 H1 TIP3 4941 8.905 -14.035 7.575 0.417 1.000 -ATOM 4485 H2 TIP3 4941 8.550 -12.608 7.268 0.417 1.000 -ATOM 4486 OH2 TIP3 4942 14.994 -12.738 -6.980 -0.834 1.520 -ATOM 4487 H1 TIP3 4942 14.847 -13.672 -6.988 0.417 1.000 -ATOM 4488 H2 TIP3 4942 14.197 -12.325 -6.627 0.417 1.000 -ATOM 4489 OH2 TIP3 4944 6.220 -3.865 7.306 -0.834 1.520 -ATOM 4490 H1 TIP3 4944 5.697 -3.604 6.557 0.417 1.000 -ATOM 4491 H2 TIP3 4944 5.783 -4.714 7.521 0.417 1.000 -ATOM 4492 OH2 TIP3 4945 8.104 -4.320 11.702 -0.834 1.520 -ATOM 4493 H1 TIP3 4945 8.381 -5.232 11.799 0.417 1.000 -ATOM 4494 H2 TIP3 4945 8.618 -3.820 12.297 0.417 1.000 -ATOM 4495 OH2 TIP3 4946 10.007 4.900 6.483 -0.834 1.520 -ATOM 4496 H1 TIP3 4946 9.793 5.366 7.313 0.417 1.000 -ATOM 4497 H2 TIP3 4946 9.198 5.090 5.945 0.417 1.000 -ATOM 4498 OH2 TIP3 4957 17.926 -7.773 -11.989 -0.834 1.520 -ATOM 4499 H1 TIP3 4957 17.544 -7.514 -11.160 0.417 1.000 -ATOM 4500 H2 TIP3 4957 17.780 -8.743 -12.062 0.417 1.000 -ATOM 4501 OH2 TIP3 4961 5.085 -6.609 11.613 -0.834 1.520 -ATOM 4502 H1 TIP3 4961 5.873 -6.654 12.261 0.417 1.000 -ATOM 4503 H2 TIP3 4961 4.631 -5.785 11.857 0.417 1.000 -ATOM 4504 OH2 TIP3 4963 7.297 -8.112 -2.289 -0.834 1.520 -ATOM 4505 H1 TIP3 4963 6.465 -7.570 -1.982 0.417 1.000 -ATOM 4506 H2 TIP3 4963 7.970 -7.402 -2.304 0.417 1.000 -ATOM 4507 OH2 TIP3 4965 19.289 2.791 -3.905 -0.834 1.520 -ATOM 4508 H1 TIP3 4965 19.949 3.383 -4.380 0.417 1.000 -ATOM 4509 H2 TIP3 4965 18.789 2.404 -4.631 0.417 1.000 -ATOM 4510 OH2 TIP3 4966 18.443 -8.035 13.988 -0.834 1.520 -ATOM 4511 H1 TIP3 4966 19.321 -7.601 14.211 0.417 1.000 -ATOM 4512 H2 TIP3 4966 18.386 -8.648 14.744 0.417 1.000 -ATOM 4513 OH2 TIP3 4978 4.570 0.269 1.544 -0.834 1.520 -ATOM 4514 H1 TIP3 4978 3.726 -0.140 1.727 0.417 1.000 -ATOM 4515 H2 TIP3 4978 4.781 -0.075 0.650 0.417 1.000 -ATOM 4516 OH2 TIP3 4979 13.989 10.080 2.223 -0.834 1.520 -ATOM 4517 H1 TIP3 4979 13.320 10.750 2.434 0.417 1.000 -ATOM 4518 H2 TIP3 4979 13.808 9.315 2.785 0.417 1.000 -ATOM 4519 OH2 TIP3 4980 12.368 -11.230 -19.060 -0.834 1.520 -ATOM 4520 H1 TIP3 4980 11.494 -10.971 -18.862 0.417 1.000 -ATOM 4521 H2 TIP3 4980 12.306 -11.907 -19.814 0.417 1.000 -ATOM 4522 OH2 TIP3 4981 0.993 -3.463 -4.159 -0.834 1.520 -ATOM 4523 H1 TIP3 4981 0.642 -4.363 -4.444 0.417 1.000 -ATOM 4524 H2 TIP3 4981 0.414 -2.868 -4.691 0.417 1.000 -ATOM 4525 OH2 TIP3 4982 10.789 4.157 -7.751 -0.834 1.520 -ATOM 4526 H1 TIP3 4982 10.760 4.783 -6.986 0.417 1.000 -ATOM 4527 H2 TIP3 4982 11.472 3.574 -7.415 0.417 1.000 -ATOM 4528 OH2 TIP3 4983 8.327 -3.150 -0.984 -0.834 1.520 -ATOM 4529 H1 TIP3 4983 8.182 -3.978 -0.387 0.417 1.000 -ATOM 4530 H2 TIP3 4983 8.722 -2.509 -0.412 0.417 1.000 -ATOM 4531 OH2 TIP3 4986 9.388 -6.781 12.244 -0.834 1.520 -ATOM 4532 H1 TIP3 4986 10.345 -6.708 12.433 0.417 1.000 -ATOM 4533 H2 TIP3 4986 9.289 -7.679 11.965 0.417 1.000 -ATOM 4534 OH2 TIP3 4988 18.167 -8.265 7.717 -0.834 1.520 -ATOM 4535 H1 TIP3 4988 17.581 -7.550 7.473 0.417 1.000 -ATOM 4536 H2 TIP3 4988 18.911 -8.189 7.124 0.417 1.000 -ATOM 4537 OH2 TIP3 4993 17.076 -7.771 11.236 -0.834 1.520 -ATOM 4538 H1 TIP3 4993 16.652 -7.228 10.558 0.417 1.000 -ATOM 4539 H2 TIP3 4993 17.875 -7.396 11.525 0.417 1.000 -ATOM 4540 OH2 TIP3 4998 18.949 9.719 -19.076 -0.834 1.520 -ATOM 4541 H1 TIP3 4998 19.477 9.290 -19.783 0.417 1.000 -ATOM 4542 H2 TIP3 4998 19.699 10.048 -18.388 0.417 1.000 -ATOM 4543 OH2 TIP3 4999 7.726 5.191 -3.601 -0.834 1.520 -ATOM 4544 H1 TIP3 4999 8.178 5.298 -2.718 0.417 1.000 -ATOM 4545 H2 TIP3 4999 8.294 4.579 -4.079 0.417 1.000 -ATOM 4546 OH2 TIP3 5000 15.828 5.902 -3.040 -0.834 1.520 -ATOM 4547 H1 TIP3 5000 16.702 5.575 -2.835 0.417 1.000 -ATOM 4548 H2 TIP3 5000 15.627 5.529 -3.991 0.417 1.000 -ATOM 4549 OH2 TIP3 5001 12.344 1.914 -4.634 -0.834 1.520 -ATOM 4550 H1 TIP3 5001 13.019 2.333 -4.142 0.417 1.000 -ATOM 4551 H2 TIP3 5001 12.552 2.120 -5.547 0.417 1.000 -ATOM 4552 OH2 TIP3 5003 17.884 2.121 7.196 -0.834 1.520 -ATOM 4553 H1 TIP3 5003 17.038 2.303 7.639 0.417 1.000 -ATOM 4554 H2 TIP3 5003 18.336 3.004 7.246 0.417 1.000 -ATOM 4555 OH2 TIP3 5005 13.251 -0.783 -6.277 -0.834 1.520 -ATOM 4556 H1 TIP3 5005 14.032 -1.407 -6.444 0.417 1.000 -ATOM 4557 H2 TIP3 5005 13.686 0.092 -6.254 0.417 1.000 -ATOM 4558 OH2 TIP3 5006 9.338 -2.691 6.203 -0.834 1.520 -ATOM 4559 H1 TIP3 5006 8.488 -2.614 6.493 0.417 1.000 -ATOM 4560 H2 TIP3 5006 9.794 -1.905 6.527 0.417 1.000 -ATOM 4561 OH2 TIP3 5007 15.647 -8.204 4.938 -0.834 1.520 -ATOM 4562 H1 TIP3 5007 16.395 -7.719 4.692 0.417 1.000 -ATOM 4563 H2 TIP3 5007 15.193 -7.517 5.556 0.417 1.000 -ATOM 4564 OH2 TIP3 5009 8.335 -4.521 2.753 -0.834 1.520 -ATOM 4565 H1 TIP3 5009 8.907 -3.963 3.229 0.417 1.000 -ATOM 4566 H2 TIP3 5009 8.670 -5.410 2.894 0.417 1.000 -ATOM 4567 OH2 TIP3 5021 15.370 11.305 -10.968 -0.834 1.520 -ATOM 4568 H1 TIP3 5021 15.419 10.340 -11.090 0.417 1.000 -ATOM 4569 H2 TIP3 5021 14.481 11.418 -10.629 0.417 1.000 -ATOM 4570 OH2 TIP3 5023 13.717 9.411 -12.949 -0.834 1.520 -ATOM 4571 H1 TIP3 5023 13.171 9.886 -13.598 0.417 1.000 -ATOM 4572 H2 TIP3 5023 14.515 9.289 -13.485 0.417 1.000 -ATOM 4573 OH2 TIP3 5024 13.592 8.925 15.367 -0.834 1.520 -ATOM 4574 H1 TIP3 5024 13.688 9.032 16.297 0.417 1.000 -ATOM 4575 H2 TIP3 5024 13.902 8.036 15.148 0.417 1.000 -ATOM 4576 OH2 TIP3 5025 4.093 8.900 -1.456 -0.834 1.520 -ATOM 4577 H1 TIP3 5025 3.326 9.488 -1.234 0.417 1.000 -ATOM 4578 H2 TIP3 5025 4.228 8.394 -0.588 0.417 1.000 -ATOM 4579 OH2 TIP3 5027 14.817 8.039 8.515 -0.834 1.520 -ATOM 4580 H1 TIP3 5027 14.697 8.968 8.241 0.417 1.000 -ATOM 4581 H2 TIP3 5027 15.366 8.109 9.312 0.417 1.000 -ATOM 4582 OH2 TIP3 5028 9.347 13.879 17.349 -0.834 1.520 -ATOM 4583 H1 TIP3 5028 9.080 14.658 17.778 0.417 1.000 -ATOM 4584 H2 TIP3 5028 9.829 14.268 16.598 0.417 1.000 -ATOM 4585 OH2 TIP3 5029 13.402 12.231 17.747 -0.834 1.520 -ATOM 4586 H1 TIP3 5029 14.266 12.607 18.005 0.417 1.000 -ATOM 4587 H2 TIP3 5029 13.539 12.199 16.755 0.417 1.000 -ATOM 4588 OH2 TIP3 5043 8.719 10.906 -8.479 -0.834 1.520 -ATOM 4589 H1 TIP3 5043 8.395 11.187 -7.588 0.417 1.000 -ATOM 4590 H2 TIP3 5043 9.590 11.280 -8.626 0.417 1.000 -ATOM 4591 OH2 TIP3 5044 11.408 7.285 -10.340 -0.834 1.520 -ATOM 4592 H1 TIP3 5044 11.908 6.745 -9.809 0.417 1.000 -ATOM 4593 H2 TIP3 5044 10.631 7.638 -9.829 0.417 1.000 -ATOM 4594 OH2 TIP3 5046 6.889 8.990 2.856 -0.834 1.520 -ATOM 4595 H1 TIP3 5046 7.254 9.757 3.253 0.417 1.000 -ATOM 4596 H2 TIP3 5046 7.221 8.318 3.456 0.417 1.000 -ATOM 4597 OH2 TIP3 5047 19.227 2.722 17.313 -0.834 1.520 -ATOM 4598 H1 TIP3 5047 18.720 1.889 17.635 0.417 1.000 -ATOM 4599 H2 TIP3 5047 18.931 3.438 17.940 0.417 1.000 -ATOM 4600 OH2 TIP3 5048 16.055 3.112 19.410 -0.834 1.520 -ATOM 4601 H1 TIP3 5048 15.615 3.280 18.585 0.417 1.000 -ATOM 4602 H2 TIP3 5048 17.001 3.373 19.291 0.417 1.000 -ATOM 4603 OH2 TIP3 5049 16.051 11.403 -3.424 -0.834 1.520 -ATOM 4604 H1 TIP3 5049 16.273 11.416 -4.349 0.417 1.000 -ATOM 4605 H2 TIP3 5049 16.095 10.464 -3.224 0.417 1.000 -ATOM 4606 OH2 TIP3 5061 15.796 2.236 -10.640 -0.834 1.520 -ATOM 4607 H1 TIP3 5061 15.374 2.018 -11.509 0.417 1.000 -ATOM 4608 H2 TIP3 5061 16.534 2.827 -10.902 0.417 1.000 -ATOM 4609 OH2 TIP3 5064 14.936 17.763 -11.514 -0.834 1.520 -ATOM 4610 H1 TIP3 5064 14.177 17.204 -11.674 0.417 1.000 -ATOM 4611 H2 TIP3 5064 15.428 17.293 -10.802 0.417 1.000 -ATOM 4612 OH2 TIP3 5068 15.022 15.199 -6.902 -0.834 1.520 -ATOM 4613 H1 TIP3 5068 14.280 14.568 -7.107 0.417 1.000 -ATOM 4614 H2 TIP3 5068 15.067 15.282 -5.904 0.417 1.000 -ATOM 4615 OH2 TIP3 5075 13.456 12.771 14.985 -0.834 1.520 -ATOM 4616 H1 TIP3 5075 14.249 13.023 14.552 0.417 1.000 -ATOM 4617 H2 TIP3 5075 13.004 13.597 15.189 0.417 1.000 -ATOM 4618 OH2 TIP3 5087 18.535 18.225 5.801 -0.834 1.520 -ATOM 4619 H1 TIP3 5087 17.831 18.919 5.666 0.417 1.000 -ATOM 4620 H2 TIP3 5087 18.496 17.617 5.062 0.417 1.000 -ATOM 4621 OH2 TIP3 5088 11.866 5.965 -0.276 -0.834 1.520 -ATOM 4622 H1 TIP3 5088 12.546 5.327 -0.078 0.417 1.000 -ATOM 4623 H2 TIP3 5088 11.891 6.600 0.377 0.417 1.000 -ATOM 4624 OH2 TIP3 5089 11.223 19.196 10.003 -0.834 1.520 -ATOM 4625 H1 TIP3 5089 11.656 19.268 10.849 0.417 1.000 -ATOM 4626 H2 TIP3 5089 10.442 18.601 10.189 0.417 1.000 -ATOM 4627 OH2 TIP3 5093 12.994 15.909 3.631 -0.834 1.520 -ATOM 4628 H1 TIP3 5093 12.468 16.675 3.756 0.417 1.000 -ATOM 4629 H2 TIP3 5093 12.508 15.300 4.092 0.417 1.000 -ATOM 4630 OH2 TIP3 5098 5.320 2.189 15.296 -0.834 1.520 -ATOM 4631 H1 TIP3 5098 4.510 2.651 15.054 0.417 1.000 -ATOM 4632 H2 TIP3 5098 5.992 2.848 15.086 0.417 1.000 -ATOM 4633 OH2 TIP3 5106 14.747 15.091 -4.128 -0.834 1.520 -ATOM 4634 H1 TIP3 5106 13.802 15.371 -3.863 0.417 1.000 -ATOM 4635 H2 TIP3 5106 15.027 14.529 -3.414 0.417 1.000 -ATOM 4636 OH2 TIP3 5115 7.081 10.869 15.522 -0.834 1.520 -ATOM 4637 H1 TIP3 5115 7.940 10.969 15.073 0.417 1.000 -ATOM 4638 H2 TIP3 5115 7.069 10.065 15.990 0.417 1.000 -ATOM 4639 OH2 TIP3 5117 18.195 13.937 2.979 -0.834 1.520 -ATOM 4640 H1 TIP3 5117 19.057 13.521 2.760 0.417 1.000 -ATOM 4641 H2 TIP3 5117 18.395 14.887 3.058 0.417 1.000 -ATOM 4642 OH2 TIP3 5125 18.369 13.410 7.513 -0.834 1.520 -ATOM 4643 H1 TIP3 5125 19.192 13.302 6.954 0.417 1.000 -ATOM 4644 H2 TIP3 5125 18.414 14.305 7.918 0.417 1.000 -ATOM 4645 OH2 TIP3 5127 10.081 17.085 -10.702 -0.834 1.520 -ATOM 4646 H1 TIP3 5127 9.579 17.884 -10.372 0.417 1.000 -ATOM 4647 H2 TIP3 5127 9.330 16.618 -11.111 0.417 1.000 -ATOM 4648 OH2 TIP3 5133 6.160 10.788 -5.788 -0.834 1.520 -ATOM 4649 H1 TIP3 5133 6.076 10.109 -5.087 0.417 1.000 -ATOM 4650 H2 TIP3 5133 6.406 10.281 -6.565 0.417 1.000 -ATOM 4651 OH2 TIP3 5164 14.212 8.724 -5.348 -0.834 1.520 -ATOM 4652 H1 TIP3 5164 15.073 8.458 -5.841 0.417 1.000 -ATOM 4653 H2 TIP3 5164 13.910 9.428 -5.910 0.417 1.000 -ATOM 4654 OH2 TIP3 5165 12.937 19.219 -9.628 -0.834 1.520 -ATOM 4655 H1 TIP3 5165 12.903 18.243 -9.731 0.417 1.000 -ATOM 4656 H2 TIP3 5165 13.607 19.380 -8.943 0.417 1.000 -ATOM 4657 OH2 TIP3 5195 14.264 5.494 7.481 -0.834 1.520 -ATOM 4658 H1 TIP3 5195 14.316 6.376 7.834 0.417 1.000 -ATOM 4659 H2 TIP3 5195 15.178 5.206 7.322 0.417 1.000 -ATOM 4660 OH2 TIP3 5234 7.070 -17.015 -5.288 -0.834 1.520 -ATOM 4661 H1 TIP3 5234 7.044 -16.425 -6.080 0.417 1.000 -ATOM 4662 H2 TIP3 5234 7.302 -17.929 -5.602 0.417 1.000 -ATOM 4663 OH2 TIP3 5251 9.248 -4.914 -17.871 -0.834 1.520 -ATOM 4664 H1 TIP3 5251 8.830 -5.681 -17.466 0.417 1.000 -ATOM 4665 H2 TIP3 5251 9.093 -4.167 -17.226 0.417 1.000 -ATOM 4666 OH2 TIP3 5260 15.782 -18.766 -0.276 -0.834 1.520 -ATOM 4667 H1 TIP3 5260 16.295 -17.968 0.016 0.417 1.000 -ATOM 4668 H2 TIP3 5260 14.976 -18.442 -0.801 0.417 1.000 -ATOM 4669 OH2 TIP3 5267 5.592 -14.400 18.398 -0.834 1.520 -ATOM 4670 H1 TIP3 5267 6.554 -14.388 18.622 0.417 1.000 -ATOM 4671 H2 TIP3 5267 5.611 -14.914 17.533 0.417 1.000 -ATOM 4672 OH2 TIP3 5272 16.512 -12.638 -14.642 -0.834 1.520 -ATOM 4673 H1 TIP3 5272 17.156 -12.776 -15.412 0.417 1.000 -ATOM 4674 H2 TIP3 5272 16.664 -13.354 -14.037 0.417 1.000 -ATOM 4675 OH2 TIP3 5302 16.233 -13.190 7.692 -0.834 1.520 -ATOM 4676 H1 TIP3 5302 16.788 -13.086 6.952 0.417 1.000 -ATOM 4677 H2 TIP3 5302 15.588 -12.445 7.567 0.417 1.000 -ATOM 4678 OH2 TIP3 5317 14.299 -12.929 -18.042 -0.834 1.520 -ATOM 4679 H1 TIP3 5317 13.774 -13.479 -17.515 0.417 1.000 -ATOM 4680 H2 TIP3 5317 13.798 -12.145 -18.284 0.417 1.000 -ATOM 4681 OH2 TIP3 5318 16.674 -10.069 -1.764 -0.834 1.520 -ATOM 4682 H1 TIP3 5318 16.138 -10.904 -1.806 0.417 1.000 -ATOM 4683 H2 TIP3 5318 16.354 -9.497 -2.518 0.417 1.000 -ATOM 4684 OH2 TIP3 5319 13.503 -18.835 -15.677 -0.834 1.520 -ATOM 4685 H1 TIP3 5319 12.690 -19.285 -15.951 0.417 1.000 -ATOM 4686 H2 TIP3 5319 14.005 -19.019 -16.487 0.417 1.000 -ATOM 4687 OH2 TIP3 5320 -2.725 -9.990 -1.303 -0.834 1.520 -ATOM 4688 H1 TIP3 5320 -2.106 -10.416 -1.906 0.417 1.000 -ATOM 4689 H2 TIP3 5320 -3.508 -10.528 -1.340 0.417 1.000 -ATOM 4690 OH2 TIP3 5323 8.656 -13.880 4.596 -0.834 1.520 -ATOM 4691 H1 TIP3 5323 9.522 -13.819 4.203 0.417 1.000 -ATOM 4692 H2 TIP3 5323 8.851 -14.185 5.493 0.417 1.000 -ATOM 4693 OH2 TIP3 5341 0.606 -6.048 -5.389 -0.834 1.520 -ATOM 4694 H1 TIP3 5341 0.573 -6.455 -4.500 0.417 1.000 -ATOM 4695 H2 TIP3 5341 0.964 -6.827 -5.957 0.417 1.000 -ATOM 4696 OH2 TIP3 5343 12.398 -8.093 7.573 -0.834 1.520 -ATOM 4697 H1 TIP3 5343 12.054 -8.864 8.119 0.417 1.000 -ATOM 4698 H2 TIP3 5343 11.596 -7.736 7.295 0.417 1.000 -ATOM 4699 OH2 TIP3 5355 7.127 -19.591 -17.384 -0.834 1.520 -ATOM 4700 H1 TIP3 5355 6.234 -19.768 -17.558 0.417 1.000 -ATOM 4701 H2 TIP3 5355 7.331 -18.758 -17.819 0.417 1.000 -ATOM 4702 OH2 TIP3 5356 1.148 -17.212 -15.264 -0.834 1.520 -ATOM 4703 H1 TIP3 5356 1.231 -16.486 -14.719 0.417 1.000 -ATOM 4704 H2 TIP3 5356 2.035 -17.255 -15.702 0.417 1.000 -ATOM 4705 OH2 TIP3 5358 11.374 0.383 -14.397 -0.834 1.520 -ATOM 4706 H1 TIP3 5358 10.606 0.894 -14.264 0.417 1.000 -ATOM 4707 H2 TIP3 5358 11.018 -0.304 -15.045 0.417 1.000 -ATOM 4708 OH2 TIP3 5360 14.296 -11.536 -9.788 -0.834 1.520 -ATOM 4709 H1 TIP3 5360 13.560 -11.925 -10.346 0.417 1.000 -ATOM 4710 H2 TIP3 5360 14.266 -12.091 -8.966 0.417 1.000 -ATOM 4711 OH2 TIP3 5364 8.474 1.819 -1.619 -0.834 1.520 -ATOM 4712 H1 TIP3 5364 9.448 2.091 -1.431 0.417 1.000 -ATOM 4713 H2 TIP3 5364 8.268 1.210 -0.894 0.417 1.000 -ATOM 4714 OH2 TIP3 5365 14.100 -11.342 7.382 -0.834 1.520 -ATOM 4715 H1 TIP3 5365 14.415 -10.569 6.920 0.417 1.000 -ATOM 4716 H2 TIP3 5365 13.394 -11.030 7.979 0.417 1.000 -ATOM 4717 OH2 TIP3 5366 4.747 -17.126 3.859 -0.834 1.520 -ATOM 4718 H1 TIP3 5366 5.471 -16.512 3.596 0.417 1.000 -ATOM 4719 H2 TIP3 5366 5.220 -17.923 4.213 0.417 1.000 -ATOM 4720 OH2 TIP3 5369 10.185 -15.314 6.606 -0.834 1.520 -ATOM 4721 H1 TIP3 5369 10.174 -16.257 6.251 0.417 1.000 -ATOM 4722 H2 TIP3 5369 11.134 -15.158 6.778 0.417 1.000 -ATOM 4723 OH2 TIP3 5370 14.602 0.297 17.848 -0.834 1.520 -ATOM 4724 H1 TIP3 5370 14.040 -0.269 17.290 0.417 1.000 -ATOM 4725 H2 TIP3 5370 15.219 -0.394 18.269 0.417 1.000 -ATOM 4726 OH2 TIP3 5378 9.237 -7.661 -9.299 -0.834 1.520 -ATOM 4727 H1 TIP3 5378 9.431 -6.727 -9.322 0.417 1.000 -ATOM 4728 H2 TIP3 5378 10.103 -8.052 -9.119 0.417 1.000 -ATOM 4729 OH2 TIP3 5380 19.043 0.480 -15.906 -0.834 1.520 -ATOM 4730 H1 TIP3 5380 19.347 -0.428 -15.843 0.417 1.000 -ATOM 4731 H2 TIP3 5380 19.763 0.868 -16.339 0.417 1.000 -ATOM 4732 OH2 TIP3 5381 12.704 10.573 -18.808 -0.834 1.520 -ATOM 4733 H1 TIP3 5381 12.141 10.374 -19.588 0.417 1.000 -ATOM 4734 H2 TIP3 5381 12.294 11.463 -18.495 0.417 1.000 -ATOM 4735 OH2 TIP3 5384 15.575 -11.671 -4.060 -0.834 1.520 -ATOM 4736 H1 TIP3 5384 14.988 -12.150 -4.630 0.417 1.000 -ATOM 4737 H2 TIP3 5384 15.336 -10.762 -4.136 0.417 1.000 -ATOM 4738 OH2 TIP3 5385 3.796 -5.682 -4.344 -0.834 1.520 -ATOM 4739 H1 TIP3 5385 4.661 -5.967 -4.718 0.417 1.000 -ATOM 4740 H2 TIP3 5385 3.317 -6.505 -4.204 0.417 1.000 -ATOM 4741 OH2 TIP3 5393 4.111 2.000 -13.574 -0.834 1.520 -ATOM 4742 H1 TIP3 5393 3.832 2.636 -12.908 0.417 1.000 -ATOM 4743 H2 TIP3 5393 3.879 2.428 -14.467 0.417 1.000 -ATOM 4744 OH2 TIP3 5396 13.185 -9.125 -14.505 -0.834 1.520 -ATOM 4745 H1 TIP3 5396 12.568 -8.575 -13.964 0.417 1.000 -ATOM 4746 H2 TIP3 5396 12.538 -9.411 -15.227 0.417 1.000 -ATOM 4747 OH2 TIP3 5400 14.596 -2.476 -3.442 -0.834 1.520 -ATOM 4748 H1 TIP3 5400 14.209 -1.722 -3.033 0.417 1.000 -ATOM 4749 H2 TIP3 5400 14.831 -2.220 -4.363 0.417 1.000 -ATOM 4750 OH2 TIP3 5401 11.944 2.445 7.176 -0.834 1.520 -ATOM 4751 H1 TIP3 5401 11.738 3.383 7.005 0.417 1.000 -ATOM 4752 H2 TIP3 5401 11.566 1.938 6.435 0.417 1.000 -ATOM 4753 OH2 TIP3 5403 8.367 -11.027 6.187 -0.834 1.520 -ATOM 4754 H1 TIP3 5403 8.718 -10.131 6.098 0.417 1.000 -ATOM 4755 H2 TIP3 5403 8.562 -11.490 5.346 0.417 1.000 -ATOM 4756 OH2 TIP3 5404 6.690 -6.853 -10.123 -0.834 1.520 -ATOM 4757 H1 TIP3 5404 7.483 -7.422 -9.872 0.417 1.000 -ATOM 4758 H2 TIP3 5404 6.446 -6.469 -9.181 0.417 1.000 -ATOM 4759 OH2 TIP3 5406 11.389 -16.853 14.614 -0.834 1.520 -ATOM 4760 H1 TIP3 5406 11.689 -16.497 15.506 0.417 1.000 -ATOM 4761 H2 TIP3 5406 11.586 -16.125 13.966 0.417 1.000 -ATOM 4762 OH2 TIP3 5408 18.703 5.587 10.663 -0.834 1.520 -ATOM 4763 H1 TIP3 5408 18.843 6.362 11.336 0.417 1.000 -ATOM 4764 H2 TIP3 5408 19.098 4.769 11.070 0.417 1.000 -ATOM 4765 OH2 TIP3 5409 7.434 5.012 12.576 -0.834 1.520 -ATOM 4766 H1 TIP3 5409 7.156 5.482 13.389 0.417 1.000 -ATOM 4767 H2 TIP3 5409 7.941 5.705 12.091 0.417 1.000 -ATOM 4768 OH2 TIP3 5410 14.092 -10.907 17.180 -0.834 1.520 -ATOM 4769 H1 TIP3 5410 13.629 -10.783 16.383 0.417 1.000 -ATOM 4770 H2 TIP3 5410 14.906 -10.408 17.069 0.417 1.000 -ATOM 4771 OH2 TIP3 5418 6.978 4.748 -15.229 -0.834 1.520 -ATOM 4772 H1 TIP3 5418 7.752 5.332 -15.017 0.417 1.000 -ATOM 4773 H2 TIP3 5418 6.598 5.191 -15.955 0.417 1.000 -ATOM 4774 OH2 TIP3 5421 -19.208 8.251 -2.977 -0.834 1.520 -ATOM 4775 H1 TIP3 5421 -19.033 8.811 -3.808 0.417 1.000 -ATOM 4776 H2 TIP3 5421 -19.678 7.534 -3.339 0.417 1.000 -ATOM 4777 OH2 TIP3 5423 16.783 5.581 8.647 -0.834 1.520 -ATOM 4778 H1 TIP3 5423 17.154 6.118 7.942 0.417 1.000 -ATOM 4779 H2 TIP3 5423 17.451 5.726 9.351 0.417 1.000 -ATOM 4780 OH2 TIP3 5424 18.809 2.308 4.480 -0.834 1.520 -ATOM 4781 H1 TIP3 5424 18.892 3.167 4.977 0.417 1.000 -ATOM 4782 H2 TIP3 5424 17.869 2.017 4.797 0.417 1.000 -ATOM 4783 OH2 TIP3 5429 14.462 -4.027 14.451 -0.834 1.520 -ATOM 4784 H1 TIP3 5429 15.148 -3.401 14.534 0.417 1.000 -ATOM 4785 H2 TIP3 5429 14.480 -4.395 15.324 0.417 1.000 -ATOM 4786 OH2 TIP3 5430 11.900 -3.789 -3.199 -0.834 1.520 -ATOM 4787 H1 TIP3 5430 12.581 -3.277 -3.608 0.417 1.000 -ATOM 4788 H2 TIP3 5430 11.064 -3.277 -3.338 0.417 1.000 -ATOM 4789 OH2 TIP3 5440 14.485 -0.646 -12.162 -0.834 1.520 -ATOM 4790 H1 TIP3 5440 15.335 -1.131 -11.960 0.417 1.000 -ATOM 4791 H2 TIP3 5440 14.813 0.175 -12.584 0.417 1.000 -ATOM 4792 OH2 TIP3 5443 12.609 -9.258 -3.624 -0.834 1.520 -ATOM 4793 H1 TIP3 5443 11.791 -8.811 -3.825 0.417 1.000 -ATOM 4794 H2 TIP3 5443 12.237 -9.936 -2.981 0.417 1.000 -ATOM 4795 OH2 TIP3 5444 11.100 3.775 -10.543 -0.834 1.520 -ATOM 4796 H1 TIP3 5444 10.416 4.441 -10.781 0.417 1.000 -ATOM 4797 H2 TIP3 5444 10.933 3.615 -9.633 0.417 1.000 -ATOM 4798 OH2 TIP3 5445 11.210 12.340 -9.099 -0.834 1.520 -ATOM 4799 H1 TIP3 5445 11.732 11.533 -9.460 0.417 1.000 -ATOM 4800 H2 TIP3 5445 11.181 12.865 -9.901 0.417 1.000 -ATOM 4801 OH2 TIP3 5448 14.455 0.732 10.621 -0.834 1.520 -ATOM 4802 H1 TIP3 5448 14.754 0.073 11.257 0.417 1.000 -ATOM 4803 H2 TIP3 5448 14.486 0.203 9.747 0.417 1.000 -ATOM 4804 OH2 TIP3 5454 14.812 -8.573 13.499 -0.834 1.520 -ATOM 4805 H1 TIP3 5454 15.552 -8.093 13.151 0.417 1.000 -ATOM 4806 H2 TIP3 5454 14.951 -8.465 14.455 0.417 1.000 -ATOM 4807 OH2 TIP3 5455 9.007 4.256 16.647 -0.834 1.520 -ATOM 4808 H1 TIP3 5455 8.876 3.559 17.371 0.417 1.000 -ATOM 4809 H2 TIP3 5455 9.861 4.650 16.935 0.417 1.000 -ATOM 4810 OH2 TIP3 5456 12.228 10.627 13.602 -0.834 1.520 -ATOM 4811 H1 TIP3 5456 12.672 11.422 13.899 0.417 1.000 -ATOM 4812 H2 TIP3 5456 12.664 9.883 14.024 0.417 1.000 -ATOM 4813 OH2 TIP3 5462 9.361 6.115 -14.689 -0.834 1.520 -ATOM 4814 H1 TIP3 5462 10.188 5.555 -14.557 0.417 1.000 -ATOM 4815 H2 TIP3 5462 9.590 6.982 -14.224 0.417 1.000 -ATOM 4816 OH2 TIP3 5463 4.980 6.576 -8.654 -0.834 1.520 -ATOM 4817 H1 TIP3 5463 5.270 6.086 -7.833 0.417 1.000 -ATOM 4818 H2 TIP3 5463 4.047 6.280 -8.778 0.417 1.000 -ATOM 4819 OH2 TIP3 5466 12.725 -3.052 -12.017 -0.834 1.520 -ATOM 4820 H1 TIP3 5466 13.444 -3.698 -12.046 0.417 1.000 -ATOM 4821 H2 TIP3 5466 13.212 -2.192 -12.134 0.417 1.000 -ATOM 4822 OH2 TIP3 5468 17.093 11.448 3.705 -0.834 1.520 -ATOM 4823 H1 TIP3 5468 17.843 11.474 4.294 0.417 1.000 -ATOM 4824 H2 TIP3 5468 17.116 12.288 3.230 0.417 1.000 -ATOM 4825 OH2 TIP3 5470 5.477 1.060 12.510 -0.834 1.520 -ATOM 4826 H1 TIP3 5470 5.580 0.888 13.447 0.417 1.000 -ATOM 4827 H2 TIP3 5470 5.397 1.990 12.354 0.417 1.000 -ATOM 4828 OH2 TIP3 5472 1.772 0.721 13.296 -0.834 1.520 -ATOM 4829 H1 TIP3 5472 0.857 0.872 13.293 0.417 1.000 -ATOM 4830 H2 TIP3 5472 2.111 1.563 12.903 0.417 1.000 -ATOM 4831 OH2 TIP3 5473 10.150 -2.350 14.111 -0.834 1.520 -ATOM 4832 H1 TIP3 5473 10.498 -2.236 14.969 0.417 1.000 -ATOM 4833 H2 TIP3 5473 9.443 -1.642 14.097 0.417 1.000 -ATOM 4834 OH2 TIP3 5484 11.221 -0.513 -1.272 -0.834 1.520 -ATOM 4835 H1 TIP3 5484 10.595 -0.924 -0.698 0.417 1.000 -ATOM 4836 H2 TIP3 5484 11.999 -0.958 -1.025 0.417 1.000 -ATOM 4837 OH2 TIP3 5485 10.724 -2.726 3.501 -0.834 1.520 -ATOM 4838 H1 TIP3 5485 10.500 -2.364 4.425 0.417 1.000 -ATOM 4839 H2 TIP3 5485 11.702 -2.759 3.492 0.417 1.000 -ATOM 4840 OH2 TIP3 5489 11.882 10.956 5.165 -0.834 1.520 -ATOM 4841 H1 TIP3 5489 11.001 11.046 5.465 0.417 1.000 -ATOM 4842 H2 TIP3 5489 11.776 10.285 4.455 0.417 1.000 -ATOM 4843 OH2 TIP3 5490 13.347 6.042 12.170 -0.834 1.520 -ATOM 4844 H1 TIP3 5490 13.110 6.803 11.609 0.417 1.000 -ATOM 4845 H2 TIP3 5490 12.595 5.502 12.128 0.417 1.000 -ATOM 4846 OH2 TIP3 5505 12.381 9.281 -3.169 -0.834 1.520 -ATOM 4847 H1 TIP3 5505 11.517 8.803 -3.188 0.417 1.000 -ATOM 4848 H2 TIP3 5505 12.710 9.154 -4.038 0.417 1.000 -ATOM 4849 OH2 TIP3 5508 12.486 16.535 13.272 -0.834 1.520 -ATOM 4850 H1 TIP3 5508 13.209 16.329 13.871 0.417 1.000 -ATOM 4851 H2 TIP3 5508 12.769 16.183 12.425 0.417 1.000 -ATOM 4852 OH2 TIP3 5511 14.369 -7.349 18.864 -0.834 1.520 -ATOM 4853 H1 TIP3 5511 13.425 -7.553 18.748 0.417 1.000 -ATOM 4854 H2 TIP3 5511 14.443 -7.447 19.814 0.417 1.000 -ATOM 4855 OH2 TIP3 5514 14.950 3.794 11.426 -0.834 1.520 -ATOM 4856 H1 TIP3 5514 14.798 4.765 11.501 0.417 1.000 -ATOM 4857 H2 TIP3 5514 14.399 3.413 12.040 0.417 1.000 -ATOM 4858 OH2 TIP3 5522 19.036 14.614 -17.999 -0.834 1.520 -ATOM 4859 H1 TIP3 5522 19.729 13.928 -18.017 0.417 1.000 -ATOM 4860 H2 TIP3 5522 19.474 15.397 -17.626 0.417 1.000 -ATOM 4861 OH2 TIP3 5528 11.135 2.229 -1.321 -0.834 1.520 -ATOM 4862 H1 TIP3 5528 11.278 1.353 -1.767 0.417 1.000 -ATOM 4863 H2 TIP3 5528 12.011 2.599 -1.355 0.417 1.000 -ATOM 4864 OH2 TIP3 5530 12.170 19.039 1.156 -0.834 1.520 -ATOM 4865 H1 TIP3 5530 12.699 18.209 0.987 0.417 1.000 -ATOM 4866 H2 TIP3 5530 12.023 19.346 0.242 0.417 1.000 -ATOM 4867 OH2 TIP3 5531 15.862 14.515 5.077 -0.834 1.520 -ATOM 4868 H1 TIP3 5531 16.165 14.505 4.102 0.417 1.000 -ATOM 4869 H2 TIP3 5531 15.031 14.091 5.011 0.417 1.000 -ATOM 4870 OH2 TIP3 5537 14.539 10.511 9.425 -0.834 1.520 -ATOM 4871 H1 TIP3 5537 14.825 10.055 10.231 0.417 1.000 -ATOM 4872 H2 TIP3 5537 15.302 11.126 9.271 0.417 1.000 -ATOM 4873 OH2 TIP3 5545 9.835 15.598 -13.639 -0.834 1.520 -ATOM 4874 H1 TIP3 5545 9.391 16.405 -13.887 0.417 1.000 -ATOM 4875 H2 TIP3 5545 9.216 14.860 -13.933 0.417 1.000 -ATOM 4876 OH2 TIP3 5549 6.448 12.371 -0.027 -0.834 1.520 -ATOM 4877 H1 TIP3 5549 6.085 11.922 0.689 0.417 1.000 -ATOM 4878 H2 TIP3 5549 5.867 13.101 -0.215 0.417 1.000 -ATOM 4879 OH2 TIP3 5550 17.281 11.681 -5.760 -0.834 1.520 -ATOM 4880 H1 TIP3 5550 17.520 12.442 -6.341 0.417 1.000 -ATOM 4881 H2 TIP3 5550 17.940 11.105 -6.124 0.417 1.000 -ATOM 4882 OH2 TIP3 5551 19.291 12.022 -2.462 -0.834 1.520 -ATOM 4883 H1 TIP3 5551 19.395 11.139 -2.833 0.417 1.000 -ATOM 4884 H2 TIP3 5551 18.973 11.884 -1.530 0.417 1.000 -ATOM 4885 OH2 TIP3 5557 18.997 17.076 18.505 -0.834 1.520 -ATOM 4886 H1 TIP3 5557 19.159 16.530 17.701 0.417 1.000 -ATOM 4887 H2 TIP3 5557 18.170 16.717 18.937 0.417 1.000 -ATOM 4888 OH2 TIP3 5566 11.906 14.524 -11.130 -0.834 1.520 -ATOM 4889 H1 TIP3 5566 11.644 15.279 -10.636 0.417 1.000 -ATOM 4890 H2 TIP3 5566 12.499 14.976 -11.759 0.417 1.000 -ATOM 4891 OH2 TIP3 5570 16.934 17.142 3.738 -0.834 1.520 -ATOM 4892 H1 TIP3 5570 16.356 17.888 3.511 0.417 1.000 -ATOM 4893 H2 TIP3 5570 16.553 16.472 3.181 0.417 1.000 -ATOM 4894 OH2 TIP3 5575 8.382 13.106 5.620 -0.834 1.520 -ATOM 4895 H1 TIP3 5575 8.699 14.015 5.900 0.417 1.000 -ATOM 4896 H2 TIP3 5575 8.951 12.449 6.124 0.417 1.000 -ATOM 4897 OH2 TIP3 5607 10.069 15.308 -17.921 -0.834 1.520 -ATOM 4898 H1 TIP3 5607 10.483 15.292 -18.754 0.417 1.000 -ATOM 4899 H2 TIP3 5607 9.513 14.548 -17.868 0.417 1.000 -ATOM 4900 OH2 TIP3 5610 15.900 16.217 -9.230 -0.834 1.520 -ATOM 4901 H1 TIP3 5610 15.441 15.887 -8.458 0.417 1.000 -ATOM 4902 H2 TIP3 5610 15.819 15.482 -9.883 0.417 1.000 -ATOM 4903 OH2 TIP3 5613 19.591 16.397 2.036 -0.834 1.520 -ATOM 4904 H1 TIP3 5613 18.836 16.506 1.366 0.417 1.000 -ATOM 4905 H2 TIP3 5613 19.452 17.178 2.647 0.417 1.000 -ATOM 4906 OH2 TIP3 5669 18.511 -17.954 -14.452 -0.834 1.520 -ATOM 4907 H1 TIP3 5669 17.889 -17.419 -14.932 0.417 1.000 -ATOM 4908 H2 TIP3 5669 17.999 -18.232 -13.736 0.417 1.000 -ATOM 4909 OH2 TIP3 5676 17.038 -15.763 -9.630 -0.834 1.520 -ATOM 4910 H1 TIP3 5676 17.927 -15.462 -9.940 0.417 1.000 -ATOM 4911 H2 TIP3 5676 16.566 -14.950 -9.774 0.417 1.000 -ATOM 4912 OH2 TIP3 5690 9.290 -15.575 -7.608 -0.834 1.520 -ATOM 4913 H1 TIP3 5690 9.842 -15.903 -8.302 0.417 1.000 -ATOM 4914 H2 TIP3 5690 8.399 -15.987 -7.841 0.417 1.000 -ATOM 4915 OH2 TIP3 5710 15.432 -18.020 -9.677 -0.834 1.520 -ATOM 4916 H1 TIP3 5710 16.211 -17.449 -9.542 0.417 1.000 -ATOM 4917 H2 TIP3 5710 15.507 -18.652 -8.903 0.417 1.000 -ATOM 4918 OH2 TIP3 5713 19.421 -18.813 -3.561 -0.834 1.520 -ATOM 4919 H1 TIP3 5713 19.141 -18.504 -4.484 0.417 1.000 -ATOM 4920 H2 TIP3 5713 19.100 -18.072 -3.044 0.417 1.000 -ATOM 4921 OH2 TIP3 5719 16.797 -17.705 6.462 -0.834 1.520 -ATOM 4922 H1 TIP3 5719 16.744 -18.284 7.169 0.417 1.000 -ATOM 4923 H2 TIP3 5719 17.466 -18.102 5.855 0.417 1.000 -ATOM 4924 OH2 TIP3 5720 17.339 -13.758 0.208 -0.834 1.520 -ATOM 4925 H1 TIP3 5720 17.305 -12.855 -0.236 0.417 1.000 -ATOM 4926 H2 TIP3 5720 17.919 -13.566 0.953 0.417 1.000 -ATOM 4927 OH2 TIP3 5723 6.919 -15.757 3.224 -0.834 1.520 -ATOM 4928 H1 TIP3 5723 7.546 -15.400 3.905 0.417 1.000 -ATOM 4929 H2 TIP3 5723 7.492 -15.921 2.426 0.417 1.000 -ATOM 4930 OH2 TIP3 5736 18.769 -15.698 -4.759 -0.834 1.520 -ATOM 4931 H1 TIP3 5736 19.640 -15.481 -4.423 0.417 1.000 -ATOM 4932 H2 TIP3 5736 18.425 -14.887 -5.162 0.417 1.000 -ATOM 4933 OH2 TIP3 5741 17.717 -6.300 5.977 -0.834 1.520 -ATOM 4934 H1 TIP3 5741 18.622 -6.487 6.236 0.417 1.000 -ATOM 4935 H2 TIP3 5741 17.860 -6.305 5.015 0.417 1.000 -ATOM 4936 OH2 TIP3 5756 18.720 -19.085 -10.042 -0.834 1.520 -ATOM 4937 H1 TIP3 5756 18.543 -18.745 -10.939 0.417 1.000 -ATOM 4938 H2 TIP3 5756 19.041 -18.335 -9.553 0.417 1.000 -ATOM 4939 OH2 TIP3 5760 18.464 -18.489 4.239 -0.834 1.520 -ATOM 4940 H1 TIP3 5760 18.696 -19.225 4.807 0.417 1.000 -ATOM 4941 H2 TIP3 5760 18.900 -18.765 3.388 0.417 1.000 -ATOM 4942 OH2 TIP3 5765 17.890 -18.159 17.115 -0.834 1.520 -ATOM 4943 H1 TIP3 5765 18.680 -18.480 17.633 0.417 1.000 -ATOM 4944 H2 TIP3 5765 17.229 -18.064 17.819 0.417 1.000 -ATOM 4945 OH2 TIP3 5767 16.459 -16.347 0.744 -0.834 1.520 -ATOM 4946 H1 TIP3 5767 15.941 -16.315 1.542 0.417 1.000 -ATOM 4947 H2 TIP3 5767 16.754 -15.402 0.621 0.417 1.000 -ATOM 4948 OH2 TIP3 5768 14.731 -4.777 0.339 -0.834 1.520 -ATOM 4949 H1 TIP3 5768 13.991 -5.085 -0.209 0.417 1.000 -ATOM 4950 H2 TIP3 5768 14.317 -4.875 1.247 0.417 1.000 -ATOM 4951 OH2 TIP3 5777 19.925 -10.137 -19.866 -0.834 1.520 -ATOM 4952 H1 TIP3 5777 19.934 -9.190 -19.832 0.417 1.000 -ATOM 4953 H2 TIP3 5777 18.975 -10.416 -19.797 0.417 1.000 -ATOM 4954 OH2 TIP3 5782 0.842 -6.430 4.883 -0.834 1.520 -ATOM 4955 H1 TIP3 5782 1.084 -5.588 5.335 0.417 1.000 -ATOM 4956 H2 TIP3 5782 -0.020 -6.620 5.201 0.417 1.000 -ATOM 4957 OH2 TIP3 5784 19.719 -4.976 8.581 -0.834 1.520 -ATOM 4958 H1 TIP3 5784 18.720 -5.011 8.595 0.417 1.000 -ATOM 4959 H2 TIP3 5784 19.932 -4.591 7.681 0.417 1.000 -ATOM 4960 OH2 TIP3 5785 8.411 -14.609 18.565 -0.834 1.520 -ATOM 4961 H1 TIP3 5785 8.638 -14.019 19.284 0.417 1.000 -ATOM 4962 H2 TIP3 5785 8.889 -15.369 18.738 0.417 1.000 -ATOM 4963 OH2 TIP3 5791 17.884 -10.183 12.645 -0.834 1.520 -ATOM 4964 H1 TIP3 5791 17.483 -9.764 11.870 0.417 1.000 -ATOM 4965 H2 TIP3 5791 17.993 -9.426 13.219 0.417 1.000 -ATOM 4966 OH2 TIP3 5795 10.434 -9.295 -6.732 -0.834 1.520 -ATOM 4967 H1 TIP3 5795 9.617 -9.807 -6.823 0.417 1.000 -ATOM 4968 H2 TIP3 5795 10.536 -9.247 -5.767 0.417 1.000 -ATOM 4969 OH2 TIP3 5803 11.367 -17.504 8.704 -0.834 1.520 -ATOM 4970 H1 TIP3 5803 11.892 -16.719 9.045 0.417 1.000 -ATOM 4971 H2 TIP3 5803 11.378 -18.082 9.459 0.417 1.000 -ATOM 4972 OH2 TIP3 5804 2.274 -17.000 8.005 -0.834 1.520 -ATOM 4973 H1 TIP3 5804 1.899 -16.933 8.900 0.417 1.000 -ATOM 4974 H2 TIP3 5804 2.349 -17.966 7.824 0.417 1.000 -ATOM 4975 OH2 TIP3 5806 19.017 -14.066 11.834 -0.834 1.520 -ATOM 4976 H1 TIP3 5806 19.443 -14.671 11.239 0.417 1.000 -ATOM 4977 H2 TIP3 5806 18.689 -13.358 11.192 0.417 1.000 -ATOM 4978 OH2 TIP3 5807 17.605 -8.794 16.594 -0.834 1.520 -ATOM 4979 H1 TIP3 5807 18.105 -7.996 16.877 0.417 1.000 -ATOM 4980 H2 TIP3 5807 16.755 -8.377 16.258 0.417 1.000 -ATOM 4981 OH2 TIP3 5818 14.951 9.246 -18.216 -0.834 1.520 -ATOM 4982 H1 TIP3 5818 15.492 9.897 -18.603 0.417 1.000 -ATOM 4983 H2 TIP3 5818 14.064 9.568 -18.502 0.417 1.000 -ATOM 4984 OH2 TIP3 5820 15.560 -9.147 -8.955 -0.834 1.520 -ATOM 4985 H1 TIP3 5820 15.946 -9.694 -8.244 0.417 1.000 -ATOM 4986 H2 TIP3 5820 15.112 -9.865 -9.526 0.417 1.000 -ATOM 4987 OH2 TIP3 5821 12.574 -5.635 -5.510 -0.834 1.520 -ATOM 4988 H1 TIP3 5821 11.973 -6.364 -5.597 0.417 1.000 -ATOM 4989 H2 TIP3 5821 12.103 -4.921 -5.889 0.417 1.000 -ATOM 4990 OH2 TIP3 5824 12.379 -18.522 6.530 -0.834 1.520 -ATOM 4991 H1 TIP3 5824 12.027 -19.442 6.456 0.417 1.000 -ATOM 4992 H2 TIP3 5824 12.226 -18.201 7.410 0.417 1.000 -ATOM 4993 OH2 TIP3 5827 3.893 -3.789 3.211 -0.834 1.520 -ATOM 4994 H1 TIP3 5827 3.768 -4.616 2.714 0.417 1.000 -ATOM 4995 H2 TIP3 5827 3.179 -3.227 3.003 0.417 1.000 -ATOM 4996 OH2 TIP3 5834 14.343 -5.605 11.122 -0.834 1.520 -ATOM 4997 H1 TIP3 5834 14.853 -5.155 11.833 0.417 1.000 -ATOM 4998 H2 TIP3 5834 13.561 -5.864 11.598 0.417 1.000 -ATOM 4999 OH2 TIP3 5839 13.028 -3.293 -15.034 -0.834 1.520 -ATOM 5000 H1 TIP3 5839 12.488 -3.000 -14.308 0.417 1.000 -ATOM 5001 H2 TIP3 5839 13.536 -3.972 -14.551 0.417 1.000 -ATOM 5002 OH2 TIP3 5840 15.922 8.590 -15.299 -0.834 1.520 -ATOM 5003 H1 TIP3 5840 15.174 8.530 -15.914 0.417 1.000 -ATOM 5004 H2 TIP3 5840 16.526 9.316 -15.654 0.417 1.000 -ATOM 5005 OH2 TIP3 5842 11.352 -1.409 8.149 -0.834 1.520 -ATOM 5006 H1 TIP3 5842 11.651 -2.223 8.551 0.417 1.000 -ATOM 5007 H2 TIP3 5842 11.234 -0.748 8.819 0.417 1.000 -ATOM 5008 OH2 TIP3 5844 19.698 -9.445 -0.979 -0.834 1.520 -ATOM 5009 H1 TIP3 5844 19.296 -8.881 -1.619 0.417 1.000 -ATOM 5010 H2 TIP3 5844 18.953 -10.002 -0.668 0.417 1.000 -ATOM 5011 OH2 TIP3 5845 12.946 4.486 5.134 -0.834 1.520 -ATOM 5012 H1 TIP3 5845 12.703 5.071 5.902 0.417 1.000 -ATOM 5013 H2 TIP3 5845 13.913 4.605 5.047 0.417 1.000 -ATOM 5014 OH2 TIP3 5849 6.737 -6.211 13.818 -0.834 1.520 -ATOM 5015 H1 TIP3 5849 7.398 -6.834 13.923 0.417 1.000 -ATOM 5016 H2 TIP3 5849 7.206 -5.396 13.613 0.417 1.000 -ATOM 5017 OH2 TIP3 5860 9.708 -4.715 -9.528 -0.834 1.520 -ATOM 5018 H1 TIP3 5860 9.576 -4.508 -8.567 0.417 1.000 -ATOM 5019 H2 TIP3 5860 10.628 -4.486 -9.646 0.417 1.000 -ATOM 5020 OH2 TIP3 5861 17.443 4.171 -12.189 -0.834 1.520 -ATOM 5021 H1 TIP3 5861 16.966 4.983 -12.404 0.417 1.000 -ATOM 5022 H2 TIP3 5861 17.263 3.629 -12.969 0.417 1.000 -ATOM 5023 OH2 TIP3 5862 17.233 0.009 -12.818 -0.834 1.520 -ATOM 5024 H1 TIP3 5862 17.096 -0.610 -13.493 0.417 1.000 -ATOM 5025 H2 TIP3 5862 17.966 -0.341 -12.270 0.417 1.000 -ATOM 5026 OH2 TIP3 5864 9.752 -0.123 10.311 -0.834 1.520 -ATOM 5027 H1 TIP3 5864 9.124 -0.691 9.764 0.417 1.000 -ATOM 5028 H2 TIP3 5864 9.196 0.589 10.657 0.417 1.000 -ATOM 5029 OH2 TIP3 5865 16.679 -6.995 1.116 -0.834 1.520 -ATOM 5030 H1 TIP3 5865 16.232 -7.906 1.064 0.417 1.000 -ATOM 5031 H2 TIP3 5865 16.396 -6.522 0.329 0.417 1.000 -ATOM 5032 OH2 TIP3 5868 14.660 -1.218 8.378 -0.834 1.520 -ATOM 5033 H1 TIP3 5868 15.453 -1.616 8.804 0.417 1.000 -ATOM 5034 H2 TIP3 5868 13.978 -1.884 8.611 0.417 1.000 -ATOM 5035 OH2 TIP3 5870 1.849 11.211 19.309 -0.834 1.520 -ATOM 5036 H1 TIP3 5870 1.681 10.244 19.348 0.417 1.000 -ATOM 5037 H2 TIP3 5870 2.819 11.222 19.501 0.417 1.000 -ATOM 5038 OH2 TIP3 5881 15.444 -10.107 -15.865 -0.834 1.520 -ATOM 5039 H1 TIP3 5881 14.898 -9.815 -15.167 0.417 1.000 -ATOM 5040 H2 TIP3 5881 15.644 -11.006 -15.452 0.417 1.000 -ATOM 5041 OH2 TIP3 5884 19.276 -15.078 -11.090 -0.834 1.520 -ATOM 5042 H1 TIP3 5884 19.353 -14.334 -11.676 0.417 1.000 -ATOM 5043 H2 TIP3 5884 19.973 -14.892 -10.463 0.417 1.000 -ATOM 5044 OH2 TIP3 5889 16.284 -6.832 -10.052 -0.834 1.520 -ATOM 5045 H1 TIP3 5889 16.271 -7.712 -9.561 0.417 1.000 -ATOM 5046 H2 TIP3 5889 15.534 -6.950 -10.703 0.417 1.000 -ATOM 5047 OH2 TIP3 5890 16.687 -5.256 15.841 -0.834 1.520 -ATOM 5048 H1 TIP3 5890 17.327 -5.249 15.159 0.417 1.000 -ATOM 5049 H2 TIP3 5890 17.077 -4.701 16.527 0.417 1.000 -ATOM 5050 OH2 TIP3 5899 2.157 6.309 -9.345 -0.834 1.520 -ATOM 5051 H1 TIP3 5899 2.113 5.340 -9.410 0.417 1.000 -ATOM 5052 H2 TIP3 5899 1.349 6.567 -9.887 0.417 1.000 -ATOM 5053 OH2 TIP3 5901 1.701 -3.796 -8.187 -0.834 1.520 -ATOM 5054 H1 TIP3 5901 1.240 -4.722 -8.322 0.417 1.000 -ATOM 5055 H2 TIP3 5901 2.146 -4.007 -7.398 0.417 1.000 -ATOM 5056 OH2 TIP3 5906 14.317 8.605 -0.076 -0.834 1.520 -ATOM 5057 H1 TIP3 5906 13.682 9.059 -0.695 0.417 1.000 -ATOM 5058 H2 TIP3 5906 14.052 9.046 0.699 0.417 1.000 -ATOM 5059 OH2 TIP3 5907 19.718 -0.138 6.819 -0.834 1.520 -ATOM 5060 H1 TIP3 5907 19.928 -0.283 7.739 0.417 1.000 -ATOM 5061 H2 TIP3 5907 19.425 0.779 6.771 0.417 1.000 -ATOM 5062 OH2 TIP3 5910 10.644 6.866 8.586 -0.834 1.520 -ATOM 5063 H1 TIP3 5910 11.352 6.691 9.172 0.417 1.000 -ATOM 5064 H2 TIP3 5910 11.140 7.329 7.913 0.417 1.000 -ATOM 5065 OH2 TIP3 5911 14.024 0.067 1.448 -0.834 1.520 -ATOM 5066 H1 TIP3 5911 14.544 0.795 1.708 0.417 1.000 -ATOM 5067 H2 TIP3 5911 13.067 0.502 1.486 0.417 1.000 -ATOM 5068 OH2 TIP3 5913 4.823 3.470 6.798 -0.834 1.520 -ATOM 5069 H1 TIP3 5913 5.330 4.268 6.950 0.417 1.000 -ATOM 5070 H2 TIP3 5913 5.191 3.224 5.984 0.417 1.000 -ATOM 5071 OH2 TIP3 5914 18.471 -9.128 19.883 -0.834 1.520 -ATOM 5072 H1 TIP3 5914 19.390 -9.501 19.765 0.417 1.000 -ATOM 5073 H2 TIP3 5914 18.468 -8.403 19.264 0.417 1.000 -ATOM 5074 OH2 TIP3 5920 14.510 -6.294 -14.442 -0.834 1.520 -ATOM 5075 H1 TIP3 5920 14.762 -6.216 -15.357 0.417 1.000 -ATOM 5076 H2 TIP3 5920 14.115 -7.218 -14.395 0.417 1.000 -ATOM 5077 OH2 TIP3 5924 17.133 6.283 2.439 -0.834 1.520 -ATOM 5078 H1 TIP3 5924 17.505 7.189 2.338 0.417 1.000 -ATOM 5079 H2 TIP3 5924 16.912 6.021 1.476 0.417 1.000 -ATOM 5080 OH2 TIP3 5925 10.116 18.130 -17.236 -0.834 1.520 -ATOM 5081 H1 TIP3 5925 10.739 17.963 -16.532 0.417 1.000 -ATOM 5082 H2 TIP3 5925 9.814 17.221 -17.426 0.417 1.000 -ATOM 5083 OH2 TIP3 5930 10.375 17.848 4.514 -0.834 1.520 -ATOM 5084 H1 TIP3 5930 10.747 18.288 5.337 0.417 1.000 -ATOM 5085 H2 TIP3 5930 10.077 18.539 3.949 0.417 1.000 -ATOM 5086 OH2 TIP3 5932 15.664 4.835 4.312 -0.834 1.520 -ATOM 5087 H1 TIP3 5932 16.209 5.213 3.655 0.417 1.000 -ATOM 5088 H2 TIP3 5932 16.218 5.094 5.054 0.417 1.000 -ATOM 5089 OH2 TIP3 5935 10.481 9.878 11.227 -0.834 1.520 -ATOM 5090 H1 TIP3 5935 11.225 10.170 11.844 0.417 1.000 -ATOM 5091 H2 TIP3 5935 10.797 10.174 10.293 0.417 1.000 -ATOM 5092 OH2 TIP3 5941 15.927 17.566 -3.842 -0.834 1.520 -ATOM 5093 H1 TIP3 5941 15.511 17.790 -2.984 0.417 1.000 -ATOM 5094 H2 TIP3 5941 15.663 16.687 -4.098 0.417 1.000 -ATOM 5095 OH2 TIP3 5945 7.702 9.196 0.160 -0.834 1.520 -ATOM 5096 H1 TIP3 5945 7.123 9.912 -0.191 0.417 1.000 -ATOM 5097 H2 TIP3 5945 7.403 9.079 1.069 0.417 1.000 -ATOM 5098 OH2 TIP3 5972 16.858 7.112 6.018 -0.834 1.520 -ATOM 5099 H1 TIP3 5972 16.455 7.899 6.455 0.417 1.000 -ATOM 5100 H2 TIP3 5972 17.484 7.544 5.453 0.417 1.000 -ATOM 5101 OH2 TIP3 5973 15.696 14.271 14.278 -0.834 1.520 -ATOM 5102 H1 TIP3 5973 15.870 13.468 13.719 0.417 1.000 -ATOM 5103 H2 TIP3 5973 16.506 14.719 14.177 0.417 1.000 -ATOM 5104 OH2 TIP3 5977 18.465 11.788 15.750 -0.834 1.520 -ATOM 5105 H1 TIP3 5977 17.791 11.588 15.036 0.417 1.000 -ATOM 5106 H2 TIP3 5977 18.044 11.301 16.503 0.417 1.000 -ATOM 5107 OH2 TIP3 5989 5.958 17.112 -9.465 -0.834 1.520 -ATOM 5108 H1 TIP3 5989 6.463 17.075 -10.303 0.417 1.000 -ATOM 5109 H2 TIP3 5989 6.119 18.021 -9.170 0.417 1.000 -ATOM 5110 OH2 TIP3 5992 13.061 16.541 0.071 -0.834 1.520 -ATOM 5111 H1 TIP3 5992 12.167 16.450 -0.238 0.417 1.000 -ATOM 5112 H2 TIP3 5992 13.259 15.623 0.332 0.417 1.000 -ATOM 5113 OH2 TIP3 5993 8.263 16.264 9.221 -0.834 1.520 -ATOM 5114 H1 TIP3 5993 9.031 16.326 9.780 0.417 1.000 -ATOM 5115 H2 TIP3 5993 7.811 15.455 9.592 0.417 1.000 -ATOM 5116 OH2 TIP3 5996 16.031 9.340 14.083 -0.834 1.520 -ATOM 5117 H1 TIP3 5996 16.709 8.952 14.620 0.417 1.000 -ATOM 5118 H2 TIP3 5996 15.219 9.300 14.549 0.417 1.000 -ATOM 5119 OH2 TIP3 6012 18.970 19.936 8.056 -0.834 1.520 -ATOM 5120 H1 TIP3 6012 19.867 19.798 8.384 0.417 1.000 -ATOM 5121 H2 TIP3 6012 19.077 19.535 7.154 0.417 1.000 -ATOM 5122 OH2 TIP3 6019 13.835 11.798 -1.720 -0.834 1.520 -ATOM 5123 H1 TIP3 6019 14.717 11.778 -2.057 0.417 1.000 -ATOM 5124 H2 TIP3 6019 13.509 10.949 -2.116 0.417 1.000 -ATOM 5125 OH2 TIP3 6036 18.524 12.307 0.226 -0.834 1.520 -ATOM 5126 H1 TIP3 6036 18.597 12.412 1.225 0.417 1.000 -ATOM 5127 H2 TIP3 6036 17.692 11.827 0.112 0.417 1.000 -ATOM 5128 OH2 TIP3 6039 15.350 14.076 8.081 -0.834 1.520 -ATOM 5129 H1 TIP3 6039 16.016 14.136 7.313 0.417 1.000 -ATOM 5130 H2 TIP3 6039 14.474 14.045 7.573 0.417 1.000 -ATOM 5131 OH2 TIP3 6048 15.236 12.545 -15.055 -0.834 1.520 -ATOM 5132 H1 TIP3 6048 14.374 12.178 -14.836 0.417 1.000 -ATOM 5133 H2 TIP3 6048 15.075 13.510 -14.862 0.417 1.000 -ATOM 5134 OH2 TIP3 6110 18.595 -18.216 -18.755 -0.834 1.520 -ATOM 5135 H1 TIP3 6110 18.500 -18.695 -19.587 0.417 1.000 -ATOM 5136 H2 TIP3 6110 19.426 -17.785 -18.960 0.417 1.000 -ATOM 5137 OH2 TIP3 6117 18.184 18.079 -17.294 -0.834 1.520 -ATOM 5138 H1 TIP3 6117 17.940 17.568 -16.584 0.417 1.000 -ATOM 5139 H2 TIP3 6117 19.167 18.220 -17.182 0.417 1.000 -ATOM 5140 OH2 TIP3 6136 16.949 -10.849 -7.430 -0.834 1.520 -ATOM 5141 H1 TIP3 6136 17.451 -10.866 -8.263 0.417 1.000 -ATOM 5142 H2 TIP3 6136 16.438 -11.693 -7.510 0.417 1.000 -ATOM 5143 OH2 TIP3 6138 12.773 -17.741 -7.363 -0.834 1.520 -ATOM 5144 H1 TIP3 6138 12.793 -18.533 -6.791 0.417 1.000 -ATOM 5145 H2 TIP3 6138 12.105 -17.987 -8.009 0.417 1.000 -ATOM 5146 OH2 TIP3 6139 16.511 -10.540 6.593 -0.834 1.520 -ATOM 5147 H1 TIP3 6139 17.314 -10.950 6.308 0.417 1.000 -ATOM 5148 H2 TIP3 6139 16.610 -9.592 6.226 0.417 1.000 -ATOM 5149 OH2 TIP3 6158 3.865 -18.173 -15.336 -0.834 1.520 -ATOM 5150 H1 TIP3 6158 3.526 -19.028 -15.556 0.417 1.000 -ATOM 5151 H2 TIP3 6158 4.483 -18.343 -14.531 0.417 1.000 -ATOM 5152 OH2 TIP3 6178 17.511 -11.193 2.131 -0.834 1.520 -ATOM 5153 H1 TIP3 6178 18.343 -10.683 1.977 0.417 1.000 -ATOM 5154 H2 TIP3 6178 16.886 -10.520 1.867 0.417 1.000 -ATOM 5155 OH2 TIP3 6183 9.289 -16.850 -10.699 -0.834 1.520 -ATOM 5156 H1 TIP3 6183 9.950 -16.210 -11.070 0.417 1.000 -ATOM 5157 H2 TIP3 6183 8.761 -17.105 -11.479 0.417 1.000 -ATOM 5158 OH2 TIP3 6187 14.008 -18.363 9.864 -0.834 1.520 -ATOM 5159 H1 TIP3 6187 14.988 -18.244 9.729 0.417 1.000 -ATOM 5160 H2 TIP3 6187 13.759 -17.437 9.984 0.417 1.000 -ATOM 5161 OH2 TIP3 6188 16.927 -15.196 15.751 -0.834 1.520 -ATOM 5162 H1 TIP3 6188 17.543 -15.675 16.351 0.417 1.000 -ATOM 5163 H2 TIP3 6188 17.511 -14.574 15.344 0.417 1.000 -ATOM 5164 OH2 TIP3 6195 10.673 -8.999 -16.499 -0.834 1.520 -ATOM 5165 H1 TIP3 6195 10.445 -9.896 -16.093 0.417 1.000 -ATOM 5166 H2 TIP3 6195 9.950 -8.827 -17.173 0.417 1.000 -ATOM 5167 OH2 TIP3 6198 19.062 -5.607 -13.274 -0.834 1.520 -ATOM 5168 H1 TIP3 6198 18.900 -6.403 -12.820 0.417 1.000 -ATOM 5169 H2 TIP3 6198 18.341 -5.478 -13.914 0.417 1.000 -ATOM 5170 OH2 TIP3 6200 18.172 -18.411 -6.104 -0.834 1.520 -ATOM 5171 H1 TIP3 6200 17.963 -17.499 -6.047 0.417 1.000 -ATOM 5172 H2 TIP3 6200 17.215 -18.764 -6.166 0.417 1.000 -ATOM 5173 OH2 TIP3 6219 18.442 -14.018 -16.211 -0.834 1.520 -ATOM 5174 H1 TIP3 6219 18.510 -14.805 -15.620 0.417 1.000 -ATOM 5175 H2 TIP3 6219 19.384 -14.022 -16.506 0.417 1.000 -ATOM 5176 OH2 TIP3 6220 12.627 0.031 -9.044 -0.834 1.520 -ATOM 5177 H1 TIP3 6220 11.932 -0.017 -9.766 0.417 1.000 -ATOM 5178 H2 TIP3 6220 12.516 -0.821 -8.536 0.417 1.000 -ATOM 5179 OH2 TIP3 6240 -16.920 -19.051 -8.212 -0.834 1.520 -ATOM 5180 H1 TIP3 6240 -16.310 -19.500 -8.828 0.417 1.000 -ATOM 5181 H2 TIP3 6240 -17.804 -19.444 -8.359 0.417 1.000 -ATOM 5182 OH2 TIP3 6241 9.462 1.024 -9.649 -0.834 1.520 -ATOM 5183 H1 TIP3 6241 9.814 0.763 -10.497 0.417 1.000 -ATOM 5184 H2 TIP3 6241 9.452 0.119 -9.241 0.417 1.000 -ATOM 5185 OH2 TIP3 6243 19.114 -10.058 -3.913 -0.834 1.520 -ATOM 5186 H1 TIP3 6243 18.333 -10.698 -3.714 0.417 1.000 -ATOM 5187 H2 TIP3 6243 19.792 -10.607 -3.510 0.417 1.000 -ATOM 5188 OH2 TIP3 6247 9.430 0.387 14.216 -0.834 1.520 -ATOM 5189 H1 TIP3 6247 9.429 1.378 14.066 0.417 1.000 -ATOM 5190 H2 TIP3 6247 10.158 0.138 13.637 0.417 1.000 -ATOM 5191 OH2 TIP3 6256 18.710 -11.190 -9.476 -0.834 1.520 -ATOM 5192 H1 TIP3 6256 19.285 -10.435 -9.422 0.417 1.000 -ATOM 5193 H2 TIP3 6256 19.249 -11.946 -9.577 0.417 1.000 -ATOM 5194 OH2 TIP3 6258 14.517 -5.304 -8.677 -0.834 1.520 -ATOM 5195 H1 TIP3 6258 14.017 -5.790 -8.053 0.417 1.000 -ATOM 5196 H2 TIP3 6258 15.388 -5.778 -8.775 0.417 1.000 -ATOM 5197 OH2 TIP3 6266 13.874 -10.066 3.981 -0.834 1.520 -ATOM 5198 H1 TIP3 6266 14.466 -9.322 4.250 0.417 1.000 -ATOM 5199 H2 TIP3 6266 14.188 -10.361 3.145 0.417 1.000 -ATOM 5200 OH2 TIP3 6300 8.603 5.046 -11.244 -0.834 1.520 -ATOM 5201 H1 TIP3 6300 8.196 5.721 -10.650 0.417 1.000 -ATOM 5202 H2 TIP3 6300 8.345 5.319 -12.104 0.417 1.000 -ATOM 5203 OH2 TIP3 6302 15.255 17.615 -1.139 -0.834 1.520 -ATOM 5204 H1 TIP3 6302 15.637 16.714 -1.125 0.417 1.000 -ATOM 5205 H2 TIP3 6302 14.346 17.487 -0.863 0.417 1.000 -ATOM 5206 OH2 TIP3 6309 15.779 3.135 0.132 -0.834 1.520 -ATOM 5207 H1 TIP3 6309 15.918 2.804 1.032 0.417 1.000 -ATOM 5208 H2 TIP3 6309 15.559 4.079 0.225 0.417 1.000 -ATOM 5209 OH2 TIP3 6311 14.117 -15.216 -7.681 -0.834 1.520 -ATOM 5210 H1 TIP3 6311 13.538 -15.951 -7.665 0.417 1.000 -ATOM 5211 H2 TIP3 6311 14.966 -15.599 -7.412 0.417 1.000 -ATOM 5212 OH2 TIP3 6315 13.898 -12.433 19.265 -0.834 1.520 -ATOM 5213 H1 TIP3 6315 14.046 -11.787 18.505 0.417 1.000 -ATOM 5214 H2 TIP3 6315 14.292 -13.272 18.976 0.417 1.000 -ATOM 5215 OH2 TIP3 6321 16.759 -6.142 -6.759 -0.834 1.520 -ATOM 5216 H1 TIP3 6321 17.254 -6.922 -6.700 0.417 1.000 -ATOM 5217 H2 TIP3 6321 16.903 -5.723 -5.906 0.417 1.000 -ATOM 5218 OH2 TIP3 6325 7.495 0.734 -3.941 -0.834 1.520 -ATOM 5219 H1 TIP3 6325 7.618 1.083 -3.066 0.417 1.000 -ATOM 5220 H2 TIP3 6325 6.546 0.766 -4.029 0.417 1.000 -ATOM 5221 OH2 TIP3 6333 14.076 -4.182 17.215 -0.834 1.520 -ATOM 5222 H1 TIP3 6333 13.717 -4.418 18.037 0.417 1.000 -ATOM 5223 H2 TIP3 6333 15.017 -4.453 17.223 0.417 1.000 -ATOM 5224 OH2 TIP3 6347 17.415 8.449 -0.750 -0.834 1.520 -ATOM 5225 H1 TIP3 6347 16.432 8.260 -0.793 0.417 1.000 -ATOM 5226 H2 TIP3 6347 17.695 8.409 -1.641 0.417 1.000 -ATOM 5227 OH2 TIP3 6348 18.265 5.005 -7.753 -0.834 1.520 -ATOM 5228 H1 TIP3 6348 18.893 4.231 -8.109 0.417 1.000 -ATOM 5229 H2 TIP3 6348 17.406 4.598 -7.627 0.417 1.000 -ATOM 5230 OH2 TIP3 6352 12.470 12.566 2.559 -0.834 1.520 -ATOM 5231 H1 TIP3 6352 11.584 12.597 2.092 0.417 1.000 -ATOM 5232 H2 TIP3 6352 12.196 12.410 3.533 0.417 1.000 -ATOM 5233 OH2 TIP3 6356 13.430 5.959 15.069 -0.834 1.520 -ATOM 5234 H1 TIP3 6356 12.749 5.332 15.250 0.417 1.000 -ATOM 5235 H2 TIP3 6356 13.448 6.034 14.131 0.417 1.000 -ATOM 5236 OH2 TIP3 6370 16.417 0.527 4.809 -0.834 1.520 -ATOM 5237 H1 TIP3 6370 15.913 1.083 5.518 0.417 1.000 -ATOM 5238 H2 TIP3 6370 16.555 -0.381 5.118 0.417 1.000 -ATOM 5239 OH2 TIP3 6373 17.481 9.369 8.871 -0.834 1.520 -ATOM 5240 H1 TIP3 6373 16.902 9.820 8.223 0.417 1.000 -ATOM 5241 H2 TIP3 6373 18.334 9.258 8.353 0.417 1.000 -ATOM 5242 OH2 TIP3 6381 15.388 -5.799 -17.128 -0.834 1.520 -ATOM 5243 H1 TIP3 6381 15.822 -6.583 -17.414 0.417 1.000 -ATOM 5244 H2 TIP3 6381 15.683 -5.117 -17.748 0.417 1.000 -ATOM 5245 OH2 TIP3 6404 14.627 19.477 -18.971 -0.834 1.520 -ATOM 5246 H1 TIP3 6404 15.534 19.676 -18.599 0.417 1.000 -ATOM 5247 H2 TIP3 6404 14.656 19.858 -19.872 0.417 1.000 -ATOM 5248 OH2 TIP3 6417 16.099 11.041 0.540 -0.834 1.520 -ATOM 5249 H1 TIP3 6417 15.853 10.544 -0.247 0.417 1.000 -ATOM 5250 H2 TIP3 6417 15.397 10.963 1.168 0.417 1.000 -ATOM 5251 OH2 TIP3 6425 14.706 13.591 -18.454 -0.834 1.520 -ATOM 5252 H1 TIP3 6425 15.001 13.098 -17.650 0.417 1.000 -ATOM 5253 H2 TIP3 6425 13.797 13.825 -18.206 0.417 1.000 -ATOM 5254 OH2 TIP3 6429 16.114 8.527 -10.530 -0.834 1.520 -ATOM 5255 H1 TIP3 6429 16.585 8.342 -9.719 0.417 1.000 -ATOM 5256 H2 TIP3 6429 16.687 8.403 -11.276 0.417 1.000 -ATOM 5257 OH2 TIP3 6439 16.110 12.348 12.423 -0.834 1.520 -ATOM 5258 H1 TIP3 6439 16.368 12.137 11.512 0.417 1.000 -ATOM 5259 H2 TIP3 6439 16.051 11.474 12.873 0.417 1.000 -ATOM 5260 OH2 TIP3 6456 13.464 13.208 5.608 -0.834 1.520 -ATOM 5261 H1 TIP3 6456 13.071 12.324 5.540 0.417 1.000 -ATOM 5262 H2 TIP3 6456 12.710 13.743 5.337 0.417 1.000 -ATOM 5263 OH2 TIP3 6483 18.297 15.389 13.797 -0.834 1.520 -ATOM 5264 H1 TIP3 6483 18.161 16.339 14.125 0.417 1.000 -ATOM 5265 H2 TIP3 6483 18.816 14.979 14.506 0.417 1.000 -ATOM 5266 OH2 TIP3 6492 10.201 8.396 -5.748 -0.834 1.520 -ATOM 5267 H1 TIP3 6492 9.790 9.206 -5.358 0.417 1.000 -ATOM 5268 H2 TIP3 6492 10.307 7.838 -4.965 0.417 1.000 -ATOM 5269 OH2 TIP3 6499 15.826 8.528 -3.171 -0.834 1.520 -ATOM 5270 H1 TIP3 6499 15.546 7.563 -2.983 0.417 1.000 -ATOM 5271 H2 TIP3 6499 15.225 8.805 -3.879 0.417 1.000 -ATOM 5272 OH2 TIP3 6502 18.029 18.224 13.986 -0.834 1.520 -ATOM 5273 H1 TIP3 6502 18.944 18.397 14.377 0.417 1.000 -ATOM 5274 H2 TIP3 6502 17.985 18.806 13.217 0.417 1.000 -ATOM 5275 OH2 TIP3 6551 17.038 -12.756 -18.318 -0.834 1.520 -ATOM 5276 H1 TIP3 6551 16.056 -12.714 -18.143 0.417 1.000 -ATOM 5277 H2 TIP3 6551 17.432 -13.299 -17.555 0.417 1.000 -ATOM 5278 OH2 TIP3 6575 16.685 -13.065 -10.242 -0.834 1.520 -ATOM 5279 H1 TIP3 6575 15.864 -12.581 -10.217 0.417 1.000 -ATOM 5280 H2 TIP3 6575 17.340 -12.414 -10.034 0.417 1.000 -ATOM 5281 OH2 TIP3 6577 18.667 -17.062 -1.377 -0.834 1.520 -ATOM 5282 H1 TIP3 6577 18.061 -16.505 -1.934 0.417 1.000 -ATOM 5283 H2 TIP3 6577 18.224 -17.043 -0.502 0.417 1.000 -ATOM 5284 OH2 TIP3 6578 18.057 -15.886 3.645 -0.834 1.520 -ATOM 5285 H1 TIP3 6578 17.174 -16.221 3.329 0.417 1.000 -ATOM 5286 H2 TIP3 6578 18.489 -16.639 4.159 0.417 1.000 -ATOM 5287 OH2 TIP3 6583 5.431 -14.780 6.033 -0.834 1.520 -ATOM 5288 H1 TIP3 6583 5.686 -13.883 5.671 0.417 1.000 -ATOM 5289 H2 TIP3 6583 5.655 -14.734 6.978 0.417 1.000 -ATOM 5290 OH2 TIP3 6597 16.934 -18.378 -12.167 -0.834 1.520 -ATOM 5291 H1 TIP3 6597 16.171 -18.749 -12.620 0.417 1.000 -ATOM 5292 H2 TIP3 6597 16.578 -17.959 -11.361 0.417 1.000 -ATOM 5293 OH2 TIP3 6603 18.685 -7.603 -2.963 -0.834 1.520 -ATOM 5294 H1 TIP3 6603 17.893 -7.205 -3.360 0.417 1.000 -ATOM 5295 H2 TIP3 6603 18.756 -8.437 -3.418 0.417 1.000 -ATOM 5296 OH2 TIP3 6623 15.905 3.289 -7.823 -0.834 1.520 -ATOM 5297 H1 TIP3 6623 15.405 2.453 -7.737 0.417 1.000 -ATOM 5298 H2 TIP3 6623 16.099 3.300 -8.793 0.417 1.000 -ATOM 5299 OH2 TIP3 6661 16.588 -1.763 -14.695 -0.834 1.520 -ATOM 5300 H1 TIP3 6661 16.139 -1.597 -15.521 0.417 1.000 -ATOM 5301 H2 TIP3 6661 16.515 -2.721 -14.635 0.417 1.000 -ATOM 5302 OH2 TIP3 6663 16.714 -10.070 9.636 -0.834 1.520 -ATOM 5303 H1 TIP3 6663 17.136 -9.185 9.734 0.417 1.000 -ATOM 5304 H2 TIP3 6663 16.615 -10.113 8.679 0.417 1.000 -ATOM 5305 OH2 TIP3 6667 14.995 -17.815 18.545 -0.834 1.520 -ATOM 5306 H1 TIP3 6667 14.341 -18.180 17.916 0.417 1.000 -ATOM 5307 H2 TIP3 6667 14.462 -17.068 18.949 0.417 1.000 -ATOM 5308 OH2 TIP3 6669 15.835 -13.074 12.145 -0.834 1.520 -ATOM 5309 H1 TIP3 6669 16.636 -13.402 11.616 0.417 1.000 -ATOM 5310 H2 TIP3 6669 15.634 -13.890 12.729 0.417 1.000 -ATOM 5311 OH2 TIP3 6671 -19.103 -7.187 0.940 -0.834 1.520 -ATOM 5312 H1 TIP3 6671 -18.766 -6.423 1.489 0.417 1.000 -ATOM 5313 H2 TIP3 6671 -18.890 -7.917 1.442 0.417 1.000 -ATOM 5314 OH2 TIP3 6672 12.685 -10.560 14.879 -0.834 1.520 -ATOM 5315 H1 TIP3 6672 12.047 -11.075 14.323 0.417 1.000 -ATOM 5316 H2 TIP3 6672 13.281 -10.201 14.205 0.417 1.000 -ATOM 5317 OH2 TIP3 6681 16.626 0.950 -18.215 -0.834 1.520 -ATOM 5318 H1 TIP3 6681 16.391 1.874 -17.889 0.417 1.000 -ATOM 5319 H2 TIP3 6681 17.091 0.565 -17.414 0.417 1.000 -ATOM 5320 OH2 TIP3 6684 7.912 -9.027 -15.928 -0.834 1.520 -ATOM 5321 H1 TIP3 6684 6.970 -9.310 -15.925 0.417 1.000 -ATOM 5322 H2 TIP3 6684 7.786 -8.059 -16.065 0.417 1.000 -ATOM 5323 OH2 TIP3 6703 14.408 -7.477 -6.332 -0.834 1.520 -ATOM 5324 H1 TIP3 6703 14.017 -6.689 -6.042 0.417 1.000 -ATOM 5325 H2 TIP3 6703 15.307 -7.120 -6.630 0.417 1.000 -ATOM 5326 OH2 TIP3 6705 14.244 2.149 -2.137 -0.834 1.520 -ATOM 5327 H1 TIP3 6705 14.911 2.111 -1.431 0.417 1.000 -ATOM 5328 H2 TIP3 6705 14.746 1.912 -2.910 0.417 1.000 -ATOM 5329 OH2 TIP3 6707 15.347 -15.272 9.772 -0.834 1.520 -ATOM 5330 H1 TIP3 6707 15.928 -14.672 9.283 0.417 1.000 -ATOM 5331 H2 TIP3 6707 15.826 -16.067 9.694 0.417 1.000 -ATOM 5332 OH2 TIP3 6726 -1.987 -3.388 -1.134 -0.834 1.520 -ATOM 5333 H1 TIP3 6726 -1.039 -3.237 -1.130 0.417 1.000 -ATOM 5334 H2 TIP3 6726 -2.097 -4.148 -1.767 0.417 1.000 -ATOM 5335 OH2 TIP3 6751 -16.952 6.445 12.140 -0.834 1.520 -ATOM 5336 H1 TIP3 6751 -16.619 5.736 12.733 0.417 1.000 -ATOM 5337 H2 TIP3 6751 -17.900 6.429 12.339 0.417 1.000 -ATOM 5338 OH2 TIP3 6774 8.445 8.554 8.432 -0.834 1.520 -ATOM 5339 H1 TIP3 6774 9.322 8.154 8.374 0.417 1.000 -ATOM 5340 H2 TIP3 6774 7.812 7.759 8.510 0.417 1.000 -ATOM 5341 OH2 TIP3 6813 13.325 -5.870 -2.151 -0.834 1.520 -ATOM 5342 H1 TIP3 6813 13.550 -6.514 -2.851 0.417 1.000 -ATOM 5343 H2 TIP3 6813 12.837 -5.114 -2.565 0.417 1.000 -ATOM 5344 OH2 TIP3 6834 5.747 14.167 -16.239 -0.834 1.520 -ATOM 5345 H1 TIP3 6834 5.515 14.736 -17.052 0.417 1.000 -ATOM 5346 H2 TIP3 6834 4.967 14.186 -15.602 0.417 1.000 -ATOM 5347 OH2 TIP3 6837 18.348 0.190 12.227 -0.834 1.520 -ATOM 5348 H1 TIP3 6837 18.102 1.040 11.791 0.417 1.000 -ATOM 5349 H2 TIP3 6837 17.479 -0.146 12.542 0.417 1.000 -ATOM 5350 OH2 TIP3 6854 16.928 14.027 -1.992 -0.834 1.520 -ATOM 5351 H1 TIP3 6854 16.850 13.124 -2.383 0.417 1.000 -ATOM 5352 H2 TIP3 6854 17.662 14.429 -2.485 0.417 1.000 -ATOM 5353 OH2 TIP3 6855 13.240 3.893 0.917 -0.834 1.520 -ATOM 5354 H1 TIP3 6855 13.505 4.515 1.564 0.417 1.000 -ATOM 5355 H2 TIP3 6855 13.133 3.113 1.432 0.417 1.000 -ATOM 5356 OH2 TIP3 6867 8.346 13.096 -3.718 -0.834 1.520 -ATOM 5357 H1 TIP3 6867 8.406 14.067 -3.550 0.417 1.000 -ATOM 5358 H2 TIP3 6867 7.374 12.973 -3.851 0.417 1.000 -ATOM 5359 OH2 TIP3 6877 11.790 10.649 8.873 -0.834 1.520 -ATOM 5360 H1 TIP3 6877 11.748 11.503 9.268 0.417 1.000 -ATOM 5361 H2 TIP3 6877 12.731 10.397 8.971 0.417 1.000 -ATOM 5362 OH2 TIP3 6917 17.309 11.938 10.025 -0.834 1.520 -ATOM 5363 H1 TIP3 6917 17.406 11.032 9.653 0.417 1.000 -ATOM 5364 H2 TIP3 6917 17.874 12.461 9.446 0.417 1.000 -ATOM 5365 OH2 TIP3 6975 16.688 -15.729 -2.742 -0.834 1.520 -ATOM 5366 H1 TIP3 6975 16.893 -15.870 -3.654 0.417 1.000 -ATOM 5367 H2 TIP3 6975 15.924 -16.267 -2.556 0.417 1.000 -ATOM 5368 OH2 TIP3 6979 18.530 8.226 15.245 -0.834 1.520 -ATOM 5369 H1 TIP3 6979 19.218 8.419 15.889 0.417 1.000 -ATOM 5370 H2 TIP3 6979 18.179 7.357 15.475 0.417 1.000 -ATOM 5371 OH2 TIP3 7017 16.067 -18.799 -17.653 -0.834 1.520 -ATOM 5372 H1 TIP3 7017 15.519 -18.640 -18.474 0.417 1.000 -ATOM 5373 H2 TIP3 7017 16.916 -18.501 -17.937 0.417 1.000 -ATOM 5374 OH2 TIP3 7021 19.529 -9.441 1.670 -0.834 1.520 -ATOM 5375 H1 TIP3 7021 19.411 -8.627 2.121 0.417 1.000 -ATOM 5376 H2 TIP3 7021 19.816 -9.096 0.723 0.417 1.000 -ATOM 5377 OH2 TIP3 7027 -19.283 -18.618 15.598 -0.834 1.520 -ATOM 5378 H1 TIP3 7027 -18.453 -19.138 15.690 0.417 1.000 -ATOM 5379 H2 TIP3 7027 -19.453 -18.376 16.484 0.417 1.000 -ATOM 5380 OH2 TIP3 7041 17.833 -8.618 -6.082 -0.834 1.520 -ATOM 5381 H1 TIP3 7041 17.472 -9.335 -6.648 0.417 1.000 -ATOM 5382 H2 TIP3 7041 18.290 -9.112 -5.415 0.417 1.000 -ATOM 5383 OH2 TIP3 7052 14.779 -4.828 -11.945 -0.834 1.520 -ATOM 5384 H1 TIP3 7052 15.198 -5.207 -11.212 0.417 1.000 -ATOM 5385 H2 TIP3 7052 14.457 -5.617 -12.426 0.417 1.000 -ATOM 5386 OH2 TIP3 7058 7.696 -1.366 -5.657 -0.834 1.520 -ATOM 5387 H1 TIP3 7058 6.941 -0.984 -5.209 0.417 1.000 -ATOM 5388 H2 TIP3 7058 8.424 -0.986 -5.075 0.417 1.000 -ATOM 5389 OH2 TIP3 7062 18.062 -4.590 0.332 -0.834 1.520 -ATOM 5390 H1 TIP3 7062 17.339 -4.860 0.883 0.417 1.000 -ATOM 5391 H2 TIP3 7062 17.656 -3.997 -0.369 0.417 1.000 -ATOM 5392 OH2 TIP3 7068 13.480 -11.792 12.114 -0.834 1.520 -ATOM 5393 H1 TIP3 7068 13.573 -10.949 11.593 0.417 1.000 -ATOM 5394 H2 TIP3 7068 14.407 -12.124 12.157 0.417 1.000 -ATOM 5395 OH2 TIP3 7078 13.653 1.374 -15.511 -0.834 1.520 -ATOM 5396 H1 TIP3 7078 13.702 0.838 -16.298 0.417 1.000 -ATOM 5397 H2 TIP3 7078 12.888 1.034 -15.044 0.417 1.000 -ATOM 5398 OH2 TIP3 7121 17.815 -13.426 -6.045 -0.834 1.520 -ATOM 5399 H1 TIP3 7121 16.975 -12.898 -6.101 0.417 1.000 -ATOM 5400 H2 TIP3 7121 18.523 -12.863 -5.927 0.417 1.000 -ATOM 5401 OH2 TIP3 7130 17.965 -11.088 18.026 -0.834 1.520 -ATOM 5402 H1 TIP3 7130 17.727 -10.479 17.293 0.417 1.000 -ATOM 5403 H2 TIP3 7130 18.030 -10.567 18.768 0.417 1.000 -ATOM 5404 OH2 TIP3 7133 -16.425 -2.423 15.420 -0.834 1.520 -ATOM 5405 H1 TIP3 7133 -15.472 -2.401 15.232 0.417 1.000 -ATOM 5406 H2 TIP3 7133 -16.705 -3.257 15.025 0.417 1.000 -ATOM 5407 OH2 TIP3 7141 -3.702 2.765 -5.053 -0.834 1.520 -ATOM 5408 H1 TIP3 7141 -3.906 2.020 -5.582 0.417 1.000 -ATOM 5409 H2 TIP3 7141 -2.737 2.705 -4.973 0.417 1.000 -ATOM 5410 OH2 TIP3 7147 16.166 6.356 -13.323 -0.834 1.520 -ATOM 5411 H1 TIP3 7147 15.328 6.530 -12.894 0.417 1.000 -ATOM 5412 H2 TIP3 7147 16.749 7.118 -12.998 0.417 1.000 -ATOM 5413 OH2 TIP3 7170 17.428 2.797 14.373 -0.834 1.520 -ATOM 5414 H1 TIP3 7170 17.633 3.370 15.112 0.417 1.000 -ATOM 5415 H2 TIP3 7170 16.520 2.918 14.215 0.417 1.000 -ATOM 5416 OH2 TIP3 7174 19.220 -12.987 15.804 -0.834 1.520 -ATOM 5417 H1 TIP3 7174 18.677 -12.417 16.388 0.417 1.000 -ATOM 5418 H2 TIP3 7174 19.322 -13.757 16.344 0.417 1.000 -ATOM 5419 OH2 TIP3 7192 15.673 9.757 5.294 -0.834 1.520 -ATOM 5420 H1 TIP3 7192 16.044 10.251 4.538 0.417 1.000 -ATOM 5421 H2 TIP3 7192 15.922 10.353 6.042 0.417 1.000 -ATOM 5422 OH2 TIP3 7222 -13.745 -10.198 -19.636 -0.834 1.520 -ATOM 5423 H1 TIP3 7222 -13.046 -10.879 -19.329 0.417 1.000 -ATOM 5424 H2 TIP3 7222 -14.541 -10.736 -19.804 0.417 1.000 -ATOM 5425 OH2 TIP3 7252 10.691 -0.088 5.720 -0.834 1.520 -ATOM 5426 H1 TIP3 7252 11.071 0.322 4.919 0.417 1.000 -ATOM 5427 H2 TIP3 7252 11.454 -0.476 6.131 0.417 1.000 -ATOM 5428 OH2 TIP3 7295 -19.149 2.646 6.279 -0.834 1.520 -ATOM 5429 H1 TIP3 7295 -18.913 1.836 5.835 0.417 1.000 -ATOM 5430 H2 TIP3 7295 -19.759 2.368 6.986 0.417 1.000 -ATOM 5431 OH2 TIP3 7335 18.795 19.215 -9.145 -0.834 1.520 -ATOM 5432 H1 TIP3 7335 19.201 19.840 -9.737 0.417 1.000 -ATOM 5433 H2 TIP3 7335 18.593 18.469 -9.736 0.417 1.000 -ATOM 5434 OH2 TIP3 7352 17.693 13.942 -7.250 -0.834 1.520 -ATOM 5435 H1 TIP3 7352 18.336 14.171 -6.505 0.417 1.000 -ATOM 5436 H2 TIP3 7352 16.961 14.518 -7.055 0.417 1.000 -ATOM 5437 OH2 TIP3 7374 14.785 14.606 -11.307 -0.834 1.520 -ATOM 5438 H1 TIP3 7374 14.825 14.231 -12.199 0.417 1.000 -ATOM 5439 H2 TIP3 7374 13.990 14.217 -10.910 0.417 1.000 -ATOM 5440 OH2 TIP3 7395 18.647 16.816 -10.714 -0.834 1.520 -ATOM 5441 H1 TIP3 7395 19.199 16.093 -11.008 0.417 1.000 -ATOM 5442 H2 TIP3 7395 17.955 16.462 -10.194 0.417 1.000 -ATOM 5443 OH2 TIP3 7437 16.637 -16.038 -6.827 -0.834 1.520 -ATOM 5444 H1 TIP3 7437 17.082 -15.250 -6.454 0.417 1.000 -ATOM 5445 H2 TIP3 7437 17.123 -16.088 -7.717 0.417 1.000 -ATOM 5446 OH2 TIP3 7479 -13.860 -16.331 -16.296 -0.834 1.520 -ATOM 5447 H1 TIP3 7479 -13.268 -16.163 -17.051 0.417 1.000 -ATOM 5448 H2 TIP3 7479 -13.193 -16.592 -15.622 0.417 1.000 -ATOM 5449 OH2 TIP3 7501 13.476 -15.160 -11.139 -0.834 1.520 -ATOM 5450 H1 TIP3 7501 13.896 -15.340 -10.325 0.417 1.000 -ATOM 5451 H2 TIP3 7501 13.229 -16.074 -11.329 0.417 1.000 -ATOM 5452 OH2 TIP3 7510 -14.850 -8.315 -8.006 -0.834 1.520 -ATOM 5453 H1 TIP3 7510 -14.688 -7.359 -7.980 0.417 1.000 -ATOM 5454 H2 TIP3 7510 -14.386 -8.595 -7.222 0.417 1.000 -ATOM 5455 OH2 TIP3 7525 12.999 -10.993 1.240 -0.834 1.520 -ATOM 5456 H1 TIP3 7525 12.490 -11.055 0.384 0.417 1.000 -ATOM 5457 H2 TIP3 7525 12.823 -11.900 1.616 0.417 1.000 -ATOM 5458 OH2 TIP3 7532 -18.993 -11.593 17.837 -0.834 1.520 -ATOM 5459 H1 TIP3 7532 -18.402 -12.206 17.369 0.417 1.000 -ATOM 5460 H2 TIP3 7532 -18.847 -11.855 18.765 0.417 1.000 -ATOM 5461 OH2 TIP3 7563 -14.804 -0.696 -4.685 -0.834 1.520 -ATOM 5462 H1 TIP3 7563 -14.773 0.213 -5.058 0.417 1.000 -ATOM 5463 H2 TIP3 7563 -14.748 -1.280 -5.431 0.417 1.000 -ATOM 5464 OH2 TIP3 7567 16.186 -4.390 -2.041 -0.834 1.520 -ATOM 5465 H1 TIP3 7567 15.536 -3.812 -2.525 0.417 1.000 -ATOM 5466 H2 TIP3 7567 15.630 -4.621 -1.255 0.417 1.000 -ATOM 5467 OH2 TIP3 7568 -16.319 -12.656 3.826 -0.834 1.520 -ATOM 5468 H1 TIP3 7568 -16.420 -12.533 4.764 0.417 1.000 -ATOM 5469 H2 TIP3 7568 -16.369 -11.739 3.500 0.417 1.000 -ATOM 5470 OH2 TIP3 7592 -15.391 4.656 13.926 -0.834 1.520 -ATOM 5471 H1 TIP3 7592 -15.711 5.189 14.710 0.417 1.000 -ATOM 5472 H2 TIP3 7592 -15.687 3.763 14.198 0.417 1.000 -ATOM 5473 OH2 TIP3 7603 -15.354 16.705 -14.461 -0.834 1.520 -ATOM 5474 H1 TIP3 7603 -16.194 17.258 -14.588 0.417 1.000 -ATOM 5475 H2 TIP3 7603 -14.904 16.891 -15.260 0.417 1.000 -ATOM 5476 OH2 TIP3 7605 -13.313 4.853 -9.652 -0.834 1.520 -ATOM 5477 H1 TIP3 7605 -12.412 4.883 -9.271 0.417 1.000 -ATOM 5478 H2 TIP3 7605 -13.156 4.632 -10.581 0.417 1.000 -ATOM 5479 OH2 TIP3 7612 19.974 -5.947 -0.977 -0.834 1.520 -ATOM 5480 H1 TIP3 7612 19.316 -6.427 -1.528 0.417 1.000 -ATOM 5481 H2 TIP3 7612 19.402 -5.571 -0.386 0.417 1.000 -ATOM 5482 OH2 TIP3 7630 -17.821 -6.536 -12.823 -0.834 1.520 -ATOM 5483 H1 TIP3 7630 -17.281 -5.939 -12.263 0.417 1.000 -ATOM 5484 H2 TIP3 7630 -18.360 -6.979 -12.157 0.417 1.000 -ATOM 5485 OH2 TIP3 7631 -18.074 1.439 -2.973 -0.834 1.520 -ATOM 5486 H1 TIP3 7631 -17.328 1.817 -3.455 0.417 1.000 -ATOM 5487 H2 TIP3 7631 -17.602 0.912 -2.338 0.417 1.000 -ATOM 5488 OH2 TIP3 7634 -16.686 -8.049 13.268 -0.834 1.520 -ATOM 5489 H1 TIP3 7634 -16.819 -7.663 12.373 0.417 1.000 -ATOM 5490 H2 TIP3 7634 -15.934 -8.600 13.009 0.417 1.000 -ATOM 5491 OH2 TIP3 7643 15.653 5.857 -16.046 -0.834 1.520 -ATOM 5492 H1 TIP3 7643 15.956 6.183 -15.187 0.417 1.000 -ATOM 5493 H2 TIP3 7643 16.136 6.461 -16.642 0.417 1.000 -ATOM 5494 OH2 TIP3 7647 -18.693 5.327 -9.867 -0.834 1.520 -ATOM 5495 H1 TIP3 7647 -17.748 5.463 -9.923 0.417 1.000 -ATOM 5496 H2 TIP3 7647 -18.878 4.555 -10.528 0.417 1.000 -ATOM 5497 OH2 TIP3 7650 -15.902 7.516 -15.559 -0.834 1.520 -ATOM 5498 H1 TIP3 7650 -16.131 6.827 -14.935 0.417 1.000 -ATOM 5499 H2 TIP3 7650 -14.916 7.574 -15.407 0.417 1.000 -ATOM 5500 OH2 TIP3 7661 -16.960 -4.174 17.777 -0.834 1.520 -ATOM 5501 H1 TIP3 7661 -17.448 -3.363 17.476 0.417 1.000 -ATOM 5502 H2 TIP3 7661 -17.726 -4.788 18.160 0.417 1.000 -ATOM 5503 OH2 TIP3 7668 12.031 6.248 -6.222 -0.834 1.520 -ATOM 5504 H1 TIP3 7668 11.580 7.134 -6.055 0.417 1.000 -ATOM 5505 H2 TIP3 7668 12.425 6.036 -5.354 0.417 1.000 -ATOM 5506 OH2 TIP3 7676 -12.967 -8.515 11.967 -0.834 1.520 -ATOM 5507 H1 TIP3 7676 -12.071 -8.669 12.292 0.417 1.000 -ATOM 5508 H2 TIP3 7676 -13.455 -9.240 12.326 0.417 1.000 -ATOM 5509 OH2 TIP3 7690 13.776 4.452 -14.397 -0.834 1.520 -ATOM 5510 H1 TIP3 7690 14.121 4.657 -15.315 0.417 1.000 -ATOM 5511 H2 TIP3 7690 13.743 5.307 -13.945 0.417 1.000 -ATOM 5512 OH2 TIP3 7707 -19.312 -17.219 -12.886 -0.834 1.520 -ATOM 5513 H1 TIP3 7707 -18.512 -16.810 -13.297 0.417 1.000 -ATOM 5514 H2 TIP3 7707 -19.947 -16.571 -13.070 0.417 1.000 -ATOM 5515 OH2 TIP3 7715 -17.093 18.455 2.007 -0.834 1.520 -ATOM 5516 H1 TIP3 7715 -17.451 18.286 2.898 0.417 1.000 -ATOM 5517 H2 TIP3 7715 -16.597 19.349 2.100 0.417 1.000 -ATOM 5518 OH2 TIP3 7716 -12.598 8.660 -9.639 -0.834 1.520 -ATOM 5519 H1 TIP3 7716 -13.391 9.153 -9.466 0.417 1.000 -ATOM 5520 H2 TIP3 7716 -12.363 8.912 -10.514 0.417 1.000 -ATOM 5521 OH2 TIP3 7739 -15.403 3.385 2.279 -0.834 1.520 -ATOM 5522 H1 TIP3 7739 -16.085 3.520 1.604 0.417 1.000 -ATOM 5523 H2 TIP3 7739 -15.588 4.142 2.857 0.417 1.000 -ATOM 5524 OH2 TIP3 7748 -18.613 12.752 -18.148 -0.834 1.520 -ATOM 5525 H1 TIP3 7748 -17.761 12.757 -18.474 0.417 1.000 -ATOM 5526 H2 TIP3 7748 -18.484 12.728 -17.200 0.417 1.000 -ATOM 5527 OH2 TIP3 7860 17.007 -4.910 8.251 -0.834 1.520 -ATOM 5528 H1 TIP3 7860 16.296 -5.590 8.477 0.417 1.000 -ATOM 5529 H2 TIP3 7860 16.957 -4.922 7.278 0.417 1.000 -ATOM 5530 OH2 TIP3 7904 19.140 -19.452 9.228 -0.834 1.520 -ATOM 5531 H1 TIP3 7904 18.639 -19.941 8.527 0.417 1.000 -ATOM 5532 H2 TIP3 7904 19.818 -18.903 8.770 0.417 1.000 -ATOM 5533 OH2 TIP3 7945 -10.765 -14.413 3.329 -0.834 1.520 -ATOM 5534 H1 TIP3 7945 -10.542 -13.865 4.099 0.417 1.000 -ATOM 5535 H2 TIP3 7945 -11.515 -13.869 2.972 0.417 1.000 -ATOM 5536 OH2 TIP3 7951 -16.555 -16.133 18.949 -0.834 1.520 -ATOM 5537 H1 TIP3 7951 -16.199 -16.682 18.209 0.417 1.000 -ATOM 5538 H2 TIP3 7951 -16.814 -16.782 19.626 0.417 1.000 -ATOM 5539 OH2 TIP3 7964 17.329 -0.581 -5.197 -0.834 1.520 -ATOM 5540 H1 TIP3 7964 18.207 -0.712 -4.713 0.417 1.000 -ATOM 5541 H2 TIP3 7964 17.005 -1.481 -5.308 0.417 1.000 -ATOM 5542 OH2 TIP3 7985 -19.551 -12.634 -10.860 -0.834 1.520 -ATOM 5543 H1 TIP3 7985 -19.798 -13.521 -10.905 0.417 1.000 -ATOM 5544 H2 TIP3 7985 -19.204 -12.437 -11.744 0.417 1.000 -ATOM 5545 OH2 TIP3 8014 -16.496 1.790 14.010 -0.834 1.520 -ATOM 5546 H1 TIP3 8014 -15.973 1.570 13.237 0.417 1.000 -ATOM 5547 H2 TIP3 8014 -17.156 2.371 13.635 0.417 1.000 -ATOM 5548 OH2 TIP3 8023 -19.087 -7.680 -19.063 -0.834 1.520 -ATOM 5549 H1 TIP3 8023 -19.377 -8.300 -19.732 0.417 1.000 -ATOM 5550 H2 TIP3 8023 -18.710 -8.216 -18.372 0.417 1.000 -ATOM 5551 OH2 TIP3 8024 -15.891 5.989 -9.851 -0.834 1.520 -ATOM 5552 H1 TIP3 8024 -14.997 5.645 -9.650 0.417 1.000 -ATOM 5553 H2 TIP3 8024 -15.683 6.768 -10.417 0.417 1.000 -ATOM 5554 OH2 TIP3 8029 -12.111 -3.003 -5.640 -0.834 1.520 -ATOM 5555 H1 TIP3 8029 -12.065 -2.819 -6.642 0.417 1.000 -ATOM 5556 H2 TIP3 8029 -11.398 -2.438 -5.266 0.417 1.000 -ATOM 5557 OH2 TIP3 8046 -16.770 2.882 -8.264 -0.834 1.520 -ATOM 5558 H1 TIP3 8046 -16.399 1.950 -8.330 0.417 1.000 -ATOM 5559 H2 TIP3 8046 -17.139 2.992 -9.147 0.417 1.000 -ATOM 5560 OH2 TIP3 8055 -13.838 -2.289 15.087 -0.834 1.520 -ATOM 5561 H1 TIP3 8055 -13.356 -2.334 15.913 0.417 1.000 -ATOM 5562 H2 TIP3 8055 -13.434 -1.507 14.651 0.417 1.000 -ATOM 5563 OH2 TIP3 8064 -15.380 2.335 -12.870 -0.834 1.520 -ATOM 5564 H1 TIP3 8064 -16.246 2.591 -12.410 0.417 1.000 -ATOM 5565 H2 TIP3 8064 -14.822 2.349 -12.093 0.417 1.000 -ATOM 5566 OH2 TIP3 8067 -18.478 9.688 -5.200 -0.834 1.520 -ATOM 5567 H1 TIP3 8067 -18.476 10.417 -5.842 0.417 1.000 -ATOM 5568 H2 TIP3 8067 -17.570 9.403 -4.980 0.417 1.000 -ATOM 5569 OH2 TIP3 8068 -18.876 2.962 -6.486 -0.834 1.520 -ATOM 5570 H1 TIP3 8068 -18.163 2.901 -7.140 0.417 1.000 -ATOM 5571 H2 TIP3 8068 -19.315 3.799 -6.690 0.417 1.000 -ATOM 5572 OH2 TIP3 8070 13.465 -12.498 -12.880 -0.834 1.520 -ATOM 5573 H1 TIP3 8070 13.340 -12.871 -13.808 0.417 1.000 -ATOM 5574 H2 TIP3 8070 13.740 -13.267 -12.324 0.417 1.000 -ATOM 5575 OH2 TIP3 8073 16.526 -2.619 9.510 -0.834 1.520 -ATOM 5576 H1 TIP3 8073 16.955 -3.347 9.033 0.417 1.000 -ATOM 5577 H2 TIP3 8073 16.593 -2.909 10.428 0.417 1.000 -ATOM 5578 OH2 TIP3 8076 -12.634 4.266 8.891 -0.834 1.520 -ATOM 5579 H1 TIP3 8076 -13.480 4.258 9.415 0.417 1.000 -ATOM 5580 H2 TIP3 8076 -12.923 3.998 7.984 0.417 1.000 -ATOM 5581 OH2 TIP3 8094 -11.265 4.622 18.928 -0.834 1.520 -ATOM 5582 H1 TIP3 8094 -10.531 4.022 18.715 0.417 1.000 -ATOM 5583 H2 TIP3 8094 -11.728 4.616 18.104 0.417 1.000 -ATOM 5584 OH2 TIP3 8133 -18.962 9.805 4.340 -0.834 1.520 -ATOM 5585 H1 TIP3 8133 -18.822 8.861 4.127 0.417 1.000 -ATOM 5586 H2 TIP3 8133 -19.353 9.734 5.231 0.417 1.000 -ATOM 5587 OH2 TIP3 8136 -18.586 11.430 -7.698 -0.834 1.520 -ATOM 5588 H1 TIP3 8136 -17.925 10.965 -8.249 0.417 1.000 -ATOM 5589 H2 TIP3 8136 -18.258 12.354 -7.659 0.417 1.000 -ATOM 5590 OH2 TIP3 8174 -17.237 6.896 -7.696 -0.834 1.520 -ATOM 5591 H1 TIP3 8174 -16.599 6.364 -8.255 0.417 1.000 -ATOM 5592 H2 TIP3 8174 -17.249 7.725 -8.141 0.417 1.000 -ATOM 5593 OH2 TIP3 8176 -15.886 13.989 8.277 -0.834 1.520 -ATOM 5594 H1 TIP3 8176 -15.618 14.939 8.099 0.417 1.000 -ATOM 5595 H2 TIP3 8176 -15.653 13.906 9.206 0.417 1.000 -ATOM 5596 OH2 TIP3 8185 17.580 6.104 16.715 -0.834 1.520 -ATOM 5597 H1 TIP3 8185 16.808 5.636 16.356 0.417 1.000 -ATOM 5598 H2 TIP3 8185 17.695 5.614 17.578 0.417 1.000 -ATOM 5599 OH2 TIP3 8193 -18.204 15.376 -13.042 -0.834 1.520 -ATOM 5600 H1 TIP3 8193 -19.138 15.378 -13.378 0.417 1.000 -ATOM 5601 H2 TIP3 8193 -17.818 16.170 -13.647 0.417 1.000 -ATOM 5602 OH2 TIP3 8206 -9.087 6.333 19.362 -0.834 1.520 -ATOM 5603 H1 TIP3 8206 -9.778 5.705 19.171 0.417 1.000 -ATOM 5604 H2 TIP3 8206 -8.496 5.710 19.872 0.417 1.000 -ATOM 5605 OH2 TIP3 8222 -15.523 19.384 14.416 -0.834 1.520 -ATOM 5606 H1 TIP3 8222 -15.396 18.706 13.741 0.417 1.000 -ATOM 5607 H2 TIP3 8222 -15.890 18.813 15.147 0.417 1.000 -ATOM 5608 OH2 TIP3 8242 -5.562 18.821 0.722 -0.834 1.520 -ATOM 5609 H1 TIP3 8242 -4.820 18.250 0.442 0.417 1.000 -ATOM 5610 H2 TIP3 8242 -6.254 18.198 1.081 0.417 1.000 -ATOM 5611 OH2 TIP3 8263 -16.761 16.744 8.122 -0.834 1.520 -ATOM 5612 H1 TIP3 8263 -17.393 16.352 8.722 0.417 1.000 -ATOM 5613 H2 TIP3 8263 -17.291 17.003 7.327 0.417 1.000 -ATOM 5614 OH2 TIP3 8265 -17.940 14.822 17.197 -0.834 1.520 -ATOM 5615 H1 TIP3 8265 -18.139 15.621 17.663 0.417 1.000 -ATOM 5616 H2 TIP3 8265 -16.981 14.885 17.279 0.417 1.000 -ATOM 5617 OH2 TIP3 8326 18.000 -15.488 7.686 -0.834 1.520 -ATOM 5618 H1 TIP3 8326 17.605 -16.367 7.423 0.417 1.000 -ATOM 5619 H2 TIP3 8326 17.181 -14.998 7.900 0.417 1.000 -ATOM 5620 OH2 TIP3 8364 -11.439 -9.076 -3.119 -0.834 1.520 -ATOM 5621 H1 TIP3 8364 -12.084 -8.812 -3.798 0.417 1.000 -ATOM 5622 H2 TIP3 8364 -11.691 -9.992 -2.877 0.417 1.000 -ATOM 5623 OH2 TIP3 8370 -3.988 -15.932 4.241 -0.834 1.520 -ATOM 5624 H1 TIP3 8370 -3.379 -16.214 3.521 0.417 1.000 -ATOM 5625 H2 TIP3 8370 -3.445 -15.992 5.013 0.417 1.000 -ATOM 5626 OH2 TIP3 8394 -11.010 -12.369 16.752 -0.834 1.520 -ATOM 5627 H1 TIP3 8394 -10.423 -11.699 17.070 0.417 1.000 -ATOM 5628 H2 TIP3 8394 -11.840 -12.279 17.323 0.417 1.000 -ATOM 5629 OH2 TIP3 8403 -15.249 -0.991 -17.186 -0.834 1.520 -ATOM 5630 H1 TIP3 8403 -15.246 -1.022 -16.240 0.417 1.000 -ATOM 5631 H2 TIP3 8403 -14.700 -1.694 -17.388 0.417 1.000 -ATOM 5632 OH2 TIP3 8408 -19.409 -15.347 5.328 -0.834 1.520 -ATOM 5633 H1 TIP3 8408 -19.253 -15.507 4.381 0.417 1.000 -ATOM 5634 H2 TIP3 8408 -18.744 -15.897 5.785 0.417 1.000 -ATOM 5635 OH2 TIP3 8409 13.953 -13.595 2.441 -0.834 1.520 -ATOM 5636 H1 TIP3 8409 14.304 -14.391 1.938 0.417 1.000 -ATOM 5637 H2 TIP3 8409 14.567 -12.876 2.197 0.417 1.000 -ATOM 5638 OH2 TIP3 8411 -16.594 -19.883 -5.507 -0.834 1.520 -ATOM 5639 H1 TIP3 8411 -16.652 -19.756 -6.454 0.417 1.000 -ATOM 5640 H2 TIP3 8411 -15.622 -19.810 -5.276 0.417 1.000 -ATOM 5641 OH2 TIP3 8412 -11.831 -17.863 17.598 -0.834 1.520 -ATOM 5642 H1 TIP3 8412 -11.739 -16.914 17.790 0.417 1.000 -ATOM 5643 H2 TIP3 8412 -12.095 -17.832 16.631 0.417 1.000 -ATOM 5644 OH2 TIP3 8425 -17.722 -16.078 -18.800 -0.834 1.520 -ATOM 5645 H1 TIP3 8425 -17.299 -16.608 -19.440 0.417 1.000 -ATOM 5646 H2 TIP3 8425 -18.444 -16.594 -18.585 0.417 1.000 -ATOM 5647 OH2 TIP3 8441 -13.754 1.216 -6.436 -0.834 1.520 -ATOM 5648 H1 TIP3 8441 -12.873 1.533 -6.206 0.417 1.000 -ATOM 5649 H2 TIP3 8441 -14.198 2.075 -6.545 0.417 1.000 -ATOM 5650 OH2 TIP3 8448 -19.584 -0.598 6.409 -0.834 1.520 -ATOM 5651 H1 TIP3 8448 -18.628 -0.288 6.262 0.417 1.000 -ATOM 5652 H2 TIP3 8448 -19.472 -1.461 6.599 0.417 1.000 -ATOM 5653 OH2 TIP3 8457 -10.564 -4.268 12.393 -0.834 1.520 -ATOM 5654 H1 TIP3 8457 -11.188 -4.698 12.981 0.417 1.000 -ATOM 5655 H2 TIP3 8457 -9.713 -4.285 12.899 0.417 1.000 -ATOM 5656 OH2 TIP3 8462 18.064 0.344 -9.343 -0.834 1.520 -ATOM 5657 H1 TIP3 8462 18.211 -0.518 -8.908 0.417 1.000 -ATOM 5658 H2 TIP3 8462 17.319 0.197 -10.027 0.417 1.000 -ATOM 5659 OH2 TIP3 8466 -14.652 -4.541 -14.012 -0.834 1.520 -ATOM 5660 H1 TIP3 8466 -15.058 -3.789 -13.535 0.417 1.000 -ATOM 5661 H2 TIP3 8466 -15.036 -5.321 -13.578 0.417 1.000 -ATOM 5662 OH2 TIP3 8468 -18.688 -6.423 -6.171 -0.834 1.520 -ATOM 5663 H1 TIP3 8468 -18.406 -6.650 -7.037 0.417 1.000 -ATOM 5664 H2 TIP3 8468 -19.095 -5.557 -6.366 0.417 1.000 -ATOM 5665 OH2 TIP3 8491 -9.605 1.375 2.397 -0.834 1.520 -ATOM 5666 H1 TIP3 8491 -9.100 0.680 2.794 0.417 1.000 -ATOM 5667 H2 TIP3 8491 -9.318 2.154 2.828 0.417 1.000 -ATOM 5668 OH2 TIP3 8492 -18.407 3.215 12.879 -0.834 1.520 -ATOM 5669 H1 TIP3 8492 -19.142 3.389 13.452 0.417 1.000 -ATOM 5670 H2 TIP3 8492 -18.801 3.016 12.034 0.417 1.000 -ATOM 5671 OH2 TIP3 8509 19.685 -15.552 -13.837 -0.834 1.520 -ATOM 5672 H1 TIP3 8509 19.380 -15.628 -12.919 0.417 1.000 -ATOM 5673 H2 TIP3 8509 19.772 -16.432 -14.133 0.417 1.000 -ATOM 5674 OH2 TIP3 8528 -13.987 -3.915 -16.674 -0.834 1.520 -ATOM 5675 H1 TIP3 8528 -13.984 -3.965 -15.708 0.417 1.000 -ATOM 5676 H2 TIP3 8528 -14.751 -4.484 -16.954 0.417 1.000 -ATOM 5677 OH2 TIP3 8534 -17.816 2.110 -10.500 -0.834 1.520 -ATOM 5678 H1 TIP3 8534 -18.087 1.297 -10.002 0.417 1.000 -ATOM 5679 H2 TIP3 8534 -18.611 2.233 -11.036 0.417 1.000 -ATOM 5680 OH2 TIP3 8536 -16.793 -6.021 -2.228 -0.834 1.520 -ATOM 5681 H1 TIP3 8536 -16.053 -5.918 -1.627 0.417 1.000 -ATOM 5682 H2 TIP3 8536 -17.415 -5.315 -2.079 0.417 1.000 -ATOM 5683 OH2 TIP3 8548 -6.361 -3.902 -14.731 -0.834 1.520 -ATOM 5684 H1 TIP3 8548 -5.901 -4.606 -15.128 0.417 1.000 -ATOM 5685 H2 TIP3 8548 -7.245 -4.276 -14.657 0.417 1.000 -ATOM 5686 OH2 TIP3 8549 -15.402 8.408 -1.681 -0.834 1.520 -ATOM 5687 H1 TIP3 8549 -15.331 8.317 -2.645 0.417 1.000 -ATOM 5688 H2 TIP3 8549 -14.610 7.828 -1.358 0.417 1.000 -ATOM 5689 OH2 TIP3 8551 -13.816 14.140 -15.946 -0.834 1.520 -ATOM 5690 H1 TIP3 8551 -14.257 14.819 -16.528 0.417 1.000 -ATOM 5691 H2 TIP3 8551 -14.494 13.825 -15.380 0.417 1.000 -ATOM 5692 OH2 TIP3 8555 -13.816 1.625 4.372 -0.834 1.520 -ATOM 5693 H1 TIP3 8555 -14.369 1.179 3.798 0.417 1.000 -ATOM 5694 H2 TIP3 8555 -14.042 1.386 5.308 0.417 1.000 -ATOM 5695 OH2 TIP3 8556 -18.019 -3.365 -1.337 -0.834 1.520 -ATOM 5696 H1 TIP3 8556 -18.079 -2.819 -0.471 0.417 1.000 -ATOM 5697 H2 TIP3 8556 -17.344 -2.883 -1.844 0.417 1.000 -ATOM 5698 OH2 TIP3 8558 -17.987 5.789 -5.125 -0.834 1.520 -ATOM 5699 H1 TIP3 8558 -18.922 5.523 -4.994 0.417 1.000 -ATOM 5700 H2 TIP3 8558 -17.882 6.044 -6.077 0.417 1.000 -ATOM 5701 OH2 TIP3 8566 -18.671 3.741 17.937 -0.834 1.520 -ATOM 5702 H1 TIP3 8566 -18.831 3.178 17.166 0.417 1.000 -ATOM 5703 H2 TIP3 8566 -19.277 4.496 17.762 0.417 1.000 -ATOM 5704 OH2 TIP3 8574 -15.893 8.282 -4.761 -0.834 1.520 -ATOM 5705 H1 TIP3 8574 -15.023 8.023 -5.218 0.417 1.000 -ATOM 5706 H2 TIP3 8574 -16.446 7.530 -4.982 0.417 1.000 -ATOM 5707 OH2 TIP3 8576 -9.957 16.852 -6.288 -0.834 1.520 -ATOM 5708 H1 TIP3 8576 -9.172 17.292 -5.846 0.417 1.000 -ATOM 5709 H2 TIP3 8576 -10.671 17.362 -6.055 0.417 1.000 -ATOM 5710 OH2 TIP3 8578 -13.604 18.881 5.021 -0.834 1.520 -ATOM 5711 H1 TIP3 8578 -13.286 18.520 4.184 0.417 1.000 -ATOM 5712 H2 TIP3 8578 -13.507 18.150 5.663 0.417 1.000 -ATOM 5713 OH2 TIP3 8579 -13.792 10.748 6.763 -0.834 1.520 -ATOM 5714 H1 TIP3 8579 -13.747 11.642 6.366 0.417 1.000 -ATOM 5715 H2 TIP3 8579 -14.788 10.523 6.975 0.417 1.000 -ATOM 5716 OH2 TIP3 8600 -14.632 7.922 11.937 -0.834 1.520 -ATOM 5717 H1 TIP3 8600 -15.523 7.601 12.188 0.417 1.000 -ATOM 5718 H2 TIP3 8600 -14.616 7.715 11.037 0.417 1.000 -ATOM 5719 OH2 TIP3 8613 -11.883 13.380 -17.732 -0.834 1.520 -ATOM 5720 H1 TIP3 8613 -12.415 13.594 -17.008 0.417 1.000 -ATOM 5721 H2 TIP3 8613 -11.143 14.005 -17.527 0.417 1.000 -ATOM 5722 OH2 TIP3 8617 -11.864 17.527 -12.535 -0.834 1.520 -ATOM 5723 H1 TIP3 8617 -12.147 18.042 -11.719 0.417 1.000 -ATOM 5724 H2 TIP3 8617 -11.347 16.807 -12.108 0.417 1.000 -ATOM 5725 OH2 TIP3 8642 -15.194 15.050 16.989 -0.834 1.520 -ATOM 5726 H1 TIP3 8642 -14.868 14.161 16.565 0.417 1.000 -ATOM 5727 H2 TIP3 8642 -14.869 15.693 16.374 0.417 1.000 -ATOM 5728 OH2 TIP3 8645 -19.641 9.801 6.958 -0.834 1.520 -ATOM 5729 H1 TIP3 8645 -19.967 9.183 7.647 0.417 1.000 -ATOM 5730 H2 TIP3 8645 -19.944 10.709 7.128 0.417 1.000 -ATOM 5731 OH2 TIP3 8653 -18.572 19.027 -17.845 -0.834 1.520 -ATOM 5732 H1 TIP3 8653 -18.507 19.600 -16.989 0.417 1.000 -ATOM 5733 H2 TIP3 8653 -18.462 18.186 -17.492 0.417 1.000 -ATOM 5734 OH2 TIP3 8658 -17.830 18.392 16.274 -0.834 1.520 -ATOM 5735 H1 TIP3 8658 -18.417 17.888 15.662 0.417 1.000 -ATOM 5736 H2 TIP3 8658 -18.289 19.231 16.405 0.417 1.000 -ATOM 5737 OH2 TIP3 8679 -17.787 17.935 -14.357 -0.834 1.520 -ATOM 5738 H1 TIP3 8679 -17.845 18.521 -13.599 0.417 1.000 -ATOM 5739 H2 TIP3 8679 -17.927 18.558 -15.075 0.417 1.000 -ATOM 5740 OH2 TIP3 8683 -19.503 15.881 1.658 -0.834 1.520 -ATOM 5741 H1 TIP3 8683 -19.764 15.928 0.778 0.417 1.000 -ATOM 5742 H2 TIP3 8683 -18.803 16.514 1.645 0.417 1.000 -ATOM 5743 OH2 TIP3 8687 -18.370 12.397 18.570 -0.834 1.520 -ATOM 5744 H1 TIP3 8687 -18.137 13.066 17.921 0.417 1.000 -ATOM 5745 H2 TIP3 8687 -18.953 12.857 19.192 0.417 1.000 -ATOM 5746 OH2 TIP3 8760 -6.543 0.491 -13.455 -0.834 1.520 -ATOM 5747 H1 TIP3 8760 -6.456 -0.287 -13.041 0.417 1.000 -ATOM 5748 H2 TIP3 8760 -6.801 0.170 -14.399 0.417 1.000 -ATOM 5749 OH2 TIP3 8780 -16.562 -11.901 -19.684 -0.834 1.520 -ATOM 5750 H1 TIP3 8780 -17.453 -12.153 -19.423 0.417 1.000 -ATOM 5751 H2 TIP3 8780 -16.111 -12.225 -18.907 0.417 1.000 -ATOM 5752 OH2 TIP3 8801 -10.984 -4.310 -10.515 -0.834 1.520 -ATOM 5753 H1 TIP3 8801 -10.842 -5.231 -10.299 0.417 1.000 -ATOM 5754 H2 TIP3 8801 -11.463 -4.446 -11.348 0.417 1.000 -ATOM 5755 OH2 TIP3 8813 -15.406 -7.857 16.989 -0.834 1.520 -ATOM 5756 H1 TIP3 8813 -15.792 -7.901 17.928 0.417 1.000 -ATOM 5757 H2 TIP3 8813 -16.238 -7.910 16.469 0.417 1.000 -ATOM 5758 OH2 TIP3 8822 -18.438 -13.464 -7.761 -0.834 1.520 -ATOM 5759 H1 TIP3 8822 -19.040 -12.750 -7.951 0.417 1.000 -ATOM 5760 H2 TIP3 8822 -18.803 -14.173 -8.447 0.417 1.000 -ATOM 5761 OH2 TIP3 8829 -18.686 -10.615 -12.827 -0.834 1.520 -ATOM 5762 H1 TIP3 8829 -18.667 -11.294 -13.556 0.417 1.000 -ATOM 5763 H2 TIP3 8829 -17.944 -10.047 -13.020 0.417 1.000 -ATOM 5764 OH2 TIP3 8833 -17.737 -17.660 10.533 -0.834 1.520 -ATOM 5765 H1 TIP3 8833 -18.006 -18.249 11.233 0.417 1.000 -ATOM 5766 H2 TIP3 8833 -18.591 -17.118 10.429 0.417 1.000 -ATOM 5767 OH2 TIP3 8843 -12.428 -19.580 -16.522 -0.834 1.520 -ATOM 5768 H1 TIP3 8843 -12.364 -19.661 -17.497 0.417 1.000 -ATOM 5769 H2 TIP3 8843 -13.372 -19.766 -16.470 0.417 1.000 -ATOM 5770 OH2 TIP3 8845 -18.867 -12.920 -14.922 -0.834 1.520 -ATOM 5771 H1 TIP3 8845 -18.799 -12.898 -15.863 0.417 1.000 -ATOM 5772 H2 TIP3 8845 -19.642 -13.451 -14.698 0.417 1.000 -ATOM 5773 OH2 TIP3 8848 -9.416 -16.789 7.118 -0.834 1.520 -ATOM 5774 H1 TIP3 8848 -8.820 -16.008 6.914 0.417 1.000 -ATOM 5775 H2 TIP3 8848 -10.016 -16.742 6.356 0.417 1.000 -ATOM 5776 OH2 TIP3 8852 -6.754 -10.545 5.397 -0.834 1.520 -ATOM 5777 H1 TIP3 8852 -6.003 -10.112 5.829 0.417 1.000 -ATOM 5778 H2 TIP3 8852 -6.414 -11.026 4.659 0.417 1.000 -ATOM 5779 OH2 TIP3 8865 -8.485 2.342 -15.173 -0.834 1.520 -ATOM 5780 H1 TIP3 8865 -9.125 1.911 -15.815 0.417 1.000 -ATOM 5781 H2 TIP3 8865 -8.795 1.919 -14.306 0.417 1.000 -ATOM 5782 OH2 TIP3 8869 -14.721 -14.245 -8.543 -0.834 1.520 -ATOM 5783 H1 TIP3 8869 -15.496 -14.667 -9.033 0.417 1.000 -ATOM 5784 H2 TIP3 8869 -14.436 -15.014 -7.981 0.417 1.000 -ATOM 5785 OH2 TIP3 8870 -19.092 -7.587 5.925 -0.834 1.520 -ATOM 5786 H1 TIP3 8870 -19.146 -6.699 5.615 0.417 1.000 -ATOM 5787 H2 TIP3 8870 -19.982 -7.938 5.781 0.417 1.000 -ATOM 5788 OH2 TIP3 8886 9.059 -3.202 -14.555 -0.834 1.520 -ATOM 5789 H1 TIP3 8886 8.687 -2.745 -13.761 0.417 1.000 -ATOM 5790 H2 TIP3 8886 9.347 -2.472 -15.130 0.417 1.000 -ATOM 5791 OH2 TIP3 8887 -11.110 1.041 -3.930 -0.834 1.520 -ATOM 5792 H1 TIP3 8887 -11.302 1.572 -4.700 0.417 1.000 -ATOM 5793 H2 TIP3 8887 -10.200 1.340 -3.756 0.417 1.000 -ATOM 5794 OH2 TIP3 8895 -14.000 -8.717 2.324 -0.834 1.520 -ATOM 5795 H1 TIP3 8895 -14.134 -7.943 2.939 0.417 1.000 -ATOM 5796 H2 TIP3 8895 -14.137 -8.366 1.452 0.417 1.000 -ATOM 5797 OH2 TIP3 8898 -10.631 -6.093 17.857 -0.834 1.520 -ATOM 5798 H1 TIP3 8898 -9.953 -6.488 18.378 0.417 1.000 -ATOM 5799 H2 TIP3 8898 -11.386 -5.956 18.509 0.417 1.000 -ATOM 5800 OH2 TIP3 8903 -3.672 -18.849 -14.215 -0.834 1.520 -ATOM 5801 H1 TIP3 8903 -2.908 -19.461 -14.122 0.417 1.000 -ATOM 5802 H2 TIP3 8903 -4.404 -19.365 -13.851 0.417 1.000 -ATOM 5803 OH2 TIP3 8905 -12.166 -5.592 -12.473 -0.834 1.520 -ATOM 5804 H1 TIP3 8905 -12.895 -5.283 -13.007 0.417 1.000 -ATOM 5805 H2 TIP3 8905 -11.806 -6.286 -13.074 0.417 1.000 -ATOM 5806 OH2 TIP3 8908 -10.655 11.960 -14.096 -0.834 1.520 -ATOM 5807 H1 TIP3 8908 -10.512 11.566 -13.167 0.417 1.000 -ATOM 5808 H2 TIP3 8908 -11.101 12.828 -13.960 0.417 1.000 -ATOM 5809 OH2 TIP3 8918 -11.744 -0.880 13.820 -0.834 1.520 -ATOM 5810 H1 TIP3 8918 -10.977 -1.321 13.483 0.417 1.000 -ATOM 5811 H2 TIP3 8918 -11.615 0.026 13.600 0.417 1.000 -ATOM 5812 OH2 TIP3 8926 -9.781 5.985 -14.833 -0.834 1.520 -ATOM 5813 H1 TIP3 8926 -9.309 5.282 -15.221 0.417 1.000 -ATOM 5814 H2 TIP3 8926 -9.651 5.758 -13.869 0.417 1.000 -ATOM 5815 OH2 TIP3 8927 -15.351 7.814 -11.678 -0.834 1.520 -ATOM 5816 H1 TIP3 8927 -14.731 8.535 -11.993 0.417 1.000 -ATOM 5817 H2 TIP3 8927 -16.228 8.055 -12.040 0.417 1.000 -ATOM 5818 OH2 TIP3 8928 -14.358 -6.559 7.230 -0.834 1.520 -ATOM 5819 H1 TIP3 8928 -14.171 -5.615 7.385 0.417 1.000 -ATOM 5820 H2 TIP3 8928 -13.841 -7.091 7.879 0.417 1.000 -ATOM 5821 OH2 TIP3 8931 -14.333 -8.188 -0.458 -0.834 1.520 -ATOM 5822 H1 TIP3 8931 -14.353 -7.257 -0.503 0.417 1.000 -ATOM 5823 H2 TIP3 8931 -14.111 -8.371 -1.382 0.417 1.000 -ATOM 5824 OH2 TIP3 8932 -7.003 -1.424 -4.793 -0.834 1.520 -ATOM 5825 H1 TIP3 8932 -7.383 -0.807 -5.507 0.417 1.000 -ATOM 5826 H2 TIP3 8932 -6.418 -0.837 -4.263 0.417 1.000 -ATOM 5827 OH2 TIP3 8935 -19.325 -8.426 -9.048 -0.834 1.520 -ATOM 5828 H1 TIP3 8935 -18.403 -8.454 -9.426 0.417 1.000 -ATOM 5829 H2 TIP3 8935 -19.735 -7.850 -9.661 0.417 1.000 -ATOM 5830 OH2 TIP3 8939 -18.020 -3.708 12.037 -0.834 1.520 -ATOM 5831 H1 TIP3 8939 -17.556 -4.251 12.703 0.417 1.000 -ATOM 5832 H2 TIP3 8939 -18.505 -3.002 12.564 0.417 1.000 -ATOM 5833 OH2 TIP3 8940 -14.210 -10.768 13.382 -0.834 1.520 -ATOM 5834 H1 TIP3 8940 -15.013 -11.368 13.560 0.417 1.000 -ATOM 5835 H2 TIP3 8940 -13.414 -11.201 13.717 0.417 1.000 -ATOM 5836 OH2 TIP3 8949 -11.218 -2.813 -17.638 -0.834 1.520 -ATOM 5837 H1 TIP3 8949 -11.996 -3.214 -17.203 0.417 1.000 -ATOM 5838 H2 TIP3 8949 -10.860 -3.578 -18.030 0.417 1.000 -ATOM 5839 OH2 TIP3 8952 -12.407 -10.504 3.616 -0.834 1.520 -ATOM 5840 H1 TIP3 8952 -11.904 -9.827 4.113 0.417 1.000 -ATOM 5841 H2 TIP3 8952 -13.032 -9.951 3.068 0.417 1.000 -ATOM 5842 OH2 TIP3 8954 -13.610 9.666 -12.829 -0.834 1.520 -ATOM 5843 H1 TIP3 8954 -13.211 9.750 -13.709 0.417 1.000 -ATOM 5844 H2 TIP3 8954 -14.087 10.472 -12.758 0.417 1.000 -ATOM 5845 OH2 TIP3 8956 -17.887 -13.484 1.893 -0.834 1.520 -ATOM 5846 H1 TIP3 8956 -17.830 -14.424 2.160 0.417 1.000 -ATOM 5847 H2 TIP3 8956 -17.554 -13.051 2.707 0.417 1.000 -ATOM 5848 OH2 TIP3 8960 -17.255 -8.754 19.163 -0.834 1.520 -ATOM 5849 H1 TIP3 8960 -17.698 -9.363 18.623 0.417 1.000 -ATOM 5850 H2 TIP3 8960 -17.868 -8.584 19.860 0.417 1.000 -ATOM 5851 OH2 TIP3 8961 -8.111 -11.830 15.099 -0.834 1.520 -ATOM 5852 H1 TIP3 8961 -7.310 -11.399 14.804 0.417 1.000 -ATOM 5853 H2 TIP3 8961 -8.769 -11.432 14.464 0.417 1.000 -ATOM 5854 OH2 TIP3 8970 -1.689 3.380 -7.612 -0.834 1.520 -ATOM 5855 H1 TIP3 8970 -1.950 2.472 -7.588 0.417 1.000 -ATOM 5856 H2 TIP3 8970 -1.142 3.546 -6.833 0.417 1.000 -ATOM 5857 OH2 TIP3 8972 -16.200 11.154 -2.205 -0.834 1.520 -ATOM 5858 H1 TIP3 8972 -16.424 11.376 -3.168 0.417 1.000 -ATOM 5859 H2 TIP3 8972 -16.174 10.184 -2.177 0.417 1.000 -ATOM 5860 OH2 TIP3 8973 -16.339 5.314 -14.330 -0.834 1.520 -ATOM 5861 H1 TIP3 8973 -15.828 4.871 -15.004 0.417 1.000 -ATOM 5862 H2 TIP3 8973 -15.952 5.053 -13.531 0.417 1.000 -ATOM 5863 OH2 TIP3 8976 -11.068 7.387 -11.991 -0.834 1.520 -ATOM 5864 H1 TIP3 8976 -11.791 7.019 -11.389 0.417 1.000 -ATOM 5865 H2 TIP3 8976 -10.238 6.895 -11.786 0.417 1.000 -ATOM 5866 OH2 TIP3 8977 -17.417 -3.877 -7.954 -0.834 1.520 -ATOM 5867 H1 TIP3 8977 -16.509 -3.492 -7.941 0.417 1.000 -ATOM 5868 H2 TIP3 8977 -17.688 -3.688 -7.113 0.417 1.000 -ATOM 5869 OH2 TIP3 8988 -17.754 0.883 -15.005 -0.834 1.520 -ATOM 5870 H1 TIP3 8988 -18.389 0.097 -15.115 0.417 1.000 -ATOM 5871 H2 TIP3 8988 -16.921 0.473 -14.805 0.417 1.000 -ATOM 5872 OH2 TIP3 8994 -8.866 13.465 7.648 -0.834 1.520 -ATOM 5873 H1 TIP3 8994 -9.663 13.889 8.046 0.417 1.000 -ATOM 5874 H2 TIP3 8994 -9.280 12.732 7.163 0.417 1.000 -ATOM 5875 OH2 TIP3 9001 -4.087 4.342 15.186 -0.834 1.520 -ATOM 5876 H1 TIP3 9001 -3.693 3.514 15.072 0.417 1.000 -ATOM 5877 H2 TIP3 9001 -5.007 4.201 15.323 0.417 1.000 -ATOM 5878 OH2 TIP3 9013 -13.681 11.624 -9.894 -0.834 1.520 -ATOM 5879 H1 TIP3 9013 -12.913 11.877 -10.459 0.417 1.000 -ATOM 5880 H2 TIP3 9013 -14.236 12.421 -10.039 0.417 1.000 -ATOM 5881 OH2 TIP3 9015 -0.007 10.539 -8.466 -0.834 1.520 -ATOM 5882 H1 TIP3 9015 0.630 11.251 -8.418 0.417 1.000 -ATOM 5883 H2 TIP3 9015 0.051 10.203 -7.536 0.417 1.000 -ATOM 5884 OH2 TIP3 9017 -18.951 -0.123 11.163 -0.834 1.520 -ATOM 5885 H1 TIP3 9017 -19.138 -0.350 12.077 0.417 1.000 -ATOM 5886 H2 TIP3 9017 -19.580 -0.682 10.641 0.417 1.000 -ATOM 5887 OH2 TIP3 9034 -4.246 13.645 -8.855 -0.834 1.520 -ATOM 5888 H1 TIP3 9034 -4.524 13.296 -9.696 0.417 1.000 -ATOM 5889 H2 TIP3 9034 -3.283 13.556 -8.962 0.417 1.000 -ATOM 5890 OH2 TIP3 9035 -17.453 15.847 -8.873 -0.834 1.520 -ATOM 5891 H1 TIP3 9035 -16.878 15.236 -9.378 0.417 1.000 -ATOM 5892 H2 TIP3 9035 -18.266 15.322 -8.781 0.417 1.000 -ATOM 5893 OH2 TIP3 9037 -10.653 15.169 9.389 -0.834 1.520 -ATOM 5894 H1 TIP3 9037 -10.651 14.510 10.081 0.417 1.000 -ATOM 5895 H2 TIP3 9037 -10.866 16.013 9.882 0.417 1.000 -ATOM 5896 OH2 TIP3 9047 -15.284 8.389 -19.042 -0.834 1.520 -ATOM 5897 H1 TIP3 9047 -16.001 8.738 -18.510 0.417 1.000 -ATOM 5898 H2 TIP3 9047 -15.433 7.411 -18.991 0.417 1.000 -ATOM 5899 OH2 TIP3 9054 -12.244 10.127 -6.148 -0.834 1.520 -ATOM 5900 H1 TIP3 9054 -11.679 10.781 -6.711 0.417 1.000 -ATOM 5901 H2 TIP3 9054 -13.136 10.405 -6.437 0.417 1.000 -ATOM 5902 OH2 TIP3 9055 -16.995 9.797 -16.973 -0.834 1.520 -ATOM 5903 H1 TIP3 9055 -17.170 8.988 -16.504 0.417 1.000 -ATOM 5904 H2 TIP3 9055 -16.221 10.190 -16.587 0.417 1.000 -ATOM 5905 OH2 TIP3 9056 -10.546 17.563 5.092 -0.834 1.520 -ATOM 5906 H1 TIP3 9056 -10.652 16.598 4.989 0.417 1.000 -ATOM 5907 H2 TIP3 9056 -10.017 17.607 5.931 0.417 1.000 -ATOM 5908 OH2 TIP3 9057 -7.410 0.617 8.532 -0.834 1.520 -ATOM 5909 H1 TIP3 9057 -7.622 0.494 9.511 0.417 1.000 -ATOM 5910 H2 TIP3 9057 -8.213 0.273 8.098 0.417 1.000 -ATOM 5911 OH2 TIP3 9082 -11.844 -2.436 -8.480 -0.834 1.520 -ATOM 5912 H1 TIP3 9082 -11.645 -1.655 -9.079 0.417 1.000 -ATOM 5913 H2 TIP3 9082 -11.666 -3.180 -9.126 0.417 1.000 -ATOM 5914 OH2 TIP3 9084 -11.252 9.168 14.621 -0.834 1.520 -ATOM 5915 H1 TIP3 9084 -11.545 9.630 13.875 0.417 1.000 -ATOM 5916 H2 TIP3 9084 -12.003 8.592 14.797 0.417 1.000 -ATOM 5917 OH2 TIP3 9093 -10.008 15.829 -16.703 -0.834 1.520 -ATOM 5918 H1 TIP3 9093 -10.013 16.093 -17.662 0.417 1.000 -ATOM 5919 H2 TIP3 9093 -9.070 15.998 -16.520 0.417 1.000 -ATOM 5920 OH2 TIP3 9096 -17.085 -5.803 -16.607 -0.834 1.520 -ATOM 5921 H1 TIP3 9096 -17.845 -5.586 -16.084 0.417 1.000 -ATOM 5922 H2 TIP3 9096 -17.281 -6.667 -16.989 0.417 1.000 -ATOM 5923 OH2 TIP3 9127 -5.246 18.382 8.553 -0.834 1.520 -ATOM 5924 H1 TIP3 9127 -5.561 19.111 7.984 0.417 1.000 -ATOM 5925 H2 TIP3 9127 -5.914 18.448 9.262 0.417 1.000 -ATOM 5926 OH2 TIP3 9165 -12.613 -19.814 6.924 -0.834 1.520 -ATOM 5927 H1 TIP3 9165 -12.998 -19.069 6.433 0.417 1.000 -ATOM 5928 H2 TIP3 9165 -13.054 -19.750 7.843 0.417 1.000 -ATOM 5929 OH2 TIP3 9170 7.884 19.129 1.844 -0.834 1.520 -ATOM 5930 H1 TIP3 9170 8.466 18.885 1.122 0.417 1.000 -ATOM 5931 H2 TIP3 9170 7.278 18.412 1.870 0.417 1.000 -ATOM 5932 OH2 TIP3 9212 -15.144 -18.317 17.499 -0.834 1.520 -ATOM 5933 H1 TIP3 9212 -14.489 -18.228 16.838 0.417 1.000 -ATOM 5934 H2 TIP3 9212 -14.650 -18.818 18.202 0.417 1.000 -ATOM 5935 OH2 TIP3 9226 -11.422 -19.168 -13.649 -0.834 1.520 -ATOM 5936 H1 TIP3 9226 -12.072 -19.470 -14.307 0.417 1.000 -ATOM 5937 H2 TIP3 9226 -11.437 -18.199 -13.665 0.417 1.000 -ATOM 5938 OH2 TIP3 9241 -12.713 -9.828 -6.185 -0.834 1.520 -ATOM 5939 H1 TIP3 9241 -13.369 -10.527 -5.923 0.417 1.000 -ATOM 5940 H2 TIP3 9241 -11.881 -10.331 -6.148 0.417 1.000 -ATOM 5941 OH2 TIP3 9250 -16.653 -9.513 -0.186 -0.834 1.520 -ATOM 5942 H1 TIP3 9250 -17.208 -9.045 -0.812 0.417 1.000 -ATOM 5943 H2 TIP3 9250 -15.736 -9.361 -0.544 0.417 1.000 -END diff --git a/tests/opencl/fft/.depend b/tests/opencl/fft/.depend new file mode 100644 index 00000000..e2cadcd3 --- /dev/null +++ b/tests/opencl/fft/.depend @@ -0,0 +1,7 @@ +main.o: main.cc /opt/pocl/runtime/include/CL/opencl.h \ + /opt/pocl/runtime/include/CL/cl.h \ + /opt/pocl/runtime/include/CL/cl_version.h \ + /opt/pocl/runtime/include/CL/cl_platform.h \ + /opt/pocl/runtime/include/CL/cl_gl.h \ + /opt/pocl/runtime/include/CL/cl_gl_ext.h \ + /opt/pocl/runtime/include/CL/cl_ext.h common.h diff --git a/tests/opencl/sgemm2/Makefile b/tests/opencl/fft/Makefile similarity index 75% rename from tests/opencl/sgemm2/Makefile rename to tests/opencl/fft/Makefile index f507d9ed..fd039b0e 100644 --- a/tests/opencl/sgemm2/Makefile +++ b/tests/opencl/fft/Makefile @@ -1,4 +1,4 @@ -PROJECT = sgemm2 +PROJECT = fft4 SRCS = main.cc diff --git a/tests/opencl/fft/common.h b/tests/opencl/fft/common.h new file mode 100644 index 00000000..8c8e3344 --- /dev/null +++ b/tests/opencl/fft/common.h @@ -0,0 +1,3 @@ +#pragma once + +#define LOCAL_SIZE 16 \ No newline at end of file diff --git a/tests/opencl/fft/fft4 b/tests/opencl/fft/fft4 new file mode 100755 index 0000000000000000000000000000000000000000..044377ffa4e28495df685213058fff9f98666f4d GIT binary patch literal 19016 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 literal 0 HcmV?d00001 diff --git a/tests/opencl/fft/fft_radix4.dump b/tests/opencl/fft/fft_radix4.dump new file mode 100644 index 00000000..b8fc3a32 --- /dev/null +++ b/tests/opencl/fft/fft_radix4.dump @@ -0,0 +1,5495 @@ + +/tmp/pocl_vortex_kernel_ZOVlwB.elf: file format elf32-littleriscv + +Disassembly of section .init: + +80000000 <_start>: +80000000: f3 22 10 fc csrr t0, nw +80000004: 17 13 00 00 auipc t1, 1 +80000008: 13 03 43 8d addi t1, t1, -1836 +8000000c: 0b 90 62 00 vx_wspawn t0, t1 +80000010: 93 02 f0 ff li t0, -1 +80000014: 0b 80 02 00 vx_tmc t0 +80000018: ef 00 d0 08 jal 0x800008a4 +8000001c: 93 02 10 00 li t0, 1 +80000020: 0b 80 02 00 vx_tmc t0 +80000024: ef 00 d0 0d jal 0x80000900 +80000028: f3 22 10 fc csrr t0, nw +8000002c: 17 13 00 00 auipc t1, 1 +80000030: 13 03 03 8c addi t1, t1, -1856 +80000034: 0b 90 62 00 vx_wspawn t0, t1 +80000038: 93 02 f0 ff li t0, -1 +8000003c: 0b 80 02 00 vx_tmc t0 +80000040: ef 00 10 0d jal 0x80000910 <__init_tls> +80000044: 93 02 10 00 li t0, 1 +80000048: 0b 80 02 00 vx_tmc t0 +8000004c: ef 00 50 0b jal 0x80000900 +80000050: 17 45 00 00 auipc a0, 4 +80000054: 13 05 c5 f7 addi a0, a0, -132 +80000058: 17 56 00 00 auipc a2, 5 +8000005c: 13 06 46 f7 addi a2, a2, -140 +80000060: 33 06 a6 40 sub a2, a2, a0 +80000064: 93 05 00 00 li a1, 0 +80000068: ef 20 c0 2e jal 0x80002354 +8000006c: 17 15 00 00 auipc a0, 1 +80000070: 13 05 c5 97 addi a0, a0, -1668 +80000074: ef 20 80 12 jal 0x8000219c +80000078: ef 00 d0 0d jal 0x80000954 <__libc_init_array> +8000007c: ef 00 40 05 jal 0x800000d0
+80000080: 6f 00 40 00 j 0x80000084 + +Disassembly of section .text: + +80000084 : +80000084: 13 01 01 ff addi sp, sp, -16 +80000088: 93 05 00 00 li a1, 0 +8000008c: 23 24 81 00 sw s0, 8(sp) +80000090: 23 26 11 00 sw ra, 12(sp) +80000094: 13 04 05 00 mv s0, a0 +80000098: ef 20 40 43 jal 0x800024cc <__call_exitprocs> +8000009c: 17 45 00 00 auipc a0, 4 +800000a0: 03 25 c5 f2 lw a0, -212(a0) +800000a4: 83 27 c5 03 lw a5, 60(a0) +800000a8: 63 84 07 00 beqz a5, 0x800000b0 +800000ac: e7 80 07 00 jalr a5 +800000b0: 13 05 04 00 mv a0, s0 +800000b4: ef 00 00 7e jal 0x80000894 <_exit> + +800000b8 : +800000b8: 93 07 00 00 li a5, 0 +800000bc: 63 88 07 00 beqz a5, 0x800000cc +800000c0: 17 15 00 00 auipc a0, 1 +800000c4: 13 05 85 92 addi a0, a0, -1752 +800000c8: 6f 20 40 0d j 0x8000219c +800000cc: 67 80 00 00 ret + +800000d0
: +800000d0: 13 01 01 ff addi sp, sp, -16 +800000d4: 23 26 11 00 sw ra, 12(sp) +800000d8: 37 05 00 80 lui a0, 524288 +800000dc: 93 05 45 14 addi a1, a0, 324 +800000e0: 37 05 ff 7f lui a0, 524272 +800000e4: 13 06 45 03 addi a2, a0, 52 +800000e8: ef 00 10 36 jal 0x80000c48 +800000ec: 13 05 00 00 li a0, 0 +800000f0: 83 20 c1 00 lw ra, 12(sp) +800000f4: 13 01 01 01 addi sp, sp, 16 +800000f8: 67 80 00 00 ret + +800000fc <_Z7_cl_cosf>: +800000fc: 13 01 01 ff addi sp, sp, -16 +80000100: 23 26 11 00 sw ra, 12(sp) +80000104: 23 24 81 00 sw s0, 8(sp) +80000108: 13 04 01 01 addi s0, sp, 16 +8000010c: 83 20 c1 00 lw ra, 12(sp) +80000110: 03 24 81 00 lw s0, 8(sp) +80000114: 13 01 01 01 addi sp, sp, 16 +80000118: 17 13 00 00 auipc t1, 1 +8000011c: 67 00 03 f4 jr -192(t1) + +80000120 <_Z7_cl_sinf>: +80000120: 13 01 01 ff addi sp, sp, -16 +80000124: 23 26 11 00 sw ra, 12(sp) +80000128: 23 24 81 00 sw s0, 8(sp) +8000012c: 13 04 01 01 addi s0, sp, 16 +80000130: 83 20 c1 00 lw ra, 12(sp) +80000134: 03 24 81 00 lw s0, 8(sp) +80000138: 13 01 01 01 addi sp, sp, 16 +8000013c: 17 13 00 00 auipc t1, 1 +80000140: 67 00 c3 fb jr -68(t1) + +80000144 <_pocl_kernel_fft_radix4_workgroup>: +80000144: 13 01 01 f0 addi sp, sp, -256 +80000148: 23 2e 11 0e sw ra, 252(sp) +8000014c: 23 2c 81 0e sw s0, 248(sp) +80000150: 23 2a 91 0e sw s1, 244(sp) +80000154: 23 28 21 0f sw s2, 240(sp) +80000158: 23 26 31 0f sw s3, 236(sp) +8000015c: 23 24 41 0f sw s4, 232(sp) +80000160: 23 22 51 0f sw s5, 228(sp) +80000164: 23 20 61 0f sw s6, 224(sp) +80000168: 23 2e 71 0d sw s7, 220(sp) +8000016c: 23 2c 81 0d sw s8, 216(sp) +80000170: 23 2a 91 0d sw s9, 212(sp) +80000174: 23 28 a1 0d sw s10, 208(sp) +80000178: 23 26 b1 0d sw s11, 204(sp) +8000017c: 27 24 81 0c fsw fs0, 200(sp) +80000180: 27 22 91 0c fsw fs1, 196(sp) +80000184: 27 20 21 0d fsw fs2, 192(sp) +80000188: 27 2e 31 0b fsw fs3, 188(sp) +8000018c: 13 04 01 10 addi s0, sp, 256 +80000190: 13 71 01 f8 andi sp, sp, -128 +80000194: 93 04 01 00 mv s1, sp +80000198: 83 26 05 00 lw a3, 0(a0) +8000019c: 03 27 45 00 lw a4, 4(a0) +800001a0: 83 27 85 00 lw a5, 8(a0) +800001a4: 83 a8 85 01 lw a7, 24(a1) +800001a8: 83 a2 c5 01 lw t0, 28(a1) +800001ac: 03 ab 05 02 lw s6, 32(a1) +800001b0: 83 25 c5 00 lw a1, 12(a0) +800001b4: 03 25 05 01 lw a0, 16(a0) +800001b8: 33 88 12 03 mul a6, t0, a7 +800001bc: 23 a2 04 07 sw a6, 100(s1) +800001c0: 33 08 68 03 mul a6, a6, s6 +800001c4: 23 ae 04 03 sw a6, 60(s1) +800001c8: 13 18 28 00 slli a6, a6, 2 +800001cc: 13 08 f8 00 addi a6, a6, 15 +800001d0: 13 78 08 ff andi a6, a6, -16 +800001d4: 23 a2 04 05 sw a6, 68(s1) +800001d8: 33 08 01 41 sub a6, sp, a6 +800001dc: 13 7d 08 f8 andi s10, a6, -128 +800001e0: 13 01 0d 00 mv sp, s10 +800001e4: 13 b8 18 00 seqz a6, a7 +800001e8: 0b 28 08 00 vx_split a6, a6 +800001ec: 93 8b 08 00 mv s7, a7 +800001f0: 63 94 08 00 bnez a7, 0x800001f8 <_pocl_kernel_fft_radix4_workgroup+0xb4> +800001f4: 93 0b 10 00 li s7, 1 +800001f8: 83 a3 06 00 lw t2, 0(a3) +800001fc: 83 26 07 00 lw a3, 0(a4) +80000200: 23 a8 d4 04 sw a3, 80(s1) +80000204: 83 ac 07 00 lw s9, 0(a5) +80000208: 83 a0 05 00 lw ra, 0(a1) +8000020c: 83 25 05 00 lw a1, 0(a0) +80000210: b3 8a c8 02 mul s5, a7, a2 +80000214: 0b 30 08 00 vx_join a6 +80000218: 13 b5 12 00 seqz a0, t0 +8000021c: 0b 25 05 00 vx_split a0, a0 +80000220: 63 94 02 00 bnez t0, 0x80000228 <_pocl_kernel_fft_radix4_workgroup+0xe4> +80000224: 93 02 10 00 li t0, 1 +80000228: 0b 30 05 00 vx_join a0 +8000022c: 13 35 1b 00 seqz a0, s6 +80000230: 0b 25 05 00 vx_split a0, a0 +80000234: 63 14 0b 00 bnez s6, 0x8000023c <_pocl_kernel_fft_radix4_workgroup+0xf8> +80000238: 13 0b 10 00 li s6, 1 +8000023c: 23 a0 74 04 sw t2, 64(s1) +80000240: 23 ac b4 06 sw a1, 120(s1) +80000244: 23 a6 54 06 sw t0, 108(s1) +80000248: 0b 30 05 00 vx_join a0 +8000024c: 93 05 00 00 li a1, 0 +80000250: 03 a5 44 06 lw a0, 100(s1) +80000254: 13 15 25 00 slli a0, a0, 2 +80000258: 23 a4 a4 06 sw a0, 104(s1) +8000025c: 37 25 00 80 lui a0, 524290 +80000260: 07 29 c5 63 flw fs2, 1596(a0) +80000264: 37 25 00 80 lui a0, 524290 +80000268: 87 29 05 64 flw fs3, 1600(a0) +8000026c: 23 a4 14 05 sw a7, 72(s1) +80000270: 93 98 28 00 slli a7, a7, 2 +80000274: 23 ae 14 07 sw a7, 124(s1) +80000278: 73 25 40 cc csrr a0, tmask +8000027c: 23 a6 a4 04 sw a0, 76(s1) +80000280: 13 09 30 00 li s2, 3 +80000284: 23 aa a4 05 sw s10, 84(s1) +80000288: 23 a0 64 07 sw s6, 96(s1) +8000028c: 6f 00 00 03 j 0x800002bc <_pocl_kernel_fft_radix4_workgroup+0x178> +80000290: 83 a5 c4 05 lw a1, 92(s1) +80000294: 93 85 15 00 addi a1, a1, 1 +80000298: 03 a5 84 06 lw a0, 104(s1) +8000029c: 03 ad 84 05 lw s10, 88(s1) +800002a0: 33 0d ad 00 add s10, s10, a0 +800002a4: 03 ab 04 06 lw s6, 96(s1) +800002a8: 33 c5 65 01 xor a0, a1, s6 +800002ac: 33 35 a0 00 snez a0, a0 +800002b0: 03 a6 c4 04 lw a2, 76(s1) +800002b4: 0b 50 c5 00 vx_pred a0, a2 +800002b8: 63 8a 65 0b beq a1, s6, 0x8000036c <_pocl_kernel_fft_radix4_workgroup+0x228> +800002bc: 23 ae b4 04 sw a1, 92(s1) +800002c0: 13 0c 00 00 li s8, 0 +800002c4: 73 25 40 cc csrr a0, tmask +800002c8: 23 a8 a4 06 sw a0, 112(s1) +800002cc: 23 ac a4 05 sw s10, 88(s1) +800002d0: 6f 00 c0 02 j 0x800002fc <_pocl_kernel_fft_radix4_workgroup+0x1b8> +800002d4: 13 0c 1c 00 addi s8, s8, 1 +800002d8: 03 a5 c4 07 lw a0, 124(s1) +800002dc: 03 ad 44 07 lw s10, 116(s1) +800002e0: 33 0d ad 00 add s10, s10, a0 +800002e4: 83 a5 c4 06 lw a1, 108(s1) +800002e8: 33 45 bc 00 xor a0, s8, a1 +800002ec: 33 35 a0 00 snez a0, a0 +800002f0: 03 a6 04 07 lw a2, 112(s1) +800002f4: 0b 50 c5 00 vx_pred a0, a2 +800002f8: e3 0c bc f8 beq s8, a1, 0x80000290 <_pocl_kernel_fft_radix4_workgroup+0x14c> +800002fc: 13 0a 00 00 li s4, 0 +80000300: f3 29 40 cc csrr s3, tmask +80000304: 23 aa a4 07 sw s10, 116(s1) +80000308: 03 ab 84 07 lw s6, 120(s1) +8000030c: 6f 00 00 02 j 0x8000032c <_pocl_kernel_fft_radix4_workgroup+0x1e8> +80000310: 13 0a 1a 00 addi s4, s4, 1 +80000314: 13 0b 8b 00 addi s6, s6, 8 +80000318: 13 0d 4d 00 addi s10, s10, 4 +8000031c: 33 c5 4b 01 xor a0, s7, s4 +80000320: 33 35 a0 00 snez a0, a0 +80000324: 0b 50 35 01 vx_pred a0, s3 +80000328: e3 86 4b fb beq s7, s4, 0x800002d4 <_pocl_kernel_fft_radix4_workgroup+0x190> +8000032c: 33 85 4a 01 add a0, s5, s4 +80000330: 23 20 ad 00 sw a0, 0(s10) +80000334: e3 4e 49 fd blt s2, s4, 0x80000310 <_pocl_kernel_fft_radix4_workgroup+0x1cc> +80000338: 53 70 0a d0 fcvt.s.w ft0, s4 +8000033c: 53 70 20 11 fmul.s ft0, ft0, fs2 +80000340: 53 74 30 11 fmul.s fs0, ft0, fs3 +80000344: 53 05 84 20 fmv.s fa0, fs0 +80000348: 93 8d 00 00 mv s11, ra +8000034c: ef f0 1f db jal 0x800000fc <_Z7_cl_cosf> +80000350: d3 04 a5 20 fmv.s fs1, fa0 +80000354: 53 05 84 20 fmv.s fa0, fs0 +80000358: ef f0 9f dc jal 0x80000120 <_Z7_cl_sinf> +8000035c: 93 80 0d 00 mv ra, s11 +80000360: 27 22 ab 00 fsw fa0, 4(s6) +80000364: 27 20 9b 00 fsw fs1, 0(s6) +80000368: 6f f0 9f fa j 0x80000310 <_pocl_kernel_fft_radix4_workgroup+0x1cc> +8000036c: 03 a5 c4 03 lw a0, 60(s1) +80000370: 13 05 f5 00 addi a0, a0, 15 +80000374: 13 75 05 ff andi a0, a0, -16 +80000378: 33 05 a1 40 sub a0, sp, a0 +8000037c: 13 75 05 f8 andi a0, a0, -128 +80000380: 13 01 05 00 mv sp, a0 +80000384: 93 05 00 00 li a1, 0 +80000388: 73 26 40 cc csrr a2, tmask +8000038c: 83 a6 44 05 lw a3, 84(s1) +80000390: 13 07 05 00 mv a4, a0 +80000394: 03 ad 84 04 lw s10, 72(s1) +80000398: 83 ad c4 06 lw s11, 108(s1) +8000039c: 83 a9 04 04 lw s3, 64(s1) +800003a0: 6f 00 80 02 j 0x800003c8 <_pocl_kernel_fft_radix4_workgroup+0x284> +800003a4: 93 85 15 00 addi a1, a1, 1 +800003a8: 83 a7 44 06 lw a5, 100(s1) +800003ac: 33 07 f7 00 add a4, a4, a5 +800003b0: 83 a7 84 06 lw a5, 104(s1) +800003b4: b3 86 f6 00 add a3, a3, a5 +800003b8: b3 c7 65 01 xor a5, a1, s6 +800003bc: b3 37 f0 00 snez a5, a5 +800003c0: 0b d0 c7 00 vx_pred a5, a2 +800003c4: 63 80 65 0b beq a1, s6, 0x80000464 <_pocl_kernel_fft_radix4_workgroup+0x320> +800003c8: 93 07 00 00 li a5, 0 +800003cc: 73 28 40 cc csrr a6, tmask +800003d0: 93 88 06 00 mv a7, a3 +800003d4: 93 02 07 00 mv t0, a4 +800003d8: 6f 00 40 02 j 0x800003fc <_pocl_kernel_fft_radix4_workgroup+0x2b8> +800003dc: 93 87 17 00 addi a5, a5, 1 +800003e0: b3 82 a2 01 add t0, t0, s10 +800003e4: 03 a3 c4 07 lw t1, 124(s1) +800003e8: b3 88 68 00 add a7, a7, t1 +800003ec: 33 c3 b7 01 xor t1, a5, s11 +800003f0: 33 33 60 00 snez t1, t1 +800003f4: 0b 50 03 01 vx_pred t1, a6 +800003f8: e3 86 b7 fb beq a5, s11, 0x800003a4 <_pocl_kernel_fft_radix4_workgroup+0x260> +800003fc: 73 23 40 cc csrr t1, tmask +80000400: 93 83 08 00 mv t2, a7 +80000404: 13 8e 02 00 mv t3, t0 +80000408: 93 8e 00 00 mv t4, ra +8000040c: 13 8f 0b 00 mv t5, s7 +80000410: 6f 00 40 02 j 0x80000434 <_pocl_kernel_fft_radix4_workgroup+0x2f0> +80000414: 0b b0 0f 00 vx_join t6 +80000418: 13 0f ff ff addi t5, t5, -1 +8000041c: 93 8e 8e 00 addi t4, t4, 8 +80000420: 13 0e 1e 00 addi t3, t3, 1 +80000424: 93 83 43 00 addi t2, t2, 4 +80000428: b3 3f e0 01 snez t6, t5 +8000042c: 0b d0 6f 00 vx_pred t6, t1 +80000430: e3 06 0f fa beqz t5, 0x800003dc <_pocl_kernel_fft_radix4_workgroup+0x298> +80000434: 03 a9 03 00 lw s2, 0(t2) +80000438: b3 3f 99 01 sltu t6, s2, s9 +8000043c: 23 00 fe 01 sb t6, 0(t3) +80000440: 8b af 0f 00 vx_split t6, t6 +80000444: e3 78 99 fd bgeu s2, s9, 0x80000414 <_pocl_kernel_fft_radix4_workgroup+0x2d0> +80000448: 13 19 39 00 slli s2, s2, 3 +8000044c: 33 89 29 01 add s2, s3, s2 +80000450: 07 20 49 00 flw ft0, 4(s2) +80000454: 87 20 09 00 flw ft1, 0(s2) +80000458: 27 a2 0e 00 fsw ft0, 4(t4) +8000045c: 27 a0 1e 00 fsw ft1, 0(t4) +80000460: 6f f0 5f fb j 0x80000414 <_pocl_kernel_fft_radix4_workgroup+0x2d0> +80000464: 83 a6 44 04 lw a3, 68(s1) +80000468: b3 05 d1 40 sub a1, sp, a3 +8000046c: 13 f6 05 f8 andi a2, a1, -128 +80000470: 13 01 06 00 mv sp, a2 +80000474: b3 05 d1 40 sub a1, sp, a3 +80000478: 93 f5 05 f8 andi a1, a1, -128 +8000047c: 13 81 05 00 mv sp, a1 +80000480: 93 06 00 00 li a3, 0 +80000484: 73 27 40 cc csrr a4, tmask +80000488: 93 07 10 00 li a5, 1 +8000048c: 13 88 05 00 mv a6, a1 +80000490: 93 08 06 00 mv a7, a2 +80000494: 83 ac 84 06 lw s9, 104(s1) +80000498: 93 02 00 00 li t0, 0 +8000049c: 73 23 40 cc csrr t1, tmask +800004a0: 93 03 08 00 mv t2, a6 +800004a4: 13 8e 08 00 mv t3, a7 +800004a8: f3 2e 40 cc csrr t4, tmask +800004ac: 13 8f 00 00 mv t5, ra +800004b0: 93 8f 03 00 mv t6, t2 +800004b4: 13 09 0e 00 mv s2, t3 +800004b8: 93 89 0b 00 mv s3, s7 +800004bc: 23 a0 ef 01 sw t5, 0(t6) +800004c0: 23 20 f9 00 sw a5, 0(s2) +800004c4: 93 89 f9 ff addi s3, s3, -1 +800004c8: 13 09 49 00 addi s2, s2, 4 +800004cc: 93 8f 4f 00 addi t6, t6, 4 +800004d0: 13 0f 8f 00 addi t5, t5, 8 +800004d4: 33 3a 30 01 snez s4, s3 +800004d8: 0b 50 da 01 vx_pred s4, t4 +800004dc: e3 90 09 fe bnez s3, 0x800004bc <_pocl_kernel_fft_radix4_workgroup+0x378> +800004e0: 93 82 12 00 addi t0, t0, 1 +800004e4: 83 ae c4 07 lw t4, 124(s1) +800004e8: 33 0e de 01 add t3, t3, t4 +800004ec: b3 83 d3 01 add t2, t2, t4 +800004f0: b3 ce b2 01 xor t4, t0, s11 +800004f4: b3 3e d0 01 snez t4, t4 +800004f8: 0b d0 6e 00 vx_pred t4, t1 +800004fc: e3 96 b2 fb bne t0, s11, 0x800004a8 <_pocl_kernel_fft_radix4_workgroup+0x364> +80000500: 93 86 16 00 addi a3, a3, 1 +80000504: b3 88 98 01 add a7, a7, s9 +80000508: 33 08 98 01 add a6, a6, s9 +8000050c: b3 c2 66 01 xor t0, a3, s6 +80000510: b3 32 50 00 snez t0, t0 +80000514: 0b d0 e2 00 vx_pred t0, a4 +80000518: e3 90 66 f9 bne a3, s6, 0x80000498 <_pocl_kernel_fft_radix4_workgroup+0x354> +8000051c: 93 08 00 00 li a7, 0 +80000520: f3 26 40 cc csrr a3, tmask +80000524: 23 aa d4 06 sw a3, 116(s1) +80000528: 13 07 00 01 li a4, 16 +8000052c: 93 07 80 01 li a5, 24 +80000530: 53 00 00 f0 fmv.w.x ft0, zero +80000534: 6f 00 c0 01 j 0x80000550 <_pocl_kernel_fft_radix4_workgroup+0x40c> +80000538: 0b b0 02 00 vx_join t0 +8000053c: 83 ac 84 06 lw s9, 104(s1) +80000540: 93 42 18 00 xori t0, a6, 1 +80000544: 83 a6 44 07 lw a3, 116(s1) +80000548: 0b d0 d2 00 vx_pred t0, a3 +8000054c: 63 10 08 22 bnez a6, 0x8000076c <_pocl_kernel_fft_radix4_workgroup+0x628> +80000550: 13 03 00 00 li t1, 0 +80000554: 33 8e 1c 03 mul t3, s9, a7 +80000558: b3 83 c5 01 add t2, a1, t3 +8000055c: 33 0e c6 01 add t3, a2, t3 +80000560: f3 2e 40 cc csrr t4, tmask +80000564: 13 0f 00 00 li t5, 0 +80000568: f3 2f 40 cc csrr t6, tmask +8000056c: 93 0a 0e 00 mv s5, t3 +80000570: 13 8b 03 00 mv s6, t2 +80000574: 93 8c 00 00 mv s9, ra +80000578: 83 a6 84 07 lw a3, 120(s1) +8000057c: 03 a8 0a 00 lw a6, 0(s5) +80000580: b3 52 0f 03 divu t0, t5, a6 +80000584: 13 f9 32 00 andi s2, t0, 3 +80000588: 93 12 28 00 slli t0, a6, 2 +8000058c: 93 f9 c2 0f andi s3, t0, 252 +80000590: b3 59 37 03 divu s3, a4, s3 +80000594: 33 09 39 03 mul s2, s2, s3 +80000598: 13 19 39 00 slli s2, s2, 3 +8000059c: 83 29 0b 00 lw s3, 0(s6) +800005a0: 33 89 26 01 add s2, a3, s2 +800005a4: 87 20 49 00 flw ft1, 4(s2) +800005a8: 07 21 09 00 flw ft2, 0(s2) +800005ac: 87 a1 49 00 flw ft3, 4(s3) +800005b0: 07 a2 09 00 flw ft4, 0(s3) +800005b4: 33 09 0f 01 add s2, t5, a6 +800005b8: 13 19 39 00 slli s2, s2, 3 +800005bc: 33 89 20 01 add s2, ra, s2 +800005c0: 87 22 49 00 flw ft5, 4(s2) +800005c4: 07 23 09 00 flw ft6, 0(s2) +800005c8: 13 1a 48 00 slli s4, a6, 4 +800005cc: 33 8a 4c 01 add s4, s9, s4 +800005d0: 87 23 4a 00 flw ft7, 4(s4) +800005d4: 07 25 0a 00 flw fa0, 0(s4) +800005d8: 33 0c f8 02 mul s8, a6, a5 +800005dc: 33 8c 8c 01 add s8, s9, s8 +800005e0: 87 25 4c 00 flw fa1, 4(s8) +800005e4: 07 26 0c 00 flw fa2, 0(s8) +800005e8: 53 73 61 10 fmul.s ft6, ft2, ft6 +800005ec: d3 f2 50 10 fmul.s ft5, ft1, ft5 +800005f0: d3 76 21 10 fmul.s fa3, ft2, ft2 +800005f4: 53 f7 10 10 fmul.s fa4, ft1, ft1 +800005f8: 53 f5 a6 10 fmul.s fa0, fa3, fa0 +800005fc: d3 73 77 10 fmul.s ft7, fa4, ft7 +80000600: 53 71 d1 10 fmul.s ft2, ft2, fa3 +80000604: d3 f0 e0 10 fmul.s ft1, ft1, fa4 +80000608: 53 71 c1 10 fmul.s ft2, ft2, fa2 +8000060c: d3 f0 b0 10 fmul.s ft1, ft1, fa1 +80000610: d3 75 a2 00 fadd.s fa1, ft4, fa0 +80000614: 53 f6 71 00 fadd.s fa2, ft3, ft7 +80000618: 53 72 a2 08 fsub.s ft4, ft4, fa0 +8000061c: d3 f1 71 08 fsub.s ft3, ft3, ft7 +80000620: d3 73 23 00 fadd.s ft7, ft6, ft2 +80000624: 53 f5 12 00 fadd.s fa0, ft5, ft1 +80000628: 53 71 23 08 fsub.s ft2, ft6, ft2 +8000062c: d3 f0 12 08 fsub.s ft1, ft5, ft1 +80000630: 53 71 01 10 fmul.s ft2, ft2, ft0 +80000634: d3 f2 75 00 fadd.s ft5, fa1, ft7 +80000638: 53 73 a6 00 fadd.s ft6, fa2, fa0 +8000063c: 27 a0 59 00 fsw ft5, 0(s3) +80000640: 27 a2 69 00 fsw ft6, 4(s3) +80000644: d3 72 22 00 fadd.s ft5, ft4, ft2 +80000648: 53 f3 11 08 fsub.s ft6, ft3, ft1 +8000064c: 27 20 59 00 fsw ft5, 0(s2) +80000650: 27 22 69 00 fsw ft6, 4(s2) +80000654: d3 f2 75 08 fsub.s ft5, fa1, ft7 +80000658: 53 73 a6 08 fsub.s ft6, fa2, fa0 +8000065c: 27 20 5a 00 fsw ft5, 0(s4) +80000660: 27 22 6a 00 fsw ft6, 4(s4) +80000664: 53 71 22 08 fsub.s ft2, ft4, ft2 +80000668: d3 f0 11 00 fadd.s ft1, ft3, ft1 +8000066c: 27 20 2c 00 fsw ft2, 0(s8) +80000670: 27 22 1c 00 fsw ft1, 4(s8) +80000674: 13 0f 1f 00 addi t5, t5, 1 +80000678: 93 8c 8c 00 addi s9, s9, 8 +8000067c: 13 0b 4b 00 addi s6, s6, 4 +80000680: 93 8a 4a 00 addi s5, s5, 4 +80000684: 33 c9 eb 01 xor s2, s7, t5 +80000688: 33 39 20 01 snez s2, s2 +8000068c: 0b 50 f9 01 vx_pred s2, t6 +80000690: e3 96 eb ef bne s7, t5, 0x8000057c <_pocl_kernel_fft_radix4_workgroup+0x438> +80000694: 13 03 13 00 addi t1, t1, 1 +80000698: 03 af c4 07 lw t5, 124(s1) +8000069c: b3 83 e3 01 add t2, t2, t5 +800006a0: 33 0e ee 01 add t3, t3, t5 +800006a4: 33 4f b3 01 xor t5, t1, s11 +800006a8: 33 3f e0 01 snez t5, t5 +800006ac: 0b 50 df 01 vx_pred t5, t4 +800006b0: e3 1a b3 eb bne t1, s11, 0x80000564 <_pocl_kernel_fft_radix4_workgroup+0x420> +800006b4: 93 88 18 00 addi a7, a7, 1 +800006b8: 03 ab 04 06 lw s6, 96(s1) +800006bc: 33 c3 68 01 xor t1, a7, s6 +800006c0: 13 33 13 00 seqz t1, t1 +800006c4: 0b 23 03 00 vx_split t1, t1 +800006c8: 93 03 10 00 li t2, 1 +800006cc: 03 ac 44 05 lw s8, 84(s1) +800006d0: 63 90 68 09 bne a7, s6, 0x80000750 <_pocl_kernel_fft_radix4_workgroup+0x60c> +800006d4: 93 08 00 00 li a7, 0 +800006d8: f3 23 40 cc csrr t2, tmask +800006dc: 13 0e 06 00 mv t3, a2 +800006e0: 83 ac 84 06 lw s9, 104(s1) +800006e4: 93 0e 00 00 li t4, 0 +800006e8: 73 2f 40 cc csrr t5, tmask +800006ec: 93 0f 0e 00 mv t6, t3 +800006f0: 73 29 40 cc csrr s2, tmask +800006f4: 93 89 0f 00 mv s3, t6 +800006f8: 13 8a 0b 00 mv s4, s7 +800006fc: 23 a0 59 00 sw t0, 0(s3) +80000700: 13 0a fa ff addi s4, s4, -1 +80000704: 93 89 49 00 addi s3, s3, 4 +80000708: b3 3a 40 01 snez s5, s4 +8000070c: 0b d0 2a 01 vx_pred s5, s2 +80000710: e3 16 0a fe bnez s4, 0x800006fc <_pocl_kernel_fft_radix4_workgroup+0x5b8> +80000714: 93 8e 1e 00 addi t4, t4, 1 +80000718: 03 a9 c4 07 lw s2, 124(s1) +8000071c: b3 8f 2f 01 add t6, t6, s2 +80000720: 33 c9 be 01 xor s2, t4, s11 +80000724: 33 39 20 01 snez s2, s2 +80000728: 0b 50 e9 01 vx_pred s2, t5 +8000072c: e3 92 be fd bne t4, s11, 0x800006f0 <_pocl_kernel_fft_radix4_workgroup+0x5ac> +80000730: 93 88 18 00 addi a7, a7, 1 +80000734: 33 0e 9e 01 add t3, t3, s9 +80000738: b3 ce 68 01 xor t4, a7, s6 +8000073c: b3 3e d0 01 snez t4, t4 +80000740: 0b d0 7e 00 vx_pred t4, t2 +80000744: e3 90 68 fb bne a7, s6, 0x800006e4 <_pocl_kernel_fft_radix4_workgroup+0x5a0> +80000748: 93 08 00 00 li a7, 0 +8000074c: 93 33 48 00 sltiu t2, a6, 4 +80000750: 0b 30 03 00 vx_join t1 +80000754: 8b a2 03 00 vx_split t0, t2 +80000758: 13 08 10 00 li a6, 1 +8000075c: 83 aa 04 05 lw s5, 80(s1) +80000760: e3 8c 03 dc beqz t2, 0x80000538 <_pocl_kernel_fft_radix4_workgroup+0x3f4> +80000764: 13 08 00 00 li a6, 0 +80000768: 6f f0 1f dd j 0x80000538 <_pocl_kernel_fft_radix4_workgroup+0x3f4> +8000076c: 13 06 00 00 li a2, 0 +80000770: f3 26 40 cc csrr a3, tmask +80000774: 03 aa 04 06 lw s4, 96(s1) +80000778: 6f 00 80 02 j 0x800007a0 <_pocl_kernel_fft_radix4_workgroup+0x65c> +8000077c: 13 06 16 00 addi a2, a2, 1 +80000780: b3 85 95 01 add a1, a1, s9 +80000784: 33 0c 9c 01 add s8, s8, s9 +80000788: 03 a7 44 06 lw a4, 100(s1) +8000078c: 33 05 e5 00 add a0, a0, a4 +80000790: 33 47 46 01 xor a4, a2, s4 +80000794: 33 37 e0 00 snez a4, a4 +80000798: 0b 50 d7 00 vx_pred a4, a3 +8000079c: 63 04 46 0b beq a2, s4, 0x80000844 <_pocl_kernel_fft_radix4_workgroup+0x700> +800007a0: 13 07 00 00 li a4, 0 +800007a4: f3 27 40 cc csrr a5, tmask +800007a8: 13 08 05 00 mv a6, a0 +800007ac: 93 08 0c 00 mv a7, s8 +800007b0: 93 82 05 00 mv t0, a1 +800007b4: 6f 00 80 02 j 0x800007dc <_pocl_kernel_fft_radix4_workgroup+0x698> +800007b8: 13 07 17 00 addi a4, a4, 1 +800007bc: 03 a3 c4 07 lw t1, 124(s1) +800007c0: b3 82 62 00 add t0, t0, t1 +800007c4: b3 88 68 00 add a7, a7, t1 +800007c8: 33 08 a8 01 add a6, a6, s10 +800007cc: 33 43 b7 01 xor t1, a4, s11 +800007d0: 33 33 60 00 snez t1, t1 +800007d4: 0b 50 f3 00 vx_pred t1, a5 +800007d8: e3 02 b7 fb beq a4, s11, 0x8000077c <_pocl_kernel_fft_radix4_workgroup+0x638> +800007dc: 73 23 40 cc csrr t1, tmask +800007e0: 93 03 08 00 mv t2, a6 +800007e4: 13 8e 08 00 mv t3, a7 +800007e8: 93 8e 02 00 mv t4, t0 +800007ec: 13 8f 0b 00 mv t5, s7 +800007f0: 6f 00 40 02 j 0x80000814 <_pocl_kernel_fft_radix4_workgroup+0x6d0> +800007f4: 0b b0 0f 00 vx_join t6 +800007f8: 13 0f ff ff addi t5, t5, -1 +800007fc: 93 8e 4e 00 addi t4, t4, 4 +80000800: 13 0e 4e 00 addi t3, t3, 4 +80000804: 93 83 13 00 addi t2, t2, 1 +80000808: b3 3f e0 01 snez t6, t5 +8000080c: 0b d0 6f 00 vx_pred t6, t1 +80000810: e3 04 0f fa beqz t5, 0x800007b8 <_pocl_kernel_fft_radix4_workgroup+0x674> +80000814: 03 c9 03 00 lbu s2, 0(t2) +80000818: 8b 2f 09 00 vx_split t6, s2 +8000081c: e3 0c 09 fc beqz s2, 0x800007f4 <_pocl_kernel_fft_radix4_workgroup+0x6b0> +80000820: 03 a9 0e 00 lw s2, 0(t4) +80000824: 83 29 0e 00 lw s3, 0(t3) +80000828: 07 20 49 00 flw ft0, 4(s2) +8000082c: 87 20 09 00 flw ft1, 0(s2) +80000830: 93 99 39 00 slli s3, s3, 3 +80000834: b3 89 3a 01 add s3, s5, s3 +80000838: 27 a2 09 00 fsw ft0, 4(s3) +8000083c: 27 a0 19 00 fsw ft1, 0(s3) +80000840: 6f f0 5f fb j 0x800007f4 <_pocl_kernel_fft_radix4_workgroup+0x6b0> +80000844: 13 01 04 f0 addi sp, s0, -256 +80000848: 83 20 c1 0f lw ra, 252(sp) +8000084c: 03 24 81 0f lw s0, 248(sp) +80000850: 83 24 41 0f lw s1, 244(sp) +80000854: 03 29 01 0f lw s2, 240(sp) +80000858: 83 29 c1 0e lw s3, 236(sp) +8000085c: 03 2a 81 0e lw s4, 232(sp) +80000860: 83 2a 41 0e lw s5, 228(sp) +80000864: 03 2b 01 0e lw s6, 224(sp) +80000868: 83 2b c1 0d lw s7, 220(sp) +8000086c: 03 2c 81 0d lw s8, 216(sp) +80000870: 83 2c 41 0d lw s9, 212(sp) +80000874: 03 2d 01 0d lw s10, 208(sp) +80000878: 83 2d c1 0c lw s11, 204(sp) +8000087c: 07 24 81 0c flw fs0, 200(sp) +80000880: 87 24 41 0c flw fs1, 196(sp) +80000884: 07 29 01 0c flw fs2, 192(sp) +80000888: 87 29 c1 0b flw fs3, 188(sp) +8000088c: 13 01 01 10 addi sp, sp, 256 +80000890: 67 80 00 00 ret + +80000894 <_exit>: +80000894: 13 04 05 00 mv s0, a0 +80000898: ef 00 80 5a jal 0x80000e40 +8000089c: 93 01 04 00 mv gp, s0 +800008a0: 0b 00 00 00 vx_tmc zero + +800008a4 : +800008a4: 97 41 00 00 auipc gp, 4 +800008a8: 93 81 c1 e9 addi gp, gp, -356 +800008ac: 37 01 00 ff lui sp, 1044480 +800008b0: f3 22 40 f1 csrr t0, mhartid +800008b4: 13 93 d2 00 slli t1, t0, 13 +800008b8: 33 01 61 40 sub sp, sp, t1 +800008bc: 13 03 00 00 li t1, 0 +800008c0: b3 82 62 02 mul t0, t0, t1 +800008c4: 17 42 00 00 auipc tp, 4 +800008c8: 13 02 72 74 addi tp, tp, 1863 +800008cc: 33 02 52 00 add tp, tp, t0 +800008d0: 13 72 02 fc andi tp, tp, -64 +800008d4: 67 80 00 00 ret + +800008d8 : +800008d8: 93 02 f0 ff li t0, -1 +800008dc: 0b 80 02 00 vx_tmc t0 +800008e0: ef f0 5f fc jal 0x800008a4 +800008e4: 0b 00 00 00 vx_tmc zero +800008e8: 67 80 00 00 ret + +800008ec : +800008ec: 93 02 f0 ff li t0, -1 +800008f0: 0b 80 02 00 vx_tmc t0 +800008f4: ef 00 c0 01 jal 0x80000910 <__init_tls> +800008f8: 0b 00 00 00 vx_tmc zero +800008fc: 67 80 00 00 ret + +80000900 : +80000900: f3 22 30 cc csrr t0, gid +80000904: 13 03 10 00 li t1, 1 +80000908: e3 9c 62 fe bne t0, t1, 0x80000900 +8000090c: 67 80 00 00 ret + +80000910 <__init_tls>: +80000910: 13 01 01 ff addi sp, sp, -16 +80000914: 13 06 00 00 li a2, 0 +80000918: 97 35 00 00 auipc a1, 3 +8000091c: 93 85 c5 1f addi a1, a1, 508 +80000920: 13 05 02 00 mv a0, tp +80000924: 23 24 81 00 sw s0, 8(sp) +80000928: 23 26 11 00 sw ra, 12(sp) +8000092c: 13 04 02 00 mv s0, tp +80000930: ef 10 10 08 jal 0x800021b0 +80000934: 13 05 00 00 li a0, 0 +80000938: 33 05 a4 00 add a0, s0, a0 +8000093c: 03 24 81 00 lw s0, 8(sp) +80000940: 83 20 c1 00 lw ra, 12(sp) +80000944: 13 06 00 00 li a2, 0 +80000948: 93 05 00 00 li a1, 0 +8000094c: 13 01 01 01 addi sp, sp, 16 +80000950: 6f 10 50 20 j 0x80002354 + +80000954 <__libc_init_array>: +80000954: 13 01 01 ff addi sp, sp, -16 +80000958: 23 24 81 00 sw s0, 8(sp) +8000095c: 23 20 21 01 sw s2, 0(sp) +80000960: 97 37 00 00 auipc a5, 3 +80000964: 93 87 47 1b addi a5, a5, 436 +80000968: 17 34 00 00 auipc s0, 3 +8000096c: 13 04 c4 1a addi s0, s0, 428 +80000970: 23 26 11 00 sw ra, 12(sp) +80000974: 23 22 91 00 sw s1, 4(sp) +80000978: 33 89 87 40 sub s2, a5, s0 +8000097c: 63 80 87 02 beq a5, s0, 0x8000099c <__libc_init_array+0x48> +80000980: 13 59 29 40 srai s2, s2, 2 +80000984: 93 04 00 00 li s1, 0 +80000988: 83 27 04 00 lw a5, 0(s0) +8000098c: 93 84 14 00 addi s1, s1, 1 +80000990: 13 04 44 00 addi s0, s0, 4 +80000994: e7 80 07 00 jalr a5 +80000998: e3 e8 24 ff bltu s1, s2, 0x80000988 <__libc_init_array+0x34> +8000099c: 97 37 00 00 auipc a5, 3 +800009a0: 93 87 c7 17 addi a5, a5, 380 +800009a4: 17 34 00 00 auipc s0, 3 +800009a8: 13 04 04 17 addi s0, s0, 368 +800009ac: 33 89 87 40 sub s2, a5, s0 +800009b0: 13 59 29 40 srai s2, s2, 2 +800009b4: 63 8e 87 00 beq a5, s0, 0x800009d0 <__libc_init_array+0x7c> +800009b8: 93 04 00 00 li s1, 0 +800009bc: 83 27 04 00 lw a5, 0(s0) +800009c0: 93 84 14 00 addi s1, s1, 1 +800009c4: 13 04 44 00 addi s0, s0, 4 +800009c8: e7 80 07 00 jalr a5 +800009cc: e3 e8 24 ff bltu s1, s2, 0x800009bc <__libc_init_array+0x68> +800009d0: 83 20 c1 00 lw ra, 12(sp) +800009d4: 03 24 81 00 lw s0, 8(sp) +800009d8: 83 24 41 00 lw s1, 4(sp) +800009dc: 03 29 01 00 lw s2, 0(sp) +800009e0: 13 01 01 01 addi sp, sp, 16 +800009e4: 67 80 00 00 ret + +800009e8 <__libc_fini_array>: +800009e8: 13 01 01 ff addi sp, sp, -16 +800009ec: 23 24 81 00 sw s0, 8(sp) +800009f0: 97 37 00 00 auipc a5, 3 +800009f4: 93 87 87 12 addi a5, a5, 296 +800009f8: 17 34 00 00 auipc s0, 3 +800009fc: 13 04 04 12 addi s0, s0, 288 +80000a00: 33 04 f4 40 sub s0, s0, a5 +80000a04: 23 22 91 00 sw s1, 4(sp) +80000a08: 23 26 11 00 sw ra, 12(sp) +80000a0c: 93 54 24 40 srai s1, s0, 2 +80000a10: 63 80 04 02 beqz s1, 0x80000a30 <__libc_fini_array+0x48> +80000a14: 13 04 c4 ff addi s0, s0, -4 +80000a18: 33 04 f4 00 add s0, s0, a5 +80000a1c: 83 27 04 00 lw a5, 0(s0) +80000a20: 93 84 f4 ff addi s1, s1, -1 +80000a24: 13 04 c4 ff addi s0, s0, -4 +80000a28: e7 80 07 00 jalr a5 +80000a2c: e3 98 04 fe bnez s1, 0x80000a1c <__libc_fini_array+0x34> +80000a30: 83 20 c1 00 lw ra, 12(sp) +80000a34: 03 24 81 00 lw s0, 8(sp) +80000a38: 83 24 41 00 lw s1, 4(sp) +80000a3c: 13 01 01 01 addi sp, sp, 16 +80000a40: 67 80 00 00 ret + +80000a44 : +80000a44: 13 01 01 fe addi sp, sp, -32 +80000a48: 23 2e 11 00 sw ra, 28(sp) +80000a4c: 23 2c 81 00 sw s0, 24(sp) +80000a50: 23 2a 91 00 sw s1, 20(sp) +80000a54: 23 28 21 01 sw s2, 16(sp) +80000a58: 23 26 31 01 sw s3, 12(sp) +80000a5c: 23 24 41 01 sw s4, 8(sp) +80000a60: 73 25 00 fc csrr a0, nt +80000a64: 73 26 20 cc csrr a2, cid +80000a68: 73 27 10 cc csrr a4, wid +80000a6c: f3 26 00 cc csrr a3, tid +80000a70: 97 37 00 00 auipc a5, 3 +80000a74: 93 87 c7 55 addi a5, a5, 1372 +80000a78: 13 16 26 00 slli a2, a2, 2 +80000a7c: b3 87 c7 00 add a5, a5, a2 +80000a80: 83 a4 07 00 lw s1, 0(a5) +80000a84: 83 a7 44 01 lw a5, 20(s1) +80000a88: 03 a6 04 01 lw a2, 16(s1) +80000a8c: 33 2a f7 00 slt s4, a4, a5 +80000a90: 33 04 e6 02 mul s0, a2, a4 +80000a94: 33 0a ca 00 add s4, s4, a2 +80000a98: 63 54 f7 00 bge a4, a5, 0x80000aa0 +80000a9c: 93 07 07 00 mv a5, a4 +80000aa0: 33 04 f4 00 add s0, s0, a5 +80000aa4: 83 a5 04 00 lw a1, 0(s1) +80000aa8: 03 a6 c4 00 lw a2, 12(s1) +80000aac: 03 c7 84 01 lbu a4, 24(s1) +80000ab0: 03 a9 05 00 lw s2, 0(a1) +80000ab4: 83 a9 45 00 lw s3, 4(a1) +80000ab8: 33 04 a4 02 mul s0, s0, a0 +80000abc: b3 07 da 02 mul a5, s4, a3 +80000ac0: 33 04 c4 00 add s0, s0, a2 +80000ac4: 33 04 f4 00 add s0, s0, a5 +80000ac8: b3 09 39 03 mul s3, s2, s3 +80000acc: 33 0a 8a 00 add s4, s4, s0 +80000ad0: 63 00 07 08 beqz a4, 0x80000b50 +80000ad4: 63 44 44 03 blt s0, s4, 0x80000afc +80000ad8: 83 20 c1 01 lw ra, 28(sp) +80000adc: 03 24 81 01 lw s0, 24(sp) +80000ae0: 83 24 41 01 lw s1, 20(sp) +80000ae4: 03 29 01 01 lw s2, 16(sp) +80000ae8: 83 29 c1 00 lw s3, 12(sp) +80000aec: 03 2a 81 00 lw s4, 8(sp) +80000af0: 13 01 01 02 addi sp, sp, 32 +80000af4: 67 80 00 00 ret +80000af8: 83 a5 04 00 lw a1, 0(s1) +80000afc: 03 c7 94 01 lbu a4, 25(s1) +80000b00: 83 c6 a4 01 lbu a3, 26(s1) +80000b04: 03 a8 44 00 lw a6, 4(s1) +80000b08: 33 57 e4 40 sra a4, s0, a4 +80000b0c: b3 87 e9 02 mul a5, s3, a4 +80000b10: 03 a5 84 00 lw a0, 8(s1) +80000b14: b3 07 f4 40 sub a5, s0, a5 +80000b18: b3 d6 d7 40 sra a3, a5, a3 +80000b1c: 33 06 d9 02 mul a2, s2, a3 +80000b20: 13 04 14 00 addi s0, s0, 1 +80000b24: 33 86 c7 40 sub a2, a5, a2 +80000b28: e7 00 08 00 jalr a6 +80000b2c: e3 16 8a fc bne s4, s0, 0x80000af8 +80000b30: 83 20 c1 01 lw ra, 28(sp) +80000b34: 03 24 81 01 lw s0, 24(sp) +80000b38: 83 24 41 01 lw s1, 20(sp) +80000b3c: 03 29 01 01 lw s2, 16(sp) +80000b40: 83 29 c1 00 lw s3, 12(sp) +80000b44: 03 2a 81 00 lw s4, 8(sp) +80000b48: 13 01 01 02 addi sp, sp, 32 +80000b4c: 67 80 00 00 ret +80000b50: 63 46 44 01 blt s0, s4, 0x80000b5c +80000b54: 6f f0 5f f8 j 0x80000ad8 +80000b58: 83 a5 04 00 lw a1, 0(s1) +80000b5c: 33 66 34 03 rem a2, s0, s3 +80000b60: 83 a7 44 00 lw a5, 4(s1) +80000b64: 03 a5 84 00 lw a0, 8(s1) +80000b68: 33 47 34 03 div a4, s0, s3 +80000b6c: 13 04 14 00 addi s0, s0, 1 +80000b70: b3 46 26 03 div a3, a2, s2 +80000b74: 33 66 26 03 rem a2, a2, s2 +80000b78: e7 80 07 00 jalr a5 +80000b7c: e3 1e 8a fc bne s4, s0, 0x80000b58 +80000b80: 83 20 c1 01 lw ra, 28(sp) +80000b84: 03 24 81 01 lw s0, 24(sp) +80000b88: 83 24 41 01 lw s1, 20(sp) +80000b8c: 03 29 01 01 lw s2, 16(sp) +80000b90: 83 29 c1 00 lw s3, 12(sp) +80000b94: 03 2a 81 00 lw s4, 8(sp) +80000b98: 13 01 01 02 addi sp, sp, 32 +80000b9c: 67 80 00 00 ret + +80000ba0 : +80000ba0: 73 27 20 cc csrr a4, cid +80000ba4: 73 28 00 cc csrr a6, tid +80000ba8: 97 37 00 00 auipc a5, 3 +80000bac: 93 87 47 42 addi a5, a5, 1060 +80000bb0: 13 17 27 00 slli a4, a4, 2 +80000bb4: b3 87 e7 00 add a5, a5, a4 +80000bb8: 83 a7 07 00 lw a5, 0(a5) +80000bbc: 83 a5 07 00 lw a1, 0(a5) +80000bc0: 83 a6 c7 00 lw a3, 12(a5) +80000bc4: 03 c7 87 01 lbu a4, 24(a5) +80000bc8: 03 a6 05 00 lw a2, 0(a1) +80000bcc: 83 a8 45 00 lw a7, 4(a1) +80000bd0: 33 08 d8 00 add a6, a6, a3 +80000bd4: b3 08 16 03 mul a7, a2, a7 +80000bd8: 63 08 07 02 beqz a4, 0x80000c08 +80000bdc: 03 c7 97 01 lbu a4, 25(a5) +80000be0: 83 c6 a7 01 lbu a3, 26(a5) +80000be4: 03 a3 47 00 lw t1, 4(a5) +80000be8: 33 57 e8 40 sra a4, a6, a4 +80000bec: 03 a5 87 00 lw a0, 8(a5) +80000bf0: b3 88 e8 02 mul a7, a7, a4 +80000bf4: 33 08 18 41 sub a6, a6, a7 +80000bf8: b3 56 d8 40 sra a3, a6, a3 +80000bfc: 33 06 d6 02 mul a2, a2, a3 +80000c00: 33 06 c8 40 sub a2, a6, a2 +80000c04: 67 00 03 00 jr t1 +80000c08: 33 63 18 03 rem t1, a6, a7 +80000c0c: 03 ae 47 00 lw t3, 4(a5) +80000c10: 03 a5 87 00 lw a0, 8(a5) +80000c14: b3 46 c3 02 div a3, t1, a2 +80000c18: 33 47 18 03 div a4, a6, a7 +80000c1c: 33 66 c3 02 rem a2, t1, a2 +80000c20: 67 00 0e 00 jr t3 + +80000c24 : +80000c24: 13 01 01 ff addi sp, sp, -16 +80000c28: 23 26 11 00 sw ra, 12(sp) +80000c2c: 93 07 f0 ff li a5, -1 +80000c30: 0b 80 07 00 vx_tmc a5 +80000c34: ef f0 1f e1 jal 0x80000a44 +80000c38: 0b 00 00 00 vx_tmc zero +80000c3c: 83 20 c1 00 lw ra, 12(sp) +80000c40: 13 01 01 01 addi sp, sp, 16 +80000c44: 67 80 00 00 ret + +80000c48 : +80000c48: 13 01 01 f9 addi sp, sp, -112 +80000c4c: 23 2e 31 05 sw s3, 92(sp) +80000c50: 23 2a 51 05 sw s5, 84(sp) +80000c54: 83 29 45 00 lw s3, 4(a0) +80000c58: 83 2a 05 00 lw s5, 0(a0) +80000c5c: 03 27 85 00 lw a4, 8(a0) +80000c60: 23 26 11 06 sw ra, 108(sp) +80000c64: 23 24 81 06 sw s0, 104(sp) +80000c68: 23 22 91 06 sw s1, 100(sp) +80000c6c: 23 20 21 07 sw s2, 96(sp) +80000c70: 23 2c 41 05 sw s4, 88(sp) +80000c74: 23 28 61 05 sw s6, 80(sp) +80000c78: 23 26 71 05 sw s7, 76(sp) +80000c7c: 23 24 81 05 sw s8, 72(sp) +80000c80: 23 22 91 05 sw s9, 68(sp) +80000c84: 23 20 a1 05 sw s10, 64(sp) +80000c88: 23 2e b1 03 sw s11, 60(sp) +80000c8c: f3 26 20 fc csrr a3, nw +80000c90: f3 2c 10 fc csrr s9, nw +80000c94: 73 2d 00 fc csrr s10, nt +80000c98: f3 24 20 cc csrr s1, cid +80000c9c: 93 07 f0 3f li a5, 1023 +80000ca0: 63 c4 97 0e blt a5, s1, 0x80000d88 +80000ca4: b3 89 3a 03 mul s3, s5, s3 +80000ca8: 93 0b 06 00 mv s7, a2 +80000cac: 13 04 05 00 mv s0, a0 +80000cb0: 13 8c 05 00 mv s8, a1 +80000cb4: 93 07 10 00 li a5, 1 +80000cb8: 33 07 37 03 mul a4, a4, s3 +80000cbc: 33 86 ac 03 mul a2, s9, s10 +80000cc0: 63 54 e6 00 bge a2, a4, 0x80000cc8 +80000cc4: b3 47 c7 02 div a5, a4, a2 +80000cc8: 63 ce f6 0e blt a3, a5, 0x80000dc4 +80000ccc: 63 de f4 0a bge s1, a5, 0x80000d88 +80000cd0: 13 86 f7 ff addi a2, a5, -1 +80000cd4: b3 46 f7 02 div a3, a4, a5 +80000cd8: 13 8a 06 00 mv s4, a3 +80000cdc: 63 16 96 00 bne a2, s1, 0x80000ce8 +80000ce0: 33 67 f7 02 rem a4, a4, a5 +80000ce4: 33 0a d7 00 add s4, a4, a3 +80000ce8: b3 4d aa 03 div s11, s4, s10 +80000cec: 33 6a aa 03 rem s4, s4, s10 +80000cf0: 63 c0 9d 0f blt s11, s9, 0x80000dd0 +80000cf4: b3 e7 9d 03 rem a5, s11, s9 +80000cf8: 33 cb 9d 03 div s6, s11, s9 +80000cfc: 23 26 f1 00 sw a5, 12(sp) +80000d00: 13 85 09 00 mv a0, s3 +80000d04: 23 24 d1 00 sw a3, 8(sp) +80000d08: ef 10 90 0e jal 0x800025f0 <__clzsi2> +80000d0c: 13 09 05 00 mv s2, a0 +80000d10: 13 85 0a 00 mv a0, s5 +80000d14: ef 10 d0 0d jal 0x800025f0 <__clzsi2> +80000d18: 83 26 81 00 lw a3, 8(sp) +80000d1c: 13 07 f0 01 li a4, 31 +80000d20: 33 09 27 41 sub s2, a4, s2 +80000d24: 93 87 f9 ff addi a5, s3, -1 +80000d28: b3 f7 37 01 and a5, a5, s3 +80000d2c: 13 79 f9 0f andi s2, s2, 255 +80000d30: 13 19 89 00 slli s2, s2, 8 +80000d34: 93 b7 17 00 seqz a5, a5 +80000d38: b3 e7 27 01 or a5, a5, s2 +80000d3c: 17 36 00 00 auipc a2, 3 +80000d40: 13 06 06 29 addi a2, a2, 656 +80000d44: 33 07 a7 40 sub a4, a4, a0 +80000d48: 23 16 f1 02 sh a5, 44(sp) +80000d4c: 93 07 41 01 addi a5, sp, 20 +80000d50: 23 2a 81 00 sw s0, 20(sp) +80000d54: 23 2c 81 01 sw s8, 24(sp) +80000d58: 23 2e 71 01 sw s7, 28(sp) +80000d5c: 23 22 61 03 sw s6, 36(sp) +80000d60: 23 07 e1 02 sb a4, 46(sp) +80000d64: b3 86 96 02 mul a3, a3, s1 +80000d68: 93 94 24 00 slli s1, s1, 2 +80000d6c: 33 06 96 00 add a2, a2, s1 +80000d70: 23 20 f6 00 sw a5, 0(a2) +80000d74: 23 20 d1 02 sw a3, 32(sp) +80000d78: 83 26 c1 00 lw a3, 12(sp) +80000d7c: 23 24 d1 02 sw a3, 40(sp) +80000d80: 63 4e b0 05 bgtz s11, 0x80000ddc +80000d84: 63 16 0a 08 bnez s4, 0x80000e10 +80000d88: 83 20 c1 06 lw ra, 108(sp) +80000d8c: 03 24 81 06 lw s0, 104(sp) +80000d90: 83 24 41 06 lw s1, 100(sp) +80000d94: 03 29 01 06 lw s2, 96(sp) +80000d98: 83 29 c1 05 lw s3, 92(sp) +80000d9c: 03 2a 81 05 lw s4, 88(sp) +80000da0: 83 2a 41 05 lw s5, 84(sp) +80000da4: 03 2b 01 05 lw s6, 80(sp) +80000da8: 83 2b c1 04 lw s7, 76(sp) +80000dac: 03 2c 81 04 lw s8, 72(sp) +80000db0: 83 2c 41 04 lw s9, 68(sp) +80000db4: 03 2d 01 04 lw s10, 64(sp) +80000db8: 83 2d c1 03 lw s11, 60(sp) +80000dbc: 13 01 01 07 addi sp, sp, 112 +80000dc0: 67 80 00 00 ret +80000dc4: 93 87 06 00 mv a5, a3 +80000dc8: e3 c4 f4 f0 blt s1, a5, 0x80000cd0 +80000dcc: 6f f0 df fb j 0x80000d88 +80000dd0: 23 26 01 00 sw zero, 12(sp) +80000dd4: 13 0b 10 00 li s6, 1 +80000dd8: 6f f0 9f f2 j 0x80000d00 +80000ddc: 93 87 0d 00 mv a5, s11 +80000de0: 63 d4 bc 01 bge s9, s11, 0x80000de8 +80000de4: 93 87 0c 00 mv a5, s9 +80000de8: 17 07 00 00 auipc a4, 0 +80000dec: 13 07 c7 e3 addi a4, a4, -452 +80000df0: 0b 90 e7 00 vx_wspawn a5, a4 +80000df4: 93 07 f0 ff li a5, -1 +80000df8: 0b 80 07 00 vx_tmc a5 +80000dfc: ef f0 9f c4 jal 0x80000a44 +80000e00: 13 05 10 00 li a0, 1 +80000e04: 0b 00 05 00 vx_tmc a0 +80000e08: ef f0 9f af jal 0x80000900 +80000e0c: e3 0e 0a f6 beqz s4, 0x80000d88 +80000e10: b3 8d ad 03 mul s11, s11, s10 +80000e14: 03 27 01 02 lw a4, 32(sp) +80000e18: 93 07 10 00 li a5, 1 +80000e1c: b3 97 47 01 sll a5, a5, s4 +80000e20: 93 87 f7 ff addi a5, a5, -1 +80000e24: 33 07 b7 01 add a4, a4, s11 +80000e28: 23 20 e1 02 sw a4, 32(sp) +80000e2c: 0b 80 07 00 vx_tmc a5 +80000e30: ef f0 1f d7 jal 0x80000ba0 +80000e34: 13 05 10 00 li a0, 1 +80000e38: 0b 00 05 00 vx_tmc a0 +80000e3c: 6f f0 df f4 j 0x80000d88 + +80000e40 : +80000e40: f3 27 20 cc csrr a5, cid +80000e44: 37 47 00 ff lui a4, 1044484 +80000e48: 13 07 07 04 addi a4, a4, 64 +80000e4c: 93 97 87 00 slli a5, a5, 8 +80000e50: b3 87 e7 00 add a5, a5, a4 +80000e54: 73 27 00 b0 csrr a4, mcycle +80000e58: 23 a0 e7 00 sw a4, 0(a5) +80000e5c: 73 27 10 b0 csrr a4, 2817 +80000e60: 23 a2 e7 00 sw a4, 4(a5) +80000e64: 73 27 20 b0 csrr a4, minstret +80000e68: 23 a4 e7 00 sw a4, 8(a5) +80000e6c: 73 27 30 b0 csrr a4, mhpmcounter3 +80000e70: 23 a6 e7 00 sw a4, 12(a5) +80000e74: 73 27 40 b0 csrr a4, mhpmcounter4 +80000e78: 23 a8 e7 00 sw a4, 16(a5) +80000e7c: 73 27 50 b0 csrr a4, mhpmcounter5 +80000e80: 23 aa e7 00 sw a4, 20(a5) +80000e84: 73 27 60 b0 csrr a4, mhpmcounter6 +80000e88: 23 ac e7 00 sw a4, 24(a5) +80000e8c: 73 27 70 b0 csrr a4, mhpmcounter7 +80000e90: 23 ae e7 00 sw a4, 28(a5) +80000e94: 73 27 80 b0 csrr a4, mhpmcounter8 +80000e98: 23 a0 e7 02 sw a4, 32(a5) +80000e9c: 73 27 90 b0 csrr a4, mhpmcounter9 +80000ea0: 23 a2 e7 02 sw a4, 36(a5) +80000ea4: 73 27 a0 b0 csrr a4, mhpmcounter10 +80000ea8: 23 a4 e7 02 sw a4, 40(a5) +80000eac: 73 27 b0 b0 csrr a4, mhpmcounter11 +80000eb0: 23 a6 e7 02 sw a4, 44(a5) +80000eb4: 73 27 c0 b0 csrr a4, mhpmcounter12 +80000eb8: 23 a8 e7 02 sw a4, 48(a5) +80000ebc: 73 27 d0 b0 csrr a4, mhpmcounter13 +80000ec0: 23 aa e7 02 sw a4, 52(a5) +80000ec4: 73 27 e0 b0 csrr a4, mhpmcounter14 +80000ec8: 23 ac e7 02 sw a4, 56(a5) +80000ecc: 73 27 f0 b0 csrr a4, mhpmcounter15 +80000ed0: 23 ae e7 02 sw a4, 60(a5) +80000ed4: 73 27 00 b1 csrr a4, mhpmcounter16 +80000ed8: 23 a0 e7 04 sw a4, 64(a5) +80000edc: 73 27 10 b1 csrr a4, mhpmcounter17 +80000ee0: 23 a2 e7 04 sw a4, 68(a5) +80000ee4: 73 27 20 b1 csrr a4, mhpmcounter18 +80000ee8: 23 a4 e7 04 sw a4, 72(a5) +80000eec: 73 27 30 b1 csrr a4, mhpmcounter19 +80000ef0: 23 a6 e7 04 sw a4, 76(a5) +80000ef4: 73 27 40 b1 csrr a4, mhpmcounter20 +80000ef8: 23 a8 e7 04 sw a4, 80(a5) +80000efc: 73 27 50 b1 csrr a4, mhpmcounter21 +80000f00: 23 aa e7 04 sw a4, 84(a5) +80000f04: 73 27 60 b1 csrr a4, mhpmcounter22 +80000f08: 23 ac e7 04 sw a4, 88(a5) +80000f0c: 73 27 70 b1 csrr a4, mhpmcounter23 +80000f10: 23 ae e7 04 sw a4, 92(a5) +80000f14: 73 27 80 b1 csrr a4, mhpmcounter24 +80000f18: 23 a0 e7 06 sw a4, 96(a5) +80000f1c: 73 27 90 b1 csrr a4, mhpmcounter25 +80000f20: 23 a2 e7 06 sw a4, 100(a5) +80000f24: 73 27 a0 b1 csrr a4, mhpmcounter26 +80000f28: 23 a4 e7 06 sw a4, 104(a5) +80000f2c: 73 27 b0 b1 csrr a4, mhpmcounter27 +80000f30: 23 a6 e7 06 sw a4, 108(a5) +80000f34: 73 27 c0 b1 csrr a4, mhpmcounter28 +80000f38: 23 a8 e7 06 sw a4, 112(a5) +80000f3c: 73 27 d0 b1 csrr a4, mhpmcounter29 +80000f40: 23 aa e7 06 sw a4, 116(a5) +80000f44: 73 27 e0 b1 csrr a4, mhpmcounter30 +80000f48: 23 ac e7 06 sw a4, 120(a5) +80000f4c: 73 27 f0 b1 csrr a4, mhpmcounter31 +80000f50: 23 ae e7 06 sw a4, 124(a5) +80000f54: 73 27 00 b8 csrr a4, mcycleh +80000f58: 23 a0 e7 08 sw a4, 128(a5) +80000f5c: 73 27 10 b8 csrr a4, 2945 +80000f60: 23 a2 e7 08 sw a4, 132(a5) +80000f64: 73 27 20 b8 csrr a4, minstreth +80000f68: 23 a4 e7 08 sw a4, 136(a5) +80000f6c: 73 27 30 b8 csrr a4, mhpmcounter3h +80000f70: 23 a6 e7 08 sw a4, 140(a5) +80000f74: 73 27 40 b8 csrr a4, mhpmcounter4h +80000f78: 23 a8 e7 08 sw a4, 144(a5) +80000f7c: 73 27 50 b8 csrr a4, mhpmcounter5h +80000f80: 23 aa e7 08 sw a4, 148(a5) +80000f84: 73 27 60 b8 csrr a4, mhpmcounter6h +80000f88: 23 ac e7 08 sw a4, 152(a5) +80000f8c: 73 27 70 b8 csrr a4, mhpmcounter7h +80000f90: 23 ae e7 08 sw a4, 156(a5) +80000f94: 73 27 80 b8 csrr a4, mhpmcounter8h +80000f98: 23 a0 e7 0a sw a4, 160(a5) +80000f9c: 73 27 90 b8 csrr a4, mhpmcounter9h +80000fa0: 23 a2 e7 0a sw a4, 164(a5) +80000fa4: 73 27 a0 b8 csrr a4, mhpmcounter10h +80000fa8: 23 a4 e7 0a sw a4, 168(a5) +80000fac: 73 27 b0 b8 csrr a4, mhpmcounter11h +80000fb0: 23 a6 e7 0a sw a4, 172(a5) +80000fb4: 73 27 c0 b8 csrr a4, mhpmcounter12h +80000fb8: 23 a8 e7 0a sw a4, 176(a5) +80000fbc: 73 27 d0 b8 csrr a4, mhpmcounter13h +80000fc0: 23 aa e7 0a sw a4, 180(a5) +80000fc4: 73 27 e0 b8 csrr a4, mhpmcounter14h +80000fc8: 23 ac e7 0a sw a4, 184(a5) +80000fcc: 73 27 f0 b8 csrr a4, mhpmcounter15h +80000fd0: 23 ae e7 0a sw a4, 188(a5) +80000fd4: 73 27 00 b9 csrr a4, mhpmcounter16h +80000fd8: 23 a0 e7 0c sw a4, 192(a5) +80000fdc: 73 27 10 b9 csrr a4, mhpmcounter17h +80000fe0: 23 a2 e7 0c sw a4, 196(a5) +80000fe4: 73 27 20 b9 csrr a4, mhpmcounter18h +80000fe8: 23 a4 e7 0c sw a4, 200(a5) +80000fec: 73 27 30 b9 csrr a4, mhpmcounter19h +80000ff0: 23 a6 e7 0c sw a4, 204(a5) +80000ff4: 73 27 40 b9 csrr a4, mhpmcounter20h +80000ff8: 23 a8 e7 0c sw a4, 208(a5) +80000ffc: 73 27 50 b9 csrr a4, mhpmcounter21h +80001000: 23 aa e7 0c sw a4, 212(a5) +80001004: 73 27 60 b9 csrr a4, mhpmcounter22h +80001008: 23 ac e7 0c sw a4, 216(a5) +8000100c: 73 27 70 b9 csrr a4, mhpmcounter23h +80001010: 23 ae e7 0c sw a4, 220(a5) +80001014: 73 27 80 b9 csrr a4, mhpmcounter24h +80001018: 23 a0 e7 0e sw a4, 224(a5) +8000101c: 73 27 90 b9 csrr a4, mhpmcounter25h +80001020: 23 a2 e7 0e sw a4, 228(a5) +80001024: 73 27 a0 b9 csrr a4, mhpmcounter26h +80001028: 23 a4 e7 0e sw a4, 232(a5) +8000102c: 73 27 b0 b9 csrr a4, mhpmcounter27h +80001030: 23 a6 e7 0e sw a4, 236(a5) +80001034: 73 27 c0 b9 csrr a4, mhpmcounter28h +80001038: 23 a8 e7 0e sw a4, 240(a5) +8000103c: 73 27 d0 b9 csrr a4, mhpmcounter29h +80001040: 23 aa e7 0e sw a4, 244(a5) +80001044: 73 27 e0 b9 csrr a4, mhpmcounter30h +80001048: 23 ac e7 0e sw a4, 248(a5) +8000104c: 73 27 f0 b9 csrr a4, mhpmcounter31h +80001050: 23 ae e7 0e sw a4, 252(a5) +80001054: 67 80 00 00 ret + +80001058 : +80001058: d3 07 05 e0 fmv.x.w a5, fa0 +8000105c: b7 16 49 3f lui a3, 259217 +80001060: 93 86 86 fd addi a3, a3, -40 +80001064: 13 97 17 00 slli a4, a5, 1 +80001068: 13 57 17 00 srli a4, a4, 1 +8000106c: 63 fc e6 04 bgeu a3, a4, 0x800010c4 +80001070: b7 06 80 7f lui a3, 522240 +80001074: 63 66 d7 00 bltu a4, a3, 0x80001080 +80001078: 53 75 a5 08 fsub.s fa0, fa0, fa0 +8000107c: 67 80 00 00 ret +80001080: 13 01 01 fe addi sp, sp, -32 +80001084: 13 05 81 00 addi a0, sp, 8 +80001088: 23 2e 11 00 sw ra, 28(sp) +8000108c: ef 00 00 11 jal 0x8000119c <__ieee754_rem_pio2f> +80001090: 13 75 35 00 andi a0, a0, 3 +80001094: 93 07 10 00 li a5, 1 +80001098: 63 0a f5 02 beq a0, a5, 0x800010cc +8000109c: 93 07 20 00 li a5, 2 +800010a0: 87 25 c1 00 flw fa1, 12(sp) +800010a4: 07 25 81 00 flw fa0, 8(sp) +800010a8: 63 02 f5 04 beq a0, a5, 0x800010ec +800010ac: 63 0c 05 02 beqz a0, 0x800010e4 +800010b0: 13 05 10 00 li a0, 1 +800010b4: ef 00 10 64 jal 0x80001ef4 <__kernel_sinf> +800010b8: 83 20 c1 01 lw ra, 28(sp) +800010bc: 13 01 01 02 addi sp, sp, 32 +800010c0: 67 80 00 00 ret +800010c4: d3 05 00 f0 fmv.w.x fa1, zero +800010c8: 6f 00 00 3f j 0x800014b8 <__kernel_cosf> +800010cc: 87 25 c1 00 flw fa1, 12(sp) +800010d0: 07 25 81 00 flw fa0, 8(sp) +800010d4: 13 05 10 00 li a0, 1 +800010d8: ef 00 d0 61 jal 0x80001ef4 <__kernel_sinf> +800010dc: 53 15 a5 20 fneg.s fa0, fa0 +800010e0: 6f f0 9f fd j 0x800010b8 +800010e4: ef 00 40 3d jal 0x800014b8 <__kernel_cosf> +800010e8: 6f f0 1f fd j 0x800010b8 +800010ec: ef 00 c0 3c jal 0x800014b8 <__kernel_cosf> +800010f0: 53 15 a5 20 fneg.s fa0, fa0 +800010f4: 6f f0 5f fc j 0x800010b8 + +800010f8 : +800010f8: d3 07 05 e0 fmv.x.w a5, fa0 +800010fc: b7 16 49 3f lui a3, 259217 +80001100: 93 86 86 fd addi a3, a3, -40 +80001104: 13 97 17 00 slli a4, a5, 1 +80001108: 13 57 17 00 srli a4, a4, 1 +8000110c: 63 fc e6 04 bgeu a3, a4, 0x80001164 +80001110: b7 06 80 7f lui a3, 522240 +80001114: 63 66 d7 00 bltu a4, a3, 0x80001120 +80001118: 53 75 a5 08 fsub.s fa0, fa0, fa0 +8000111c: 67 80 00 00 ret +80001120: 13 01 01 fe addi sp, sp, -32 +80001124: 13 05 81 00 addi a0, sp, 8 +80001128: 23 2e 11 00 sw ra, 28(sp) +8000112c: ef 00 00 07 jal 0x8000119c <__ieee754_rem_pio2f> +80001130: 13 75 35 00 andi a0, a0, 3 +80001134: 93 07 10 00 li a5, 1 +80001138: 63 0c f5 02 beq a0, a5, 0x80001170 +8000113c: 93 07 20 00 li a5, 2 +80001140: 87 25 c1 00 flw fa1, 12(sp) +80001144: 07 25 81 00 flw fa0, 8(sp) +80001148: 63 02 f5 04 beq a0, a5, 0x8000118c +8000114c: 63 0a 05 02 beqz a0, 0x80001180 +80001150: ef 00 80 36 jal 0x800014b8 <__kernel_cosf> +80001154: 53 15 a5 20 fneg.s fa0, fa0 +80001158: 83 20 c1 01 lw ra, 28(sp) +8000115c: 13 01 01 02 addi sp, sp, 32 +80001160: 67 80 00 00 ret +80001164: d3 05 00 f0 fmv.w.x fa1, zero +80001168: 13 05 00 00 li a0, 0 +8000116c: 6f 00 90 58 j 0x80001ef4 <__kernel_sinf> +80001170: 87 25 c1 00 flw fa1, 12(sp) +80001174: 07 25 81 00 flw fa0, 8(sp) +80001178: ef 00 00 34 jal 0x800014b8 <__kernel_cosf> +8000117c: 6f f0 df fd j 0x80001158 +80001180: 13 05 10 00 li a0, 1 +80001184: ef 00 10 57 jal 0x80001ef4 <__kernel_sinf> +80001188: 6f f0 1f fd j 0x80001158 +8000118c: 13 05 10 00 li a0, 1 +80001190: ef 00 50 56 jal 0x80001ef4 <__kernel_sinf> +80001194: 53 15 a5 20 fneg.s fa0, fa0 +80001198: 6f f0 1f fc j 0x80001158 + +8000119c <__ieee754_rem_pio2f>: +8000119c: 13 01 01 fd addi sp, sp, -48 +800011a0: 23 22 91 02 sw s1, 36(sp) +800011a4: d3 04 05 e0 fmv.x.w s1, fa0 +800011a8: 23 20 21 03 sw s2, 32(sp) +800011ac: 37 09 00 80 lui s2, 524288 +800011b0: 23 24 81 02 sw s0, 40(sp) +800011b4: b7 17 49 3f lui a5, 259217 +800011b8: 13 44 f9 ff not s0, s2 +800011bc: 23 2e 31 01 sw s3, 28(sp) +800011c0: 23 26 11 02 sw ra, 44(sp) +800011c4: 23 2c 41 01 sw s4, 24(sp) +800011c8: 33 74 94 00 and s0, s0, s1 +800011cc: 93 87 87 fd addi a5, a5, -40 +800011d0: 93 09 05 00 mv s3, a0 +800011d4: 63 f6 87 12 bgeu a5, s0, 0x80001300 <__ieee754_rem_pio2f+0x164> +800011d8: b7 d7 16 40 lui a5, 262509 +800011dc: 93 87 37 be addi a5, a5, -1053 +800011e0: 13 8a 04 00 mv s4, s1 +800011e4: 63 e4 87 06 bltu a5, s0, 0x8000124c <__ieee754_rem_pio2f+0xb0> +800011e8: 97 37 00 00 auipc a5, 3 +800011ec: 87 a7 87 d5 flw fa5, -680(a5) +800011f0: 13 49 09 ff xori s2, s2, -16 +800011f4: b7 17 c9 3f lui a5, 261265 +800011f8: 33 79 99 00 and s2, s2, s1 +800011fc: 93 87 07 fd addi a5, a5, -48 +80001200: 63 54 90 26 blez s1, 0x80001468 <__ieee754_rem_pio2f+0x2cc> +80001204: d3 77 f5 08 fsub.s fa5, fa0, fa5 +80001208: 63 0e f9 10 beq s2, a5, 0x80001324 <__ieee754_rem_pio2f+0x188> +8000120c: 97 37 00 00 auipc a5, 3 +80001210: 87 a6 87 d3 flw fa3, -712(a5) +80001214: 53 f7 d7 08 fsub.s fa4, fa5, fa3 +80001218: d3 f7 e7 08 fsub.s fa5, fa5, fa4 +8000121c: d3 f7 d7 08 fsub.s fa5, fa5, fa3 +80001220: 27 a0 e9 00 fsw fa4, 0(s3) +80001224: 27 a2 f9 00 fsw fa5, 4(s3) +80001228: 13 05 10 00 li a0, 1 +8000122c: 83 20 c1 02 lw ra, 44(sp) +80001230: 03 24 81 02 lw s0, 40(sp) +80001234: 83 24 41 02 lw s1, 36(sp) +80001238: 03 29 01 02 lw s2, 32(sp) +8000123c: 83 29 c1 01 lw s3, 28(sp) +80001240: 03 2a 81 01 lw s4, 24(sp) +80001244: 13 01 01 03 addi sp, sp, 48 +80001248: 67 80 00 00 ret +8000124c: b7 17 49 43 lui a5, 275601 +80001250: 93 87 07 f8 addi a5, a5, -128 +80001254: 63 fa 87 0e bgeu a5, s0, 0x80001348 <__ieee754_rem_pio2f+0x1ac> +80001258: b7 07 80 7f lui a5, 522240 +8000125c: 63 7a f4 0a bgeu s0, a5, 0x80001310 <__ieee754_rem_pio2f+0x174> +80001260: 13 56 74 41 srai a2, s0, 23 +80001264: 13 06 a6 f7 addi a2, a2, -134 +80001268: 93 17 76 01 slli a5, a2, 23 +8000126c: 33 04 f4 40 sub s0, s0, a5 +80001270: d3 07 04 f0 fmv.w.x fa5, s0 +80001274: 17 37 00 00 auipc a4, 3 +80001278: 87 26 c7 ce flw fa3, -788(a4) +8000127c: 53 06 00 f0 fmv.w.x fa2, zero +80001280: d3 97 07 c0 fcvt.w.s a5, fa5, rtz +80001284: 93 06 30 00 li a3, 3 +80001288: 53 f7 07 d0 fcvt.s.w fa4, a5 +8000128c: d3 f7 e7 08 fsub.s fa5, fa5, fa4 +80001290: 27 22 e1 00 fsw fa4, 4(sp) +80001294: d3 f7 d7 10 fmul.s fa5, fa5, fa3 +80001298: d3 97 07 c0 fcvt.w.s a5, fa5, rtz +8000129c: 53 f7 07 d0 fcvt.s.w fa4, a5 +800012a0: d3 f7 e7 08 fsub.s fa5, fa5, fa4 +800012a4: 27 24 e1 00 fsw fa4, 8(sp) +800012a8: d3 f7 d7 10 fmul.s fa5, fa5, fa3 +800012ac: d3 a7 c7 a0 feq.s a5, fa5, fa2 +800012b0: 27 26 f1 00 fsw fa5, 12(sp) +800012b4: 63 88 07 00 beqz a5, 0x800012c4 <__ieee754_rem_pio2f+0x128> +800012b8: d3 26 c7 a0 feq.s a3, fa4, fa2 +800012bc: 93 b6 16 00 seqz a3, a3 +800012c0: 93 86 16 00 addi a3, a3, 1 +800012c4: 97 17 00 00 auipc a5, 1 +800012c8: 93 87 07 40 addi a5, a5, 1024 +800012cc: 13 07 20 00 li a4, 2 +800012d0: 93 85 09 00 mv a1, s3 +800012d4: 13 05 41 00 addi a0, sp, 4 +800012d8: ef 00 c0 32 jal 0x80001604 <__kernel_rem_pio2f> +800012dc: e3 58 0a f4 bgez s4, 0x8000122c <__ieee754_rem_pio2f+0x90> +800012e0: 07 a7 09 00 flw fa4, 0(s3) +800012e4: 87 a7 49 00 flw fa5, 4(s3) +800012e8: 33 05 a0 40 neg a0, a0 +800012ec: 53 17 e7 20 fneg.s fa4, fa4 +800012f0: d3 97 f7 20 fneg.s fa5, fa5 +800012f4: 27 a0 e9 00 fsw fa4, 0(s3) +800012f8: 27 a2 f9 00 fsw fa5, 4(s3) +800012fc: 6f f0 1f f3 j 0x8000122c <__ieee754_rem_pio2f+0x90> +80001300: 27 a0 a9 00 fsw fa0, 0(s3) +80001304: 23 22 05 00 sw zero, 4(a0) +80001308: 13 05 00 00 li a0, 0 +8000130c: 6f f0 1f f2 j 0x8000122c <__ieee754_rem_pio2f+0x90> +80001310: d3 77 a5 08 fsub.s fa5, fa0, fa0 +80001314: 27 22 f5 00 fsw fa5, 4(a0) +80001318: 27 20 f5 00 fsw fa5, 0(a0) +8000131c: 13 05 00 00 li a0, 0 +80001320: 6f f0 df f0 j 0x8000122c <__ieee754_rem_pio2f+0x90> +80001324: 97 37 00 00 auipc a5, 3 +80001328: 07 a7 47 c2 flw fa4, -988(a5) +8000132c: d3 f7 e7 08 fsub.s fa5, fa5, fa4 +80001330: 97 37 00 00 auipc a5, 3 +80001334: 87 a6 c7 c1 flw fa3, -996(a5) +80001338: 53 f7 d7 08 fsub.s fa4, fa5, fa3 +8000133c: d3 f7 e7 08 fsub.s fa5, fa5, fa4 +80001340: d3 f7 d7 08 fsub.s fa5, fa5, fa3 +80001344: 6f f0 df ed j 0x80001220 <__ieee754_rem_pio2f+0x84> +80001348: ef 00 90 45 jal 0x80001fa0 +8000134c: 97 37 00 00 auipc a5, 3 +80001350: 87 a6 47 c0 flw fa3, -1020(a5) +80001354: 97 37 00 00 auipc a5, 3 +80001358: 07 a6 07 c0 flw fa2, -1024(a5) +8000135c: c3 76 d5 60 fmadd.s fa3, fa0, fa3, fa2 +80001360: 97 37 00 00 auipc a5, 3 +80001364: 87 a7 07 be flw fa5, -1056(a5) +80001368: 97 37 00 00 auipc a5, 3 +8000136c: 07 a7 c7 bd flw fa4, -1060(a5) +80001370: 93 07 f0 01 li a5, 31 +80001374: 53 95 06 c0 fcvt.w.s a0, fa3, rtz +80001378: d3 76 05 d0 fcvt.s.w fa3, a0 +8000137c: cb f7 f6 50 fnmsub.s fa5, fa3, fa5, fa0 +80001380: 53 f7 e6 10 fmul.s fa4, fa3, fa4 +80001384: 63 c0 a7 06 blt a5, a0, 0x800013e4 <__ieee754_rem_pio2f+0x248> +80001388: 13 07 f5 ff addi a4, a0, -1 +8000138c: 13 17 27 00 slli a4, a4, 2 +80001390: 97 17 00 00 auipc a5, 1 +80001394: 93 87 47 2b addi a5, a5, 692 +80001398: b3 87 e7 00 add a5, a5, a4 +8000139c: 83 a7 07 00 lw a5, 0(a5) +800013a0: 13 49 09 f0 xori s2, s2, -256 +800013a4: 33 79 99 00 and s2, s2, s1 +800013a8: 63 0e f9 02 beq s2, a5, 0x800013e4 <__ieee754_rem_pio2f+0x248> +800013ac: d3 f6 e7 08 fsub.s fa3, fa5, fa4 +800013b0: d3 87 06 e0 fmv.x.w a5, fa3 +800013b4: d3 86 07 f0 fmv.w.x fa3, a5 +800013b8: 23 a0 f9 00 sw a5, 0(s3) +800013bc: d3 f7 d7 08 fsub.s fa5, fa5, fa3 +800013c0: d3 f7 e7 08 fsub.s fa5, fa5, fa4 +800013c4: 27 a2 f9 00 fsw fa5, 4(s3) +800013c8: e3 52 0a e6 bgez s4, 0x8000122c <__ieee754_rem_pio2f+0x90> +800013cc: 53 97 d6 20 fneg.s fa4, fa3 +800013d0: d3 97 f7 20 fneg.s fa5, fa5 +800013d4: 33 05 a0 40 neg a0, a0 +800013d8: 27 a0 e9 00 fsw fa4, 0(s3) +800013dc: 27 a2 f9 00 fsw fa5, 4(s3) +800013e0: 6f f0 df e4 j 0x8000122c <__ieee754_rem_pio2f+0x90> +800013e4: 53 f6 e7 08 fsub.s fa2, fa5, fa4 +800013e8: 13 54 74 41 srai s0, s0, 23 +800013ec: 93 06 80 00 li a3, 8 +800013f0: d3 07 06 e0 fmv.x.w a5, fa2 +800013f4: 13 d7 77 01 srli a4, a5, 23 +800013f8: 13 77 f7 0f andi a4, a4, 255 +800013fc: 33 07 e4 40 sub a4, s0, a4 +80001400: e3 da e6 fa bge a3, a4, 0x800013b4 <__ieee754_rem_pio2f+0x218> +80001404: 97 37 00 00 auipc a5, 3 +80001408: 87 a5 47 b4 flw fa1, -1212(a5) +8000140c: 4b f6 b6 78 fnmsub.s fa2, fa3, fa1, fa5 +80001410: 97 37 00 00 auipc a5, 3 +80001414: 07 a7 c7 b3 flw fa4, -1220(a5) +80001418: 93 06 90 01 li a3, 25 +8000141c: 53 f5 c7 08 fsub.s fa0, fa5, fa2 +80001420: d3 07 c6 20 fmv.s fa5, fa2 +80001424: cb f5 b6 50 fnmsub.s fa1, fa3, fa1, fa0 +80001428: 47 f7 e6 58 fmsub.s fa4, fa3, fa4, fa1 +8000142c: d3 75 e6 08 fsub.s fa1, fa2, fa4 +80001430: d3 87 05 e0 fmv.x.w a5, fa1 +80001434: 13 d7 77 01 srli a4, a5, 23 +80001438: 13 77 f7 0f andi a4, a4, 255 +8000143c: 33 04 e4 40 sub s0, s0, a4 +80001440: e3 da 86 f6 bge a3, s0, 0x800013b4 <__ieee754_rem_pio2f+0x218> +80001444: 97 37 00 00 auipc a5, 3 +80001448: 87 a5 47 b1 flw fa1, -1260(a5) +8000144c: cb f7 b6 60 fnmsub.s fa5, fa3, fa1, fa2 +80001450: 97 37 00 00 auipc a5, 3 +80001454: 07 a7 c7 b0 flw fa4, -1268(a5) +80001458: 53 76 f6 08 fsub.s fa2, fa2, fa5 +8000145c: cb f5 b6 60 fnmsub.s fa1, fa3, fa1, fa2 +80001460: 47 f7 e6 58 fmsub.s fa4, fa3, fa4, fa1 +80001464: 6f f0 9f f4 j 0x800013ac <__ieee754_rem_pio2f+0x210> +80001468: d3 77 f5 00 fadd.s fa5, fa0, fa5 +8000146c: 63 04 f9 02 beq s2, a5, 0x80001494 <__ieee754_rem_pio2f+0x2f8> +80001470: 97 37 00 00 auipc a5, 3 +80001474: 87 a6 47 ad flw fa3, -1324(a5) +80001478: 53 f7 d7 00 fadd.s fa4, fa5, fa3 +8000147c: d3 f7 e7 08 fsub.s fa5, fa5, fa4 +80001480: d3 f7 d7 00 fadd.s fa5, fa5, fa3 +80001484: 27 a0 e9 00 fsw fa4, 0(s3) +80001488: 27 a2 f9 00 fsw fa5, 4(s3) +8000148c: 13 05 f0 ff li a0, -1 +80001490: 6f f0 df d9 j 0x8000122c <__ieee754_rem_pio2f+0x90> +80001494: 97 37 00 00 auipc a5, 3 +80001498: 07 a7 47 ab flw fa4, -1356(a5) +8000149c: d3 f7 e7 00 fadd.s fa5, fa5, fa4 +800014a0: 97 37 00 00 auipc a5, 3 +800014a4: 87 a6 c7 aa flw fa3, -1364(a5) +800014a8: 53 f7 d7 00 fadd.s fa4, fa5, fa3 +800014ac: d3 f7 e7 08 fsub.s fa5, fa5, fa4 +800014b0: d3 f7 d7 00 fadd.s fa5, fa5, fa3 +800014b4: 6f f0 1f fd j 0x80001484 <__ieee754_rem_pio2f+0x2e8> + +800014b8 <__kernel_cosf>: +800014b8: d3 07 05 e0 fmv.x.w a5, fa0 +800014bc: b7 06 00 32 lui a3, 204800 +800014c0: 13 97 17 00 slli a4, a5, 1 +800014c4: 13 57 17 00 srli a4, a4, 1 +800014c8: 63 70 d7 08 bgeu a4, a3, 0x80001548 <__kernel_cosf+0x90> +800014cc: 53 17 05 c0 fcvt.w.s a4, fa0, rtz +800014d0: 63 04 07 12 beqz a4, 0x800015f8 <__kernel_cosf+0x140> +800014d4: 53 77 a5 10 fmul.s fa4, fa0, fa0 +800014d8: 17 37 00 00 auipc a4, 3 +800014dc: 87 26 c7 a9 flw fa3, -1380(a4) +800014e0: 17 37 00 00 auipc a4, 3 +800014e4: 87 27 07 a9 flw fa5, -1392(a4) +800014e8: 17 37 00 00 auipc a4, 3 +800014ec: 07 20 07 a9 flw ft0, -1392(a4) +800014f0: 17 37 00 00 auipc a4, 3 +800014f4: 07 25 c7 a8 flw fa0, -1396(a4) +800014f8: c3 77 f7 68 fmadd.s fa5, fa4, fa5, fa3 +800014fc: 17 37 00 00 auipc a4, 3 +80001500: 07 26 47 a8 flw fa2, -1404(a4) +80001504: 17 37 00 00 auipc a4, 3 +80001508: 87 26 07 a8 flw fa3, -1408(a4) +8000150c: c3 f7 e7 00 fmadd.s fa5, fa5, fa4, ft0 +80001510: c3 77 f7 50 fmadd.s fa5, fa4, fa5, fa0 +80001514: c3 77 f7 60 fmadd.s fa5, fa4, fa5, fa2 +80001518: c3 77 f7 68 fmadd.s fa5, fa4, fa5, fa3 +8000151c: d3 77 f7 10 fmul.s fa5, fa4, fa5 +80001520: d3 86 07 f0 fmv.w.x fa3, a5 +80001524: 97 37 00 00 auipc a5, 3 +80001528: 07 a5 87 a4 flw fa0, -1464(a5) +8000152c: d3 f5 b6 10 fmul.s fa1, fa3, fa1 +80001530: 97 37 00 00 auipc a5, 3 +80001534: 87 a6 47 a2 flw fa3, -1500(a5) +80001538: c7 77 f7 58 fmsub.s fa5, fa4, fa5, fa1 +8000153c: c7 77 d7 78 fmsub.s fa5, fa4, fa3, fa5 +80001540: 53 75 f5 08 fsub.s fa0, fa0, fa5 +80001544: 67 80 00 00 ret +80001548: 53 77 a5 10 fmul.s fa4, fa0, fa0 +8000154c: 97 36 00 00 auipc a3, 3 +80001550: 87 a6 86 a2 flw fa3, -1496(a3) +80001554: 97 36 00 00 auipc a3, 3 +80001558: 87 a7 c6 a1 flw fa5, -1508(a3) +8000155c: 97 36 00 00 auipc a3, 3 +80001560: 07 a0 c6 a1 flw ft0, -1508(a3) +80001564: 97 36 00 00 auipc a3, 3 +80001568: 07 a5 86 a1 flw fa0, -1512(a3) +8000156c: c3 77 f7 68 fmadd.s fa5, fa4, fa5, fa3 +80001570: 97 36 00 00 auipc a3, 3 +80001574: 07 a6 06 a1 flw fa2, -1520(a3) +80001578: 97 36 00 00 auipc a3, 3 +8000157c: 87 a6 c6 a0 flw fa3, -1524(a3) +80001580: b7 a6 99 3e lui a3, 256410 +80001584: 93 86 96 99 addi a3, a3, -1639 +80001588: c3 f7 e7 00 fmadd.s fa5, fa5, fa4, ft0 +8000158c: c3 f7 e7 50 fmadd.s fa5, fa5, fa4, fa0 +80001590: c3 f7 e7 60 fmadd.s fa5, fa5, fa4, fa2 +80001594: c3 f7 e7 68 fmadd.s fa5, fa5, fa4, fa3 +80001598: d3 f7 e7 10 fmul.s fa5, fa5, fa4 +8000159c: e3 f2 e6 f8 bgeu a3, a4, 0x80001520 <__kernel_cosf+0x68> +800015a0: b7 06 48 3f lui a3, 259200 +800015a4: 63 e0 e6 04 bltu a3, a4, 0x800015e4 <__kernel_cosf+0x12c> +800015a8: b7 06 00 ff lui a3, 1044480 +800015ac: 33 07 d7 00 add a4, a4, a3 +800015b0: d3 06 07 f0 fmv.w.x fa3, a4 +800015b4: 97 36 00 00 auipc a3, 3 +800015b8: 07 a5 86 9b flw fa0, -1608(a3) +800015bc: 53 75 d5 08 fsub.s fa0, fa0, fa3 +800015c0: 53 86 07 f0 fmv.w.x fa2, a5 +800015c4: d3 75 b6 10 fmul.s fa1, fa2, fa1 +800015c8: 97 37 00 00 auipc a5, 3 +800015cc: 07 a6 c7 98 flw fa2, -1652(a5) +800015d0: c7 76 c7 68 fmsub.s fa3, fa4, fa2, fa3 +800015d4: c7 77 f7 58 fmsub.s fa5, fa4, fa5, fa1 +800015d8: d3 f7 f6 08 fsub.s fa5, fa3, fa5 +800015dc: 53 75 f5 08 fsub.s fa0, fa0, fa5 +800015e0: 67 80 00 00 ret +800015e4: 17 37 00 00 auipc a4, 3 +800015e8: 07 25 07 98 flw fa0, -1664(a4) +800015ec: 17 37 00 00 auipc a4, 3 +800015f0: 87 26 c7 97 flw fa3, -1668(a4) +800015f4: 6f f0 df fc j 0x800015c0 <__kernel_cosf+0x108> +800015f8: 97 37 00 00 auipc a5, 3 +800015fc: 07 a5 47 97 flw fa0, -1676(a5) +80001600: 67 80 00 00 ret + +80001604 <__kernel_rem_pio2f>: +80001604: 13 01 01 e3 addi sp, sp, -464 +80001608: 13 18 27 00 slli a6, a4, 2 +8000160c: 23 22 e1 02 sw a4, 36(sp) +80001610: 17 17 00 00 auipc a4, 1 +80001614: 13 07 87 3f addi a4, a4, 1016 +80001618: 23 24 81 1c sw s0, 456(sp) +8000161c: 23 2e 31 1b sw s3, 444(sp) +80001620: 23 26 71 1b sw s7, 428(sp) +80001624: 33 07 07 01 add a4, a4, a6 +80001628: 23 26 11 1c sw ra, 460(sp) +8000162c: 23 22 91 1c sw s1, 452(sp) +80001630: 23 20 21 1d sw s2, 448(sp) +80001634: 23 2c 41 1b sw s4, 440(sp) +80001638: 23 2a 51 1b sw s5, 436(sp) +8000163c: 23 28 61 1b sw s6, 432(sp) +80001640: 23 24 81 1b sw s8, 424(sp) +80001644: 23 22 91 1b sw s9, 420(sp) +80001648: 23 20 a1 1b sw s10, 416(sp) +8000164c: 23 2e b1 19 sw s11, 412(sp) +80001650: 27 26 81 18 fsw fs0, 396(sp) +80001654: 27 24 91 18 fsw fs1, 392(sp) +80001658: 27 22 21 19 fsw fs2, 388(sp) +8000165c: 27 20 31 19 fsw fs3, 384(sp) +80001660: 27 2e 41 17 fsw fs4, 380(sp) +80001664: 27 2c 51 17 fsw fs5, 376(sp) +80001668: 27 2a 61 17 fsw fs6, 372(sp) +8000166c: 23 2a d1 00 sw a3, 20(sp) +80001670: 23 26 c1 02 sw a2, 44(sp) +80001674: 93 08 c0 ff li a7, -4 +80001678: 23 20 b1 02 sw a1, 32(sp) +8000167c: 23 2c f1 00 sw a5, 24(sp) +80001680: 83 2b 07 00 lw s7, 0(a4) +80001684: 93 09 05 00 mv s3, a0 +80001688: 13 84 f6 ff addi s0, a3, -1 +8000168c: 63 44 16 7b blt a2, a7, 0x80001e34 <__kernel_rem_pio2f+0x830> +80001690: 93 07 d6 ff addi a5, a2, -3 +80001694: 93 d4 f7 41 srai s1, a5, 31 +80001698: 93 f4 74 00 andi s1, s1, 7 +8000169c: b3 84 f4 00 add s1, s1, a5 +800016a0: 93 d7 34 40 srai a5, s1, 3 +800016a4: 93 8c 17 00 addi s9, a5, 1 +800016a8: 23 28 f1 00 sw a5, 16(sp) +800016ac: 93 97 3c 00 slli a5, s9, 3 +800016b0: 23 24 f1 02 sw a5, 40(sp) +800016b4: 83 27 c1 02 lw a5, 44(sp) +800016b8: 83 26 81 02 lw a3, 40(sp) +800016bc: 33 87 8b 00 add a4, s7, s0 +800016c0: 33 8a d7 40 sub s4, a5, a3 +800016c4: 83 27 01 01 lw a5, 16(sp) +800016c8: b3 87 87 40 sub a5, a5, s0 +800016cc: 63 40 07 04 bltz a4, 0x8000170c <__kernel_rem_pio2f+0x108> +800016d0: 83 26 81 01 lw a3, 24(sp) +800016d4: 13 05 17 00 addi a0, a4, 1 +800016d8: 93 95 27 00 slli a1, a5, 2 +800016dc: 13 07 01 08 addi a4, sp, 128 +800016e0: b3 85 b6 00 add a1, a3, a1 +800016e4: 33 05 f5 00 add a0, a0, a5 +800016e8: d3 07 00 f0 fmv.w.x fa5, zero +800016ec: 63 c6 07 00 bltz a5, 0x800016f8 <__kernel_rem_pio2f+0xf4> +800016f0: 03 a3 05 00 lw t1, 0(a1) +800016f4: d3 77 03 d0 fcvt.s.w fa5, t1 +800016f8: 93 87 17 00 addi a5, a5, 1 +800016fc: 27 20 f7 00 fsw fa5, 0(a4) +80001700: 13 07 47 00 addi a4, a4, 4 +80001704: 93 85 45 00 addi a1, a1, 4 +80001708: e3 90 a7 fe bne a5, a0, 0x800016e8 <__kernel_rem_pio2f+0xe4> +8000170c: 63 c2 0b 06 bltz s7, 0x80001770 <__kernel_rem_pio2f+0x16c> +80001710: 93 17 24 00 slli a5, s0, 2 +80001714: 13 07 01 08 addi a4, sp, 128 +80001718: 93 85 47 00 addi a1, a5, 4 +8000171c: 33 05 f7 00 add a0, a4, a5 +80001720: 83 27 41 01 lw a5, 20(sp) +80001724: 13 0e 01 12 addi t3, sp, 288 +80001728: 13 03 04 00 mv t1, s0 +8000172c: b3 8e fb 00 add t4, s7, a5 +80001730: b3 85 35 01 add a1, a1, s3 +80001734: d3 07 00 f0 fmv.w.x fa5, zero +80001738: 13 07 05 00 mv a4, a0 +8000173c: 93 87 09 00 mv a5, s3 +80001740: 63 4e 04 00 bltz s0, 0x8000175c <__kernel_rem_pio2f+0x158> +80001744: 87 a6 07 00 flw fa3, 0(a5) +80001748: 07 27 07 00 flw fa4, 0(a4) +8000174c: 93 87 47 00 addi a5, a5, 4 +80001750: 13 07 c7 ff addi a4, a4, -4 +80001754: c3 f7 e6 78 fmadd.s fa5, fa3, fa4, fa5 +80001758: e3 96 b7 fe bne a5, a1, 0x80001744 <__kernel_rem_pio2f+0x140> +8000175c: 27 20 fe 00 fsw fa5, 0(t3) +80001760: 13 03 13 00 addi t1, t1, 1 +80001764: 13 0e 4e 00 addi t3, t3, 4 +80001768: 13 05 45 00 addi a0, a0, 4 +8000176c: e3 14 d3 fd bne t1, t4, 0x80001734 <__kernel_rem_pio2f+0x130> +80001770: 03 27 41 01 lw a4, 20(sp) +80001774: 93 97 2b 00 slli a5, s7, 2 +80001778: 93 0a 01 03 addi s5, sp, 48 +8000177c: 13 8b 87 ff addi s6, a5, -8 +80001780: 13 1d 27 00 slli s10, a4, 2 +80001784: 13 07 c1 02 addi a4, sp, 44 +80001788: b3 04 f7 00 add s1, a4, a5 +8000178c: b3 87 6a 01 add a5, s5, s6 +80001790: 23 2e f1 00 sw a5, 28(sp) +80001794: 97 27 00 00 auipc a5, 2 +80001798: 87 a4 87 7f flw fs1, 2040(a5) +8000179c: 97 27 00 00 auipc a5, 2 +800017a0: 07 a4 47 7f flw fs0, 2036(a5) +800017a4: 97 27 00 00 auipc a5, 2 +800017a8: 07 a9 87 7c flw fs2, 1992(a5) +800017ac: b7 07 00 40 lui a5, 262144 +800017b0: 93 87 f7 ff addi a5, a5, -1 +800017b4: 13 89 fb ff addi s2, s7, -1 +800017b8: 23 26 f1 00 sw a5, 12(sp) +800017bc: 13 19 29 00 slli s2, s2, 2 +800017c0: 97 27 00 00 auipc a5, 2 +800017c4: 87 aa 87 7c flw fs5, 1992(a5) +800017c8: 97 27 00 00 auipc a5, 2 +800017cc: 07 aa 87 79 flw fs4, 1944(a5) +800017d0: 97 27 00 00 auipc a5, 2 +800017d4: 87 a9 47 78 flw fs3, 1924(a5) +800017d8: 93 07 09 14 addi a5, s2, 320 +800017dc: 33 8d a9 01 add s10, s3, s10 +800017e0: 13 8b 0b 00 mv s6, s7 +800017e4: 33 89 57 01 add s2, a5, s5 +800017e8: 93 1d 2b 00 slli s11, s6, 2 +800017ec: 93 87 0d 14 addi a5, s11, 320 +800017f0: 13 07 01 03 addi a4, sp, 48 +800017f4: b3 87 e7 00 add a5, a5, a4 +800017f8: 07 a5 07 fb flw fa0, -80(a5) +800017fc: 63 56 60 05 blez s6, 0x80001848 <__kernel_rem_pio2f+0x244> +80001800: 83 27 c1 00 lw a5, 12(sp) +80001804: 13 0f 01 12 addi t5, sp, 288 +80001808: 13 85 0a 00 mv a0, s5 +8000180c: b3 07 fb 00 add a5, s6, a5 +80001810: 93 97 27 00 slli a5, a5, 2 +80001814: b3 07 ff 00 add a5, t5, a5 +80001818: d3 77 55 11 fmul.s fa5, fa0, fs5 +8000181c: 87 a6 07 00 flw fa3, 0(a5) +80001820: 13 05 45 00 addi a0, a0, 4 +80001824: 13 8e 07 00 mv t3, a5 +80001828: 93 87 c7 ff addi a5, a5, -4 +8000182c: d3 9e 07 c0 fcvt.w.s t4, fa5, rtz +80001830: d3 f7 0e d0 fcvt.s.w fa5, t4 +80001834: 4b f7 47 51 fnmsub.s fa4, fa5, fs4, fa0 +80001838: 53 f5 d7 00 fadd.s fa0, fa5, fa3 +8000183c: d3 1e 07 c0 fcvt.w.s t4, fa4, rtz +80001840: 23 2e d5 ff sw t4, -4(a0) +80001844: e3 1a cf fd bne t5, t3, 0x80001818 <__kernel_rem_pio2f+0x214> +80001848: 13 05 0a 00 mv a0, s4 +8000184c: ef 00 90 02 jal 0x80002074 +80001850: 53 0b a5 20 fmv.s fs6, fa0 +80001854: 53 75 95 10 fmul.s fa0, fa0, fs1 +80001858: ef 00 00 75 jal 0x80001fa8 +8000185c: cb 77 85 b0 fnmsub.s fa5, fa0, fs0, fs6 +80001860: d3 9c 07 c0 fcvt.w.s s9, fa5, rtz +80001864: 53 f7 0c d0 fcvt.s.w fa4, s9 +80001868: 53 fb e7 08 fsub.s fs6, fa5, fa4 +8000186c: 63 5a 40 13 blez s4, 0x800019a0 <__kernel_rem_pio2f+0x39c> +80001870: 93 07 fb ff addi a5, s6, -1 +80001874: 93 97 27 00 slli a5, a5, 2 +80001878: 93 87 07 14 addi a5, a5, 320 +8000187c: 13 07 01 03 addi a4, sp, 48 +80001880: b3 87 e7 00 add a5, a5, a4 +80001884: 03 ae 07 ec lw t3, -320(a5) +80001888: 13 05 80 00 li a0, 8 +8000188c: 33 05 45 41 sub a0, a0, s4 +80001890: 33 5f ae 40 sra t5, t3, a0 +80001894: 33 15 af 00 sll a0, t5, a0 +80001898: 33 0e ae 40 sub t3, t3, a0 +8000189c: 13 05 70 00 li a0, 7 +800018a0: 33 05 45 41 sub a0, a0, s4 +800018a4: 23 a0 c7 ed sw t3, -320(a5) +800018a8: 33 5c ae 40 sra s8, t3, a0 +800018ac: b3 8c ec 01 add s9, s9, t5 +800018b0: 63 48 80 31 bgtz s8, 0x80001bc0 <__kernel_rem_pio2f+0x5bc> +800018b4: 53 07 00 f0 fmv.w.x fa4, zero +800018b8: d3 27 eb a0 feq.s a5, fs6, fa4 +800018bc: 63 80 07 1c beqz a5, 0x80001a7c <__kernel_rem_pio2f+0x478> +800018c0: 63 d6 6b 03 bge s7, s6, 0x800018ec <__kernel_rem_pio2f+0x2e8> +800018c4: 83 27 c1 00 lw a5, 12(sp) +800018c8: 13 05 00 00 li a0, 0 +800018cc: b3 07 fb 00 add a5, s6, a5 +800018d0: 93 97 27 00 slli a5, a5, 2 +800018d4: b3 87 fa 00 add a5, s5, a5 +800018d8: 03 af 07 00 lw t5, 0(a5) +800018dc: 93 87 c7 ff addi a5, a5, -4 +800018e0: 33 65 e5 01 or a0, a0, t5 +800018e4: e3 9a 97 fe bne a5, s1, 0x800018d8 <__kernel_rem_pio2f+0x2d4> +800018e8: 63 10 05 32 bnez a0, 0x80001c08 <__kernel_rem_pio2f+0x604> +800018ec: 83 27 09 ec lw a5, -320(s2) +800018f0: 63 94 07 30 bnez a5, 0x80001bf8 <__kernel_rem_pio2f+0x5f4> +800018f4: 83 27 c1 01 lw a5, 28(sp) +800018f8: 13 05 10 00 li a0, 1 +800018fc: 03 ae 07 00 lw t3, 0(a5) +80001900: 13 05 15 00 addi a0, a0, 1 +80001904: 93 87 c7 ff addi a5, a5, -4 +80001908: e3 0a 0e fe beqz t3, 0x800018fc <__kernel_rem_pio2f+0x2f8> +8000190c: 93 07 1b 00 addi a5, s6, 1 +80001910: 93 8f 07 00 mv t6, a5 +80001914: 33 0f ab 00 add t5, s6, a0 +80001918: 03 27 01 01 lw a4, 16(sp) +8000191c: 83 26 81 01 lw a3, 24(sp) +80001920: 33 0e f7 00 add t3, a4, a5 +80001924: 03 27 41 01 lw a4, 20(sp) +80001928: 13 1e 2e 00 slli t3, t3, 2 +8000192c: 33 8e c6 01 add t3, a3, t3 +80001930: 33 07 67 01 add a4, a4, s6 +80001934: 13 17 27 00 slli a4, a4, 2 +80001938: 93 06 01 08 addi a3, sp, 128 +8000193c: 93 97 27 00 slli a5, a5, 2 +80001940: 33 85 e6 00 add a0, a3, a4 +80001944: 13 07 01 12 addi a4, sp, 288 +80001948: b3 0e f7 00 add t4, a4, a5 +8000194c: 83 27 0e 00 lw a5, 0(t3) +80001950: d3 f7 07 d0 fcvt.s.w fa5, a5 +80001954: 27 20 f5 00 fsw fa5, 0(a0) +80001958: d3 07 00 f0 fmv.w.x fa5, zero +8000195c: 63 42 04 02 bltz s0, 0x80001980 <__kernel_rem_pio2f+0x37c> +80001960: 13 07 05 00 mv a4, a0 +80001964: 93 87 09 00 mv a5, s3 +80001968: 87 a6 07 00 flw fa3, 0(a5) +8000196c: 07 27 07 00 flw fa4, 0(a4) +80001970: 93 87 47 00 addi a5, a5, 4 +80001974: 13 07 c7 ff addi a4, a4, -4 +80001978: c3 f7 e6 78 fmadd.s fa5, fa3, fa4, fa5 +8000197c: e3 96 a7 ff bne a5, s10, 0x80001968 <__kernel_rem_pio2f+0x364> +80001980: 27 a0 fe 00 fsw fa5, 0(t4) +80001984: 93 8f 1f 00 addi t6, t6, 1 +80001988: 13 0e 4e 00 addi t3, t3, 4 +8000198c: 13 05 45 00 addi a0, a0, 4 +80001990: 93 8e 4e 00 addi t4, t4, 4 +80001994: e3 5c ff fb bge t5, t6, 0x8000194c <__kernel_rem_pio2f+0x348> +80001998: 13 0b 0f 00 mv s6, t5 +8000199c: 6f f0 df e4 j 0x800017e8 <__kernel_rem_pio2f+0x1e4> +800019a0: 63 10 0a 20 bnez s4, 0x80001ba0 <__kernel_rem_pio2f+0x59c> +800019a4: 93 07 fb ff addi a5, s6, -1 +800019a8: 93 97 27 00 slli a5, a5, 2 +800019ac: 93 87 07 14 addi a5, a5, 320 +800019b0: 13 07 01 03 addi a4, sp, 48 +800019b4: b3 87 e7 00 add a5, a5, a4 +800019b8: 03 ae 07 ec lw t3, -320(a5) +800019bc: 13 5c 7e 40 srai s8, t3, 7 +800019c0: e3 5a 80 ef blez s8, 0x800018b4 <__kernel_rem_pio2f+0x2b0> +800019c4: 93 8c 1c 00 addi s9, s9, 1 +800019c8: 63 5c 60 4d blez s6, 0x80001ea0 <__kernel_rem_pio2f+0x89c> +800019cc: 93 87 0a 00 mv a5, s5 +800019d0: 13 0f 00 00 li t5, 0 +800019d4: 93 0f 00 00 li t6, 0 +800019d8: 93 03 f0 0f li t2, 255 +800019dc: 93 02 00 10 li t0, 256 +800019e0: 03 a5 07 00 lw a0, 0(a5) +800019e4: 63 90 0f 02 bnez t6, 0x80001a04 <__kernel_rem_pio2f+0x400> +800019e8: b3 80 a2 40 sub ra, t0, a0 +800019ec: 63 02 05 02 beqz a0, 0x80001a10 <__kernel_rem_pio2f+0x40c> +800019f0: 23 a0 17 00 sw ra, 0(a5) +800019f4: 13 0f 1f 00 addi t5, t5, 1 +800019f8: 93 87 47 00 addi a5, a5, 4 +800019fc: 63 58 6f 43 bge t5, s6, 0x80001e2c <__kernel_rem_pio2f+0x828> +80001a00: 03 a5 07 00 lw a0, 0(a5) +80001a04: 33 85 a3 40 sub a0, t2, a0 +80001a08: 93 0f 10 00 li t6, 1 +80001a0c: 23 a0 a7 00 sw a0, 0(a5) +80001a10: 13 0f 1f 00 addi t5, t5, 1 +80001a14: 93 87 47 00 addi a5, a5, 4 +80001a18: e3 44 6f fd blt t5, s6, 0x800019e0 <__kernel_rem_pio2f+0x3dc> +80001a1c: 63 5a 40 03 blez s4, 0x80001a50 <__kernel_rem_pio2f+0x44c> +80001a20: 93 07 10 00 li a5, 1 +80001a24: 63 08 fa 1a beq s4, a5, 0x80001bd4 <__kernel_rem_pio2f+0x5d0> +80001a28: 93 07 20 00 li a5, 2 +80001a2c: 63 12 fa 02 bne s4, a5, 0x80001a50 <__kernel_rem_pio2f+0x44c> +80001a30: 93 07 fb ff addi a5, s6, -1 +80001a34: 93 97 27 00 slli a5, a5, 2 +80001a38: 93 87 07 14 addi a5, a5, 320 +80001a3c: 13 07 01 03 addi a4, sp, 48 +80001a40: b3 87 e7 00 add a5, a5, a4 +80001a44: 03 a5 07 ec lw a0, -320(a5) +80001a48: 13 75 f5 03 andi a0, a0, 63 +80001a4c: 23 a0 a7 ec sw a0, -320(a5) +80001a50: 93 07 20 00 li a5, 2 +80001a54: e3 10 fc e6 bne s8, a5, 0x800018b4 <__kernel_rem_pio2f+0x2b0> +80001a58: 53 7b 69 09 fsub.s fs6, fs2, fs6 +80001a5c: e3 8c 0f e4 beqz t6, 0x800018b4 <__kernel_rem_pio2f+0x2b0> +80001a60: 53 05 29 21 fmv.s fa0, fs2 +80001a64: 13 05 0a 00 mv a0, s4 +80001a68: ef 00 c0 60 jal 0x80002074 +80001a6c: 53 7b ab 08 fsub.s fs6, fs6, fa0 +80001a70: 53 07 00 f0 fmv.w.x fa4, zero +80001a74: d3 27 eb a0 feq.s a5, fs6, fa4 +80001a78: e3 94 07 e4 bnez a5, 0x800018c0 <__kernel_rem_pio2f+0x2bc> +80001a7c: 83 27 81 02 lw a5, 40(sp) +80001a80: 03 27 c1 02 lw a4, 44(sp) +80001a84: 53 05 6b 21 fmv.s fa0, fs6 +80001a88: 33 85 e7 40 sub a0, a5, a4 +80001a8c: ef 00 80 5e jal 0x80002074 +80001a90: 97 27 00 00 auipc a5, 2 +80001a94: 07 a7 07 4d flw fa4, 1232(a5) +80001a98: d3 07 a7 a0 fle.s a5, fa4, fa0 +80001a9c: 63 84 07 3a beqz a5, 0x80001e44 <__kernel_rem_pio2f+0x840> +80001aa0: 97 27 00 00 auipc a5, 2 +80001aa4: 87 a6 87 4e flw fa3, 1256(a5) +80001aa8: d3 76 d5 10 fmul.s fa3, fa0, fa3 +80001aac: 13 07 01 03 addi a4, sp, 48 +80001ab0: 93 87 0d 14 addi a5, s11, 320 +80001ab4: 13 04 1b 00 addi s0, s6, 1 +80001ab8: b3 8d e7 00 add s11, a5, a4 +80001abc: 93 17 24 00 slli a5, s0, 2 +80001ac0: 93 87 07 14 addi a5, a5, 320 +80001ac4: b3 87 e7 00 add a5, a5, a4 +80001ac8: 53 97 06 c0 fcvt.w.s a4, fa3, rtz +80001acc: 13 0a 8a 00 addi s4, s4, 8 +80001ad0: d3 76 07 d0 fcvt.s.w fa3, a4 +80001ad4: 4b f7 e6 50 fnmsub.s fa4, fa3, fa4, fa0 +80001ad8: 53 97 06 c0 fcvt.w.s a4, fa3, rtz +80001adc: 53 16 07 c0 fcvt.w.s a2, fa4, rtz +80001ae0: 23 a0 cd ec sw a2, -320(s11) +80001ae4: 23 a0 e7 ec sw a4, -320(a5) +80001ae8: 53 05 29 21 fmv.s fa0, fs2 +80001aec: 13 05 0a 00 mv a0, s4 +80001af0: ef 00 40 58 jal 0x80002074 +80001af4: 53 07 a5 20 fmv.s fa4, fa0 +80001af8: 63 42 04 16 bltz s0, 0x80001c5c <__kernel_rem_pio2f+0x658> +80001afc: 13 15 24 00 slli a0, s0, 2 +80001b00: 93 07 01 12 addi a5, sp, 288 +80001b04: 33 88 a7 00 add a6, a5, a0 +80001b08: 13 07 08 00 mv a4, a6 +80001b0c: b3 87 aa 00 add a5, s5, a0 +80001b10: 97 26 00 00 auipc a3, 2 +80001b14: 87 a6 86 47 flw fa3, 1144(a3) +80001b18: 83 a5 07 00 lw a1, 0(a5) +80001b1c: 13 07 c7 ff addi a4, a4, -4 +80001b20: 13 86 07 00 mv a2, a5 +80001b24: d3 f7 05 d0 fcvt.s.w fa5, a1 +80001b28: 93 87 c7 ff addi a5, a5, -4 +80001b2c: d3 f7 e7 10 fmul.s fa5, fa5, fa4 +80001b30: 53 77 d7 10 fmul.s fa4, fa4, fa3 +80001b34: 27 22 f7 00 fsw fa5, 4(a4) +80001b38: e3 90 ca fe bne s5, a2, 0x80001b18 <__kernel_rem_pio2f+0x514> +80001b3c: 13 03 01 0d addi t1, sp, 208 +80001b40: 93 08 03 00 mv a7, t1 +80001b44: 93 05 00 00 li a1, 0 +80001b48: d3 07 00 f0 fmv.w.x fa5, zero +80001b4c: 63 cc 0b 02 bltz s7, 0x80001b84 <__kernel_rem_pio2f+0x580> +80001b50: 17 17 00 00 auipc a4, 1 +80001b54: 13 07 c7 e8 addi a4, a4, -372 +80001b58: 13 06 08 00 mv a2, a6 +80001b5c: 93 07 00 00 li a5, 0 +80001b60: 6f 00 c0 00 j 0x80001b6c <__kernel_rem_pio2f+0x568> +80001b64: 13 06 46 00 addi a2, a2, 4 +80001b68: 63 ce f5 00 blt a1, a5, 0x80001b84 <__kernel_rem_pio2f+0x580> +80001b6c: 87 26 07 00 flw fa3, 0(a4) +80001b70: 07 27 06 00 flw fa4, 0(a2) +80001b74: 93 87 17 00 addi a5, a5, 1 +80001b78: 13 07 47 00 addi a4, a4, 4 +80001b7c: c3 f7 e6 78 fmadd.s fa5, fa3, fa4, fa5 +80001b80: e3 d2 fb fe bge s7, a5, 0x80001b64 <__kernel_rem_pio2f+0x560> +80001b84: 27 a0 f8 00 fsw fa5, 0(a7) +80001b88: 93 87 15 00 addi a5, a1, 1 +80001b8c: 93 88 48 00 addi a7, a7, 4 +80001b90: 13 08 c8 ff addi a6, a6, -4 +80001b94: 63 86 85 14 beq a1, s0, 0x80001ce0 <__kernel_rem_pio2f+0x6dc> +80001b98: 93 85 07 00 mv a1, a5 +80001b9c: 6f f0 df fa j 0x80001b48 <__kernel_rem_pio2f+0x544> +80001ba0: d3 87 69 a1 fle.s a5, fs3, fs6 +80001ba4: 13 0c 00 00 li s8, 0 +80001ba8: e3 86 07 d0 beqz a5, 0x800018b4 <__kernel_rem_pio2f+0x2b0> +80001bac: 93 8c 1c 00 addi s9, s9, 1 +80001bb0: 13 0c 20 00 li s8, 2 +80001bb4: e3 4c 60 e1 bgtz s6, 0x800019cc <__kernel_rem_pio2f+0x3c8> +80001bb8: 53 7b 69 09 fsub.s fs6, fs2, fs6 +80001bbc: 6f f0 9f cf j 0x800018b4 <__kernel_rem_pio2f+0x2b0> +80001bc0: 93 8c 1c 00 addi s9, s9, 1 +80001bc4: 93 0f 00 00 li t6, 0 +80001bc8: e3 42 60 e1 bgtz s6, 0x800019cc <__kernel_rem_pio2f+0x3c8> +80001bcc: 93 07 10 00 li a5, 1 +80001bd0: e3 1c fa e4 bne s4, a5, 0x80001a28 <__kernel_rem_pio2f+0x424> +80001bd4: 93 07 fb ff addi a5, s6, -1 +80001bd8: 93 97 27 00 slli a5, a5, 2 +80001bdc: 93 87 07 14 addi a5, a5, 320 +80001be0: 13 07 01 03 addi a4, sp, 48 +80001be4: b3 87 e7 00 add a5, a5, a4 +80001be8: 03 a5 07 ec lw a0, -320(a5) +80001bec: 13 75 f5 07 andi a0, a0, 127 +80001bf0: 23 a0 a7 ec sw a0, -320(a5) +80001bf4: 6f f0 df e5 j 0x80001a50 <__kernel_rem_pio2f+0x44c> +80001bf8: 93 07 1b 00 addi a5, s6, 1 +80001bfc: 93 8f 07 00 mv t6, a5 +80001c00: 13 8f 07 00 mv t5, a5 +80001c04: 6f f0 5f d1 j 0x80001918 <__kernel_rem_pio2f+0x314> +80001c08: 13 04 fb ff addi s0, s6, -1 +80001c0c: 93 17 24 00 slli a5, s0, 2 +80001c10: 93 87 07 14 addi a5, a5, 320 +80001c14: 13 07 01 03 addi a4, sp, 48 +80001c18: b3 87 e7 00 add a5, a5, a4 +80001c1c: 83 a7 07 ec lw a5, -320(a5) +80001c20: 13 0a 8a ff addi s4, s4, -8 +80001c24: e3 92 07 ec bnez a5, 0x80001ae8 <__kernel_rem_pio2f+0x4e4> +80001c28: 93 17 2b 00 slli a5, s6, 2 +80001c2c: 93 87 87 ff addi a5, a5, -8 +80001c30: b3 87 fa 00 add a5, s5, a5 +80001c34: 03 a7 07 00 lw a4, 0(a5) +80001c38: 13 04 f4 ff addi s0, s0, -1 +80001c3c: 93 87 c7 ff addi a5, a5, -4 +80001c40: 13 0a 8a ff addi s4, s4, -8 +80001c44: e3 08 07 fe beqz a4, 0x80001c34 <__kernel_rem_pio2f+0x630> +80001c48: 53 05 29 21 fmv.s fa0, fs2 +80001c4c: 13 05 0a 00 mv a0, s4 +80001c50: ef 00 40 42 jal 0x80002074 +80001c54: 53 07 a5 20 fmv.s fa4, fa0 +80001c58: e3 52 04 ea bgez s0, 0x80001afc <__kernel_rem_pio2f+0x4f8> +80001c5c: 03 27 41 02 lw a4, 36(sp) +80001c60: 93 07 20 00 li a5, 2 +80001c64: 63 c6 e7 24 blt a5, a4, 0x80001eb0 <__kernel_rem_pio2f+0x8ac> +80001c68: 63 4e e0 24 bgtz a4, 0x80001ec4 <__kernel_rem_pio2f+0x8c0> +80001c6c: d3 07 00 f0 fmv.w.x fa5, zero +80001c70: 63 1a 07 00 bnez a4, 0x80001c84 <__kernel_rem_pio2f+0x680> +80001c74: 63 04 0c 00 beqz s8, 0x80001c7c <__kernel_rem_pio2f+0x678> +80001c78: d3 97 f7 20 fneg.s fa5, fa5 +80001c7c: 83 27 01 02 lw a5, 32(sp) +80001c80: 27 a0 f7 00 fsw fa5, 0(a5) +80001c84: 83 20 c1 1c lw ra, 460(sp) +80001c88: 03 24 81 1c lw s0, 456(sp) +80001c8c: 83 24 41 1c lw s1, 452(sp) +80001c90: 03 29 01 1c lw s2, 448(sp) +80001c94: 83 29 c1 1b lw s3, 444(sp) +80001c98: 03 2a 81 1b lw s4, 440(sp) +80001c9c: 83 2a 41 1b lw s5, 436(sp) +80001ca0: 03 2b 01 1b lw s6, 432(sp) +80001ca4: 83 2b c1 1a lw s7, 428(sp) +80001ca8: 03 2c 81 1a lw s8, 424(sp) +80001cac: 03 2d 01 1a lw s10, 416(sp) +80001cb0: 83 2d c1 19 lw s11, 412(sp) +80001cb4: 07 24 c1 18 flw fs0, 396(sp) +80001cb8: 87 24 81 18 flw fs1, 392(sp) +80001cbc: 07 29 41 18 flw fs2, 388(sp) +80001cc0: 87 29 01 18 flw fs3, 384(sp) +80001cc4: 07 2a c1 17 flw fs4, 380(sp) +80001cc8: 87 2a 81 17 flw fs5, 376(sp) +80001ccc: 07 2b 41 17 flw fs6, 372(sp) +80001cd0: 13 f5 7c 00 andi a0, s9, 7 +80001cd4: 83 2c 41 1a lw s9, 420(sp) +80001cd8: 13 01 01 1d addi sp, sp, 464 +80001cdc: 67 80 00 00 ret +80001ce0: 03 27 41 02 lw a4, 36(sp) +80001ce4: 93 07 20 00 li a5, 2 +80001ce8: 63 c6 e7 08 blt a5, a4, 0x80001d74 <__kernel_rem_pio2f+0x770> +80001cec: d3 07 00 f0 fmv.w.x fa5, zero +80001cf0: b3 07 a3 00 add a5, t1, a0 +80001cf4: 63 42 e0 02 bgtz a4, 0x80001d18 <__kernel_rem_pio2f+0x714> +80001cf8: e3 16 07 f8 bnez a4, 0x80001c84 <__kernel_rem_pio2f+0x680> +80001cfc: 07 a7 07 00 flw fa4, 0(a5) +80001d00: 13 87 07 00 mv a4, a5 +80001d04: 93 87 c7 ff addi a5, a5, -4 +80001d08: d3 f7 e7 00 fadd.s fa5, fa5, fa4 +80001d0c: e3 18 e3 fe bne t1, a4, 0x80001cfc <__kernel_rem_pio2f+0x6f8> +80001d10: e3 06 0c f6 beqz s8, 0x80001c7c <__kernel_rem_pio2f+0x678> +80001d14: 6f f0 5f f6 j 0x80001c78 <__kernel_rem_pio2f+0x674> +80001d18: 07 a7 07 00 flw fa4, 0(a5) +80001d1c: 13 87 07 00 mv a4, a5 +80001d20: 93 87 c7 ff addi a5, a5, -4 +80001d24: d3 f7 e7 00 fadd.s fa5, fa5, fa4 +80001d28: e3 18 e3 fe bne t1, a4, 0x80001d18 <__kernel_rem_pio2f+0x714> +80001d2c: 63 1a 0c 12 bnez s8, 0x80001e60 <__kernel_rem_pio2f+0x85c> +80001d30: 83 27 01 02 lw a5, 32(sp) +80001d34: 07 27 01 0d flw fa4, 208(sp) +80001d38: 27 a0 f7 00 fsw fa5, 0(a5) +80001d3c: d3 77 f7 08 fsub.s fa5, fa4, fa5 +80001d40: 63 04 04 02 beqz s0, 0x80001d68 <__kernel_rem_pio2f+0x764> +80001d44: 13 07 41 0d addi a4, sp, 212 +80001d48: 93 07 10 00 li a5, 1 +80001d4c: 07 27 07 00 flw fa4, 0(a4) +80001d50: 93 87 17 00 addi a5, a5, 1 +80001d54: 13 07 47 00 addi a4, a4, 4 +80001d58: d3 f7 e7 00 fadd.s fa5, fa5, fa4 +80001d5c: e3 58 f4 fe bge s0, a5, 0x80001d4c <__kernel_rem_pio2f+0x748> +80001d60: 63 04 0c 00 beqz s8, 0x80001d68 <__kernel_rem_pio2f+0x764> +80001d64: d3 97 f7 20 fneg.s fa5, fa5 +80001d68: 83 27 01 02 lw a5, 32(sp) +80001d6c: 27 a2 f7 00 fsw fa5, 4(a5) +80001d70: 6f f0 5f f1 j 0x80001c84 <__kernel_rem_pio2f+0x680> +80001d74: 03 27 41 02 lw a4, 36(sp) +80001d78: 93 07 30 00 li a5, 3 +80001d7c: e3 14 f7 f0 bne a4, a5, 0x80001c84 <__kernel_rem_pio2f+0x680> +80001d80: 63 0e 04 12 beqz s0, 0x80001ebc <__kernel_rem_pio2f+0x8b8> +80001d84: b3 06 a3 00 add a3, t1, a0 +80001d88: 93 07 c5 ff addi a5, a0, -4 +80001d8c: 07 a7 06 00 flw fa4, 0(a3) +80001d90: b3 07 f3 00 add a5, t1, a5 +80001d94: 13 87 07 00 mv a4, a5 +80001d98: 87 27 07 00 flw fa5, 0(a4) +80001d9c: d3 06 e7 20 fmv.s fa3, fa4 +80001da0: 13 06 07 00 mv a2, a4 +80001da4: 53 77 f7 00 fadd.s fa4, fa4, fa5 +80001da8: 13 07 c7 ff addi a4, a4, -4 +80001dac: d3 f7 e7 08 fsub.s fa5, fa5, fa4 +80001db0: 27 22 e7 00 fsw fa4, 4(a4) +80001db4: d3 f7 d7 00 fadd.s fa5, fa5, fa3 +80001db8: 27 24 f7 00 fsw fa5, 8(a4) +80001dbc: e3 1e 66 fc bne a2, t1, 0x80001d98 <__kernel_rem_pio2f+0x794> +80001dc0: 13 07 10 00 li a4, 1 +80001dc4: 63 0c e4 0e beq s0, a4, 0x80001ebc <__kernel_rem_pio2f+0x8b8> +80001dc8: 07 a7 06 00 flw fa4, 0(a3) +80001dcc: 87 a7 07 00 flw fa5, 0(a5) +80001dd0: d3 06 e7 20 fmv.s fa3, fa4 +80001dd4: 13 87 07 00 mv a4, a5 +80001dd8: 53 77 f7 00 fadd.s fa4, fa4, fa5 +80001ddc: 93 87 c7 ff addi a5, a5, -4 +80001de0: d3 f7 e7 08 fsub.s fa5, fa5, fa4 +80001de4: 27 a2 e7 00 fsw fa4, 4(a5) +80001de8: d3 f7 d7 00 fadd.s fa5, fa5, fa3 +80001dec: 27 a4 f7 00 fsw fa5, 8(a5) +80001df0: e3 1e f3 fc bne t1, a5, 0x80001dcc <__kernel_rem_pio2f+0x7c8> +80001df4: d3 07 00 f0 fmv.w.x fa5, zero +80001df8: 93 87 06 00 mv a5, a3 +80001dfc: 07 a7 07 00 flw fa4, 0(a5) +80001e00: 93 87 c7 ff addi a5, a5, -4 +80001e04: d3 f7 e7 00 fadd.s fa5, fa5, fa4 +80001e08: e3 1a f7 fe bne a4, a5, 0x80001dfc <__kernel_rem_pio2f+0x7f8> +80001e0c: 87 26 01 0d flw fa3, 208(sp) +80001e10: 07 27 41 0d flw fa4, 212(sp) +80001e14: 63 16 0c 06 bnez s8, 0x80001e80 <__kernel_rem_pio2f+0x87c> +80001e18: 83 27 01 02 lw a5, 32(sp) +80001e1c: 27 a0 d7 00 fsw fa3, 0(a5) +80001e20: 27 a2 e7 00 fsw fa4, 4(a5) +80001e24: 27 a4 f7 00 fsw fa5, 8(a5) +80001e28: 6f f0 df e5 j 0x80001c84 <__kernel_rem_pio2f+0x680> +80001e2c: 93 0f 10 00 li t6, 1 +80001e30: 6f f0 df be j 0x80001a1c <__kernel_rem_pio2f+0x418> +80001e34: 93 07 80 00 li a5, 8 +80001e38: 23 24 f1 02 sw a5, 40(sp) +80001e3c: 23 28 01 00 sw zero, 16(sp) +80001e40: 6f f0 5f 87 j 0x800016b4 <__kernel_rem_pio2f+0xb0> +80001e44: d3 17 05 c0 fcvt.w.s a5, fa0, rtz +80001e48: 13 87 0d 14 addi a4, s11, 320 +80001e4c: 93 06 01 03 addi a3, sp, 48 +80001e50: b3 0d d7 00 add s11, a4, a3 +80001e54: 13 04 0b 00 mv s0, s6 +80001e58: 23 a0 fd ec sw a5, -320(s11) +80001e5c: 6f f0 df c8 j 0x80001ae8 <__kernel_rem_pio2f+0x4e4> +80001e60: 53 97 f7 20 fneg.s fa4, fa5 +80001e64: 83 27 01 02 lw a5, 32(sp) +80001e68: 27 a0 e7 00 fsw fa4, 0(a5) +80001e6c: 07 27 01 0d flw fa4, 208(sp) +80001e70: d3 77 f7 08 fsub.s fa5, fa4, fa5 +80001e74: e3 18 04 ec bnez s0, 0x80001d44 <__kernel_rem_pio2f+0x740> +80001e78: d3 97 f7 20 fneg.s fa5, fa5 +80001e7c: 6f f0 df ee j 0x80001d68 <__kernel_rem_pio2f+0x764> +80001e80: 83 27 01 02 lw a5, 32(sp) +80001e84: d3 96 d6 20 fneg.s fa3, fa3 +80001e88: 53 17 e7 20 fneg.s fa4, fa4 +80001e8c: d3 97 f7 20 fneg.s fa5, fa5 +80001e90: 27 a0 d7 00 fsw fa3, 0(a5) +80001e94: 27 a2 e7 00 fsw fa4, 4(a5) +80001e98: 27 a4 f7 00 fsw fa5, 8(a5) +80001e9c: 6f f0 9f de j 0x80001c84 <__kernel_rem_pio2f+0x680> +80001ea0: 93 07 20 00 li a5, 2 +80001ea4: e3 18 fc a0 bne s8, a5, 0x800018b4 <__kernel_rem_pio2f+0x2b0> +80001ea8: 53 7b 69 09 fsub.s fs6, fs2, fs6 +80001eac: 6f f0 9f a0 j 0x800018b4 <__kernel_rem_pio2f+0x2b0> +80001eb0: 03 27 41 02 lw a4, 36(sp) +80001eb4: 93 07 30 00 li a5, 3 +80001eb8: e3 16 f7 dc bne a4, a5, 0x80001c84 <__kernel_rem_pio2f+0x680> +80001ebc: d3 07 00 f0 fmv.w.x fa5, zero +80001ec0: 6f f0 df f4 j 0x80001e0c <__kernel_rem_pio2f+0x808> +80001ec4: 63 1a 0c 00 bnez s8, 0x80001ed8 <__kernel_rem_pio2f+0x8d4> +80001ec8: 83 27 01 02 lw a5, 32(sp) +80001ecc: 87 27 01 0d flw fa5, 208(sp) +80001ed0: 23 a0 07 00 sw zero, 0(a5) +80001ed4: 6f f0 5f e9 j 0x80001d68 <__kernel_rem_pio2f+0x764> +80001ed8: 97 27 00 00 auipc a5, 2 +80001edc: 07 a7 c7 0b flw fa4, 188(a5) +80001ee0: 87 27 01 0d flw fa5, 208(sp) +80001ee4: 83 27 01 02 lw a5, 32(sp) +80001ee8: d3 97 f7 20 fneg.s fa5, fa5 +80001eec: 27 a0 e7 00 fsw fa4, 0(a5) +80001ef0: 6f f0 9f e7 j 0x80001d68 <__kernel_rem_pio2f+0x764> + +80001ef4 <__kernel_sinf>: +80001ef4: d3 07 05 e0 fmv.x.w a5, fa0 +80001ef8: b7 06 00 32 lui a3, 204800 +80001efc: 13 97 17 00 slli a4, a5, 1 +80001f00: 13 57 17 00 srli a4, a4, 1 +80001f04: 63 76 d7 00 bgeu a4, a3, 0x80001f10 <__kernel_sinf+0x1c> +80001f08: 53 17 05 c0 fcvt.w.s a4, fa0, rtz +80001f0c: 63 08 07 08 beqz a4, 0x80001f9c <__kernel_sinf+0xa8> +80001f10: d3 87 07 f0 fmv.w.x fa5, a5 +80001f14: 17 27 00 00 auipc a4, 2 +80001f18: 87 26 87 08 flw fa3, 136(a4) +80001f1c: 17 27 00 00 auipc a4, 2 +80001f20: 07 20 47 08 flw ft0, 132(a4) +80001f24: 53 f7 f7 10 fmul.s fa4, fa5, fa5 +80001f28: 17 27 00 00 auipc a4, 2 +80001f2c: 87 27 07 07 flw fa5, 112(a4) +80001f30: 17 27 00 00 auipc a4, 2 +80001f34: 07 26 47 07 flw fa2, 116(a4) +80001f38: 53 85 07 f0 fmv.w.x fa0, a5 +80001f3c: c3 77 f7 68 fmadd.s fa5, fa4, fa5, fa3 +80001f40: 17 27 00 00 auipc a4, 2 +80001f44: 87 26 87 06 flw fa3, 104(a4) +80001f48: 53 75 e5 10 fmul.s fa0, fa0, fa4 +80001f4c: c3 f7 e7 00 fmadd.s fa5, fa5, fa4, ft0 +80001f50: c3 f7 e7 60 fmadd.s fa5, fa5, fa4, fa2 +80001f54: c3 f7 e7 68 fmadd.s fa5, fa5, fa4, fa3 +80001f58: 63 1e 05 00 bnez a0, 0x80001f74 <__kernel_sinf+0x80> +80001f5c: 17 27 00 00 auipc a4, 2 +80001f60: 87 26 07 05 flw fa3, 80(a4) +80001f64: 43 77 f7 68 fmadd.s fa4, fa4, fa5, fa3 +80001f68: d3 87 07 f0 fmv.w.x fa5, a5 +80001f6c: 43 75 a7 78 fmadd.s fa0, fa4, fa0, fa5 +80001f70: 67 80 00 00 ret +80001f74: d3 77 f5 10 fmul.s fa5, fa0, fa5 +80001f78: 17 27 00 00 auipc a4, 2 +80001f7c: 87 26 c7 fd flw fa3, -36(a4) +80001f80: 17 27 00 00 auipc a4, 2 +80001f84: 07 26 07 03 flw fa2, 48(a4) +80001f88: c7 f7 d5 78 fmsub.s fa5, fa1, fa3, fa5 +80001f8c: c7 f7 e7 58 fmsub.s fa5, fa5, fa4, fa1 +80001f90: 43 75 c5 78 fmadd.s fa0, fa0, fa2, fa5 +80001f94: d3 87 07 f0 fmv.w.x fa5, a5 +80001f98: 53 f5 a7 08 fsub.s fa0, fa5, fa0 +80001f9c: 67 80 00 00 ret + +80001fa0 : +80001fa0: 53 25 a5 20 fabs.s fa0, fa0 +80001fa4: 67 80 00 00 ret + +80001fa8 : +80001fa8: d3 07 05 e0 fmv.x.w a5, fa0 +80001fac: 13 06 60 01 li a2, 22 +80001fb0: 93 96 17 00 slli a3, a5, 1 +80001fb4: 13 d7 86 01 srli a4, a3, 24 +80001fb8: 13 07 17 f8 addi a4, a4, -127 +80001fbc: 93 d6 16 00 srli a3, a3, 1 +80001fc0: 63 46 e6 08 blt a2, a4, 0x8000204c +80001fc4: 13 85 07 00 mv a0, a5 +80001fc8: 63 48 07 04 bltz a4, 0x80002018 +80001fcc: b7 05 80 00 lui a1, 2048 +80001fd0: 93 86 f5 ff addi a3, a1, -1 +80001fd4: b3 d6 e6 40 sra a3, a3, a4 +80001fd8: 33 f8 f6 00 and a6, a3, a5 +80001fdc: 53 06 05 e0 fmv.x.w a2, fa0 +80001fe0: 63 08 08 02 beqz a6, 0x80002010 +80001fe4: 17 28 00 00 auipc a6, 2 +80001fe8: 87 27 48 fd flw fa5, -44(a6) +80001fec: d3 77 f5 00 fadd.s fa5, fa0, fa5 +80001ff0: 53 07 00 f0 fmv.w.x fa4, zero +80001ff4: 53 18 f7 a0 flt.s a6, fa4, fa5 +80001ff8: 63 0c 08 00 beqz a6, 0x80002010 +80001ffc: 63 d6 07 00 bgez a5, 0x80002008 +80002000: b3 d5 e5 40 sra a1, a1, a4 +80002004: 33 85 f5 00 add a0, a1, a5 +80002008: 93 c6 f6 ff not a3, a3 +8000200c: 33 f6 a6 00 and a2, a3, a0 +80002010: 53 05 06 f0 fmv.w.x fa0, a2 +80002014: 67 80 00 00 ret +80002018: 17 27 00 00 auipc a4, 2 +8000201c: 87 27 07 fa flw fa5, -96(a4) +80002020: d3 77 f5 00 fadd.s fa5, fa0, fa5 +80002024: 53 07 00 f0 fmv.w.x fa4, zero +80002028: 53 06 05 e0 fmv.x.w a2, fa0 +8000202c: 53 17 f7 a0 flt.s a4, fa4, fa5 +80002030: e3 00 07 fe beqz a4, 0x80002010 +80002034: 53 06 07 e0 fmv.x.w a2, fa4 +80002038: e3 dc 07 fc bgez a5, 0x80002010 +8000203c: 63 96 06 02 bnez a3, 0x80002068 +80002040: 17 26 00 00 auipc a2, 2 +80002044: 03 26 46 f5 lw a2, -172(a2) +80002048: 6f f0 9f fc j 0x80002010 +8000204c: 37 07 80 7f lui a4, 522240 +80002050: 53 06 05 e0 fmv.x.w a2, fa0 +80002054: e3 ee e6 fa bltu a3, a4, 0x80002010 +80002058: d3 77 a5 00 fadd.s fa5, fa0, fa0 +8000205c: 53 86 07 e0 fmv.x.w a2, fa5 +80002060: 53 05 06 f0 fmv.w.x fa0, a2 +80002064: 67 80 00 00 ret +80002068: 17 26 00 00 auipc a2, 2 +8000206c: 03 26 c6 f4 lw a2, -180(a2) +80002070: 6f f0 1f fa j 0x80002010 + +80002074 : +80002074: d3 07 05 e0 fmv.x.w a5, fa0 +80002078: 93 96 17 00 slli a3, a5, 1 +8000207c: 13 d7 16 00 srli a4, a3, 1 +80002080: 63 82 06 06 beqz a3, 0x800020e4 +80002084: b7 06 80 7f lui a3, 522240 +80002088: 63 72 d7 06 bgeu a4, a3, 0x800020ec +8000208c: 33 f6 d7 00 and a2, a5, a3 +80002090: 63 16 06 06 bnez a2, 0x800020fc +80002094: 17 27 00 00 auipc a4, 2 +80002098: 87 27 87 f2 flw fa5, -216(a4) +8000209c: d3 77 f5 10 fmul.s fa5, fa0, fa5 +800020a0: 37 47 ff ff lui a4, 1048564 +800020a4: 13 07 07 cb addi a4, a4, -848 +800020a8: d3 87 07 e0 fmv.x.w a5, fa5 +800020ac: 63 4e e5 0a blt a0, a4, 0x80002168 +800020b0: 13 d7 77 41 srai a4, a5, 23 +800020b4: 13 77 f7 0f andi a4, a4, 255 +800020b8: 13 07 77 fe addi a4, a4, -25 +800020bc: 33 05 a7 00 add a0, a4, a0 +800020c0: 13 07 e0 0f li a4, 254 +800020c4: 93 86 07 00 mv a3, a5 +800020c8: 63 54 a7 04 bge a4, a0, 0x80002110 +800020cc: d3 87 07 f0 fmv.w.x fa5, a5 +800020d0: 17 27 00 00 auipc a4, 2 +800020d4: 07 27 87 ee flw fa4, -280(a4) +800020d8: d3 07 f7 20 fsgnj.s fa5, fa4, fa5 +800020dc: d3 f7 e7 10 fmul.s fa5, fa5, fa4 +800020e0: d3 87 07 e0 fmv.x.w a5, fa5 +800020e4: 53 85 07 f0 fmv.w.x fa0, a5 +800020e8: 67 80 00 00 ret +800020ec: d3 77 a5 00 fadd.s fa5, fa0, fa0 +800020f0: d3 87 07 e0 fmv.x.w a5, fa5 +800020f4: 53 85 07 f0 fmv.w.x fa0, a5 +800020f8: 67 80 00 00 ret +800020fc: 13 57 77 01 srli a4, a4, 23 +80002100: 33 05 a7 00 add a0, a4, a0 +80002104: 13 07 e0 0f li a4, 254 +80002108: 93 86 07 00 mv a3, a5 +8000210c: e3 40 a7 fc blt a4, a0, 0x800020cc +80002110: 63 4e a0 02 bgtz a0, 0x8000214c +80002114: 13 07 a0 fe li a4, -22 +80002118: 63 44 e5 06 blt a0, a4, 0x80002180 +8000211c: b7 07 80 80 lui a5, 526336 +80002120: 93 87 f7 ff addi a5, a5, -1 +80002124: 13 05 95 01 addi a0, a0, 25 +80002128: b3 f6 f6 00 and a3, a3, a5 +8000212c: 13 15 75 01 slli a0, a0, 23 +80002130: 33 65 d5 00 or a0, a0, a3 +80002134: 53 07 05 f0 fmv.w.x fa4, a0 +80002138: 97 27 00 00 auipc a5, 2 +8000213c: 87 a7 c7 e8 flw fa5, -372(a5) +80002140: d3 77 f7 10 fmul.s fa5, fa4, fa5 +80002144: d3 87 07 e0 fmv.x.w a5, fa5 +80002148: 6f f0 df f9 j 0x800020e4 +8000214c: b7 07 80 80 lui a5, 526336 +80002150: 93 87 f7 ff addi a5, a5, -1 +80002154: 13 15 75 01 slli a0, a0, 23 +80002158: b3 f6 f6 00 and a3, a3, a5 +8000215c: b3 67 d5 00 or a5, a0, a3 +80002160: 53 85 07 f0 fmv.w.x fa0, a5 +80002164: 67 80 00 00 ret +80002168: 53 87 07 f0 fmv.w.x fa4, a5 +8000216c: 17 27 00 00 auipc a4, 2 +80002170: 87 27 47 e5 flw fa5, -428(a4) +80002174: d3 77 f7 10 fmul.s fa5, fa4, fa5 +80002178: d3 87 07 e0 fmv.x.w a5, fa5 +8000217c: 6f f0 9f f6 j 0x800020e4 +80002180: d3 87 07 f0 fmv.w.x fa5, a5 +80002184: 17 27 00 00 auipc a4, 2 +80002188: 07 27 c7 e3 flw fa4, -452(a4) +8000218c: d3 07 f7 20 fsgnj.s fa5, fa4, fa5 +80002190: d3 f7 e7 10 fmul.s fa5, fa5, fa4 +80002194: d3 87 07 e0 fmv.x.w a5, fa5 +80002198: 6f f0 df f4 j 0x800020e4 + +8000219c : +8000219c: 93 05 05 00 mv a1, a0 +800021a0: 93 06 00 00 li a3, 0 +800021a4: 13 06 00 00 li a2, 0 +800021a8: 13 05 00 00 li a0, 0 +800021ac: 6f 00 40 28 j 0x80002430 <__register_exitproc> + +800021b0 : +800021b0: b3 47 b5 00 xor a5, a0, a1 +800021b4: 93 f7 37 00 andi a5, a5, 3 +800021b8: b3 08 c5 00 add a7, a0, a2 +800021bc: 63 94 07 06 bnez a5, 0x80002224 +800021c0: 93 07 30 00 li a5, 3 +800021c4: 63 f0 c7 06 bgeu a5, a2, 0x80002224 +800021c8: 93 77 35 00 andi a5, a0, 3 +800021cc: 13 07 05 00 mv a4, a0 +800021d0: 63 9a 07 06 bnez a5, 0x80002244 +800021d4: 13 f6 c8 ff andi a2, a7, -4 +800021d8: b3 06 e6 40 sub a3, a2, a4 +800021dc: 93 07 00 02 li a5, 32 +800021e0: 63 ce d7 08 blt a5, a3, 0x8000227c +800021e4: 93 86 05 00 mv a3, a1 +800021e8: 93 07 07 00 mv a5, a4 +800021ec: 63 78 c7 02 bgeu a4, a2, 0x8000221c +800021f0: 03 a8 06 00 lw a6, 0(a3) +800021f4: 93 87 47 00 addi a5, a5, 4 +800021f8: 93 86 46 00 addi a3, a3, 4 +800021fc: 23 ae 07 ff sw a6, -4(a5) +80002200: e3 e8 c7 fe bltu a5, a2, 0x800021f0 +80002204: 93 07 f6 ff addi a5, a2, -1 +80002208: b3 87 e7 40 sub a5, a5, a4 +8000220c: 93 f7 c7 ff andi a5, a5, -4 +80002210: 93 87 47 00 addi a5, a5, 4 +80002214: 33 07 f7 00 add a4, a4, a5 +80002218: b3 85 f5 00 add a1, a1, a5 +8000221c: 63 68 17 01 bltu a4, a7, 0x8000222c +80002220: 67 80 00 00 ret +80002224: 13 07 05 00 mv a4, a0 +80002228: 63 78 15 05 bgeu a0, a7, 0x80002278 +8000222c: 83 c7 05 00 lbu a5, 0(a1) +80002230: 13 07 17 00 addi a4, a4, 1 +80002234: 93 85 15 00 addi a1, a1, 1 +80002238: a3 0f f7 fe sb a5, -1(a4) +8000223c: e3 98 e8 fe bne a7, a4, 0x8000222c +80002240: 67 80 00 00 ret +80002244: 83 c6 05 00 lbu a3, 0(a1) +80002248: 13 07 17 00 addi a4, a4, 1 +8000224c: 93 77 37 00 andi a5, a4, 3 +80002250: a3 0f d7 fe sb a3, -1(a4) +80002254: 93 85 15 00 addi a1, a1, 1 +80002258: e3 8e 07 f6 beqz a5, 0x800021d4 +8000225c: 83 c6 05 00 lbu a3, 0(a1) +80002260: 13 07 17 00 addi a4, a4, 1 +80002264: 93 77 37 00 andi a5, a4, 3 +80002268: a3 0f d7 fe sb a3, -1(a4) +8000226c: 93 85 15 00 addi a1, a1, 1 +80002270: e3 9a 07 fc bnez a5, 0x80002244 +80002274: 6f f0 1f f6 j 0x800021d4 +80002278: 67 80 00 00 ret +8000227c: 13 01 01 ff addi sp, sp, -16 +80002280: 23 26 81 00 sw s0, 12(sp) +80002284: 13 04 00 02 li s0, 32 +80002288: 83 a3 05 00 lw t2, 0(a1) +8000228c: 83 a2 45 00 lw t0, 4(a1) +80002290: 83 af 85 00 lw t6, 8(a1) +80002294: 03 af c5 00 lw t5, 12(a1) +80002298: 83 ae 05 01 lw t4, 16(a1) +8000229c: 03 ae 45 01 lw t3, 20(a1) +800022a0: 03 a3 85 01 lw t1, 24(a1) +800022a4: 03 a8 c5 01 lw a6, 28(a1) +800022a8: 83 a6 05 02 lw a3, 32(a1) +800022ac: 13 07 47 02 addi a4, a4, 36 +800022b0: b3 07 e6 40 sub a5, a2, a4 +800022b4: 23 2e 77 fc sw t2, -36(a4) +800022b8: 23 20 57 fe sw t0, -32(a4) +800022bc: 23 22 f7 ff sw t6, -28(a4) +800022c0: 23 24 e7 ff sw t5, -24(a4) +800022c4: 23 26 d7 ff sw t4, -20(a4) +800022c8: 23 28 c7 ff sw t3, -16(a4) +800022cc: 23 2a 67 fe sw t1, -12(a4) +800022d0: 23 2c 07 ff sw a6, -8(a4) +800022d4: 23 2e d7 fe sw a3, -4(a4) +800022d8: 93 85 45 02 addi a1, a1, 36 +800022dc: e3 46 f4 fa blt s0, a5, 0x80002288 +800022e0: 93 86 05 00 mv a3, a1 +800022e4: 93 07 07 00 mv a5, a4 +800022e8: 63 78 c7 02 bgeu a4, a2, 0x80002318 +800022ec: 03 a8 06 00 lw a6, 0(a3) +800022f0: 93 87 47 00 addi a5, a5, 4 +800022f4: 93 86 46 00 addi a3, a3, 4 +800022f8: 23 ae 07 ff sw a6, -4(a5) +800022fc: e3 e8 c7 fe bltu a5, a2, 0x800022ec +80002300: 93 07 f6 ff addi a5, a2, -1 +80002304: b3 87 e7 40 sub a5, a5, a4 +80002308: 93 f7 c7 ff andi a5, a5, -4 +8000230c: 93 87 47 00 addi a5, a5, 4 +80002310: 33 07 f7 00 add a4, a4, a5 +80002314: b3 85 f5 00 add a1, a1, a5 +80002318: 63 68 17 01 bltu a4, a7, 0x80002328 +8000231c: 03 24 c1 00 lw s0, 12(sp) +80002320: 13 01 01 01 addi sp, sp, 16 +80002324: 67 80 00 00 ret +80002328: 83 c7 05 00 lbu a5, 0(a1) +8000232c: 13 07 17 00 addi a4, a4, 1 +80002330: 93 85 15 00 addi a1, a1, 1 +80002334: a3 0f f7 fe sb a5, -1(a4) +80002338: e3 82 e8 fe beq a7, a4, 0x8000231c +8000233c: 83 c7 05 00 lbu a5, 0(a1) +80002340: 13 07 17 00 addi a4, a4, 1 +80002344: 93 85 15 00 addi a1, a1, 1 +80002348: a3 0f f7 fe sb a5, -1(a4) +8000234c: e3 9e e8 fc bne a7, a4, 0x80002328 +80002350: 6f f0 df fc j 0x8000231c + +80002354 : +80002354: 13 03 f0 00 li t1, 15 +80002358: 13 07 05 00 mv a4, a0 +8000235c: 63 7e c3 02 bgeu t1, a2, 0x80002398 +80002360: 93 77 f7 00 andi a5, a4, 15 +80002364: 63 90 07 0a bnez a5, 0x80002404 +80002368: 63 92 05 08 bnez a1, 0x800023ec +8000236c: 93 76 06 ff andi a3, a2, -16 +80002370: 13 76 f6 00 andi a2, a2, 15 +80002374: b3 86 e6 00 add a3, a3, a4 +80002378: 23 20 b7 00 sw a1, 0(a4) +8000237c: 23 22 b7 00 sw a1, 4(a4) +80002380: 23 24 b7 00 sw a1, 8(a4) +80002384: 23 26 b7 00 sw a1, 12(a4) +80002388: 13 07 07 01 addi a4, a4, 16 +8000238c: e3 66 d7 fe bltu a4, a3, 0x80002378 +80002390: 63 14 06 00 bnez a2, 0x80002398 +80002394: 67 80 00 00 ret +80002398: b3 06 c3 40 sub a3, t1, a2 +8000239c: 93 96 26 00 slli a3, a3, 2 +800023a0: 97 02 00 00 auipc t0, 0 +800023a4: b3 86 56 00 add a3, a3, t0 +800023a8: 67 80 c6 00 jr 12(a3) +800023ac: 23 07 b7 00 sb a1, 14(a4) +800023b0: a3 06 b7 00 sb a1, 13(a4) +800023b4: 23 06 b7 00 sb a1, 12(a4) +800023b8: a3 05 b7 00 sb a1, 11(a4) +800023bc: 23 05 b7 00 sb a1, 10(a4) +800023c0: a3 04 b7 00 sb a1, 9(a4) +800023c4: 23 04 b7 00 sb a1, 8(a4) +800023c8: a3 03 b7 00 sb a1, 7(a4) +800023cc: 23 03 b7 00 sb a1, 6(a4) +800023d0: a3 02 b7 00 sb a1, 5(a4) +800023d4: 23 02 b7 00 sb a1, 4(a4) +800023d8: a3 01 b7 00 sb a1, 3(a4) +800023dc: 23 01 b7 00 sb a1, 2(a4) +800023e0: a3 00 b7 00 sb a1, 1(a4) +800023e4: 23 00 b7 00 sb a1, 0(a4) +800023e8: 67 80 00 00 ret +800023ec: 93 f5 f5 0f andi a1, a1, 255 +800023f0: 93 96 85 00 slli a3, a1, 8 +800023f4: b3 e5 d5 00 or a1, a1, a3 +800023f8: 93 96 05 01 slli a3, a1, 16 +800023fc: b3 e5 d5 00 or a1, a1, a3 +80002400: 6f f0 df f6 j 0x8000236c +80002404: 93 96 27 00 slli a3, a5, 2 +80002408: 97 02 00 00 auipc t0, 0 +8000240c: b3 86 56 00 add a3, a3, t0 +80002410: 93 82 00 00 mv t0, ra +80002414: e7 80 06 fa jalr -96(a3) +80002418: 93 80 02 00 mv ra, t0 +8000241c: 93 87 07 ff addi a5, a5, -16 +80002420: 33 07 f7 40 sub a4, a4, a5 +80002424: 33 06 f6 00 add a2, a2, a5 +80002428: e3 78 c3 f6 bgeu t1, a2, 0x80002398 +8000242c: 6f f0 df f3 j 0x80002368 + +80002430 <__register_exitproc>: +80002430: 17 27 00 00 auipc a4, 2 +80002434: 03 27 87 b9 lw a4, -1128(a4) +80002438: 83 27 87 14 lw a5, 328(a4) +8000243c: 63 8c 07 04 beqz a5, 0x80002494 <__register_exitproc+0x64> +80002440: 03 a7 47 00 lw a4, 4(a5) +80002444: 13 08 f0 01 li a6, 31 +80002448: 63 4e e8 06 blt a6, a4, 0x800024c4 <__register_exitproc+0x94> +8000244c: 13 18 27 00 slli a6, a4, 2 +80002450: 63 06 05 02 beqz a0, 0x8000247c <__register_exitproc+0x4c> +80002454: 33 83 07 01 add t1, a5, a6 +80002458: 23 24 c3 08 sw a2, 136(t1) +8000245c: 83 a8 87 18 lw a7, 392(a5) +80002460: 13 06 10 00 li a2, 1 +80002464: 33 16 e6 00 sll a2, a2, a4 +80002468: b3 e8 c8 00 or a7, a7, a2 +8000246c: 23 a4 17 19 sw a7, 392(a5) +80002470: 23 24 d3 10 sw a3, 264(t1) +80002474: 93 06 20 00 li a3, 2 +80002478: 63 04 d5 02 beq a0, a3, 0x800024a0 <__register_exitproc+0x70> +8000247c: 13 07 17 00 addi a4, a4, 1 +80002480: 23 a2 e7 00 sw a4, 4(a5) +80002484: b3 87 07 01 add a5, a5, a6 +80002488: 23 a4 b7 00 sw a1, 8(a5) +8000248c: 13 05 00 00 li a0, 0 +80002490: 67 80 00 00 ret +80002494: 93 07 c7 14 addi a5, a4, 332 +80002498: 23 24 f7 14 sw a5, 328(a4) +8000249c: 6f f0 5f fa j 0x80002440 <__register_exitproc+0x10> +800024a0: 83 a6 c7 18 lw a3, 396(a5) +800024a4: 13 07 17 00 addi a4, a4, 1 +800024a8: 23 a2 e7 00 sw a4, 4(a5) +800024ac: b3 e6 c6 00 or a3, a3, a2 +800024b0: 23 a6 d7 18 sw a3, 396(a5) +800024b4: b3 87 07 01 add a5, a5, a6 +800024b8: 23 a4 b7 00 sw a1, 8(a5) +800024bc: 13 05 00 00 li a0, 0 +800024c0: 67 80 00 00 ret +800024c4: 13 05 f0 ff li a0, -1 +800024c8: 67 80 00 00 ret + +800024cc <__call_exitprocs>: +800024cc: 13 01 01 fd addi sp, sp, -48 +800024d0: 23 2c 41 01 sw s4, 24(sp) +800024d4: 17 2a 00 00 auipc s4, 2 +800024d8: 03 2a 4a af lw s4, -1292(s4) +800024dc: 23 20 21 03 sw s2, 32(sp) +800024e0: 03 29 8a 14 lw s2, 328(s4) +800024e4: 23 26 11 02 sw ra, 44(sp) +800024e8: 23 24 81 02 sw s0, 40(sp) +800024ec: 23 22 91 02 sw s1, 36(sp) +800024f0: 23 2e 31 01 sw s3, 28(sp) +800024f4: 23 2a 51 01 sw s5, 20(sp) +800024f8: 23 28 61 01 sw s6, 16(sp) +800024fc: 23 26 71 01 sw s7, 12(sp) +80002500: 23 24 81 01 sw s8, 8(sp) +80002504: 63 00 09 04 beqz s2, 0x80002544 <__call_exitprocs+0x78> +80002508: 13 0b 05 00 mv s6, a0 +8000250c: 93 8b 05 00 mv s7, a1 +80002510: 93 0a 10 00 li s5, 1 +80002514: 93 09 f0 ff li s3, -1 +80002518: 83 24 49 00 lw s1, 4(s2) +8000251c: 13 84 f4 ff addi s0, s1, -1 +80002520: 63 42 04 02 bltz s0, 0x80002544 <__call_exitprocs+0x78> +80002524: 93 94 24 00 slli s1, s1, 2 +80002528: b3 04 99 00 add s1, s2, s1 +8000252c: 63 84 0b 04 beqz s7, 0x80002574 <__call_exitprocs+0xa8> +80002530: 83 a7 44 10 lw a5, 260(s1) +80002534: 63 80 77 05 beq a5, s7, 0x80002574 <__call_exitprocs+0xa8> +80002538: 13 04 f4 ff addi s0, s0, -1 +8000253c: 93 84 c4 ff addi s1, s1, -4 +80002540: e3 16 34 ff bne s0, s3, 0x8000252c <__call_exitprocs+0x60> +80002544: 83 20 c1 02 lw ra, 44(sp) +80002548: 03 24 81 02 lw s0, 40(sp) +8000254c: 83 24 41 02 lw s1, 36(sp) +80002550: 03 29 01 02 lw s2, 32(sp) +80002554: 83 29 c1 01 lw s3, 28(sp) +80002558: 03 2a 81 01 lw s4, 24(sp) +8000255c: 83 2a 41 01 lw s5, 20(sp) +80002560: 03 2b 01 01 lw s6, 16(sp) +80002564: 83 2b c1 00 lw s7, 12(sp) +80002568: 03 2c 81 00 lw s8, 8(sp) +8000256c: 13 01 01 03 addi sp, sp, 48 +80002570: 67 80 00 00 ret +80002574: 83 27 49 00 lw a5, 4(s2) +80002578: 83 a6 44 00 lw a3, 4(s1) +8000257c: 93 87 f7 ff addi a5, a5, -1 +80002580: 63 8e 87 04 beq a5, s0, 0x800025dc <__call_exitprocs+0x110> +80002584: 23 a2 04 00 sw zero, 4(s1) +80002588: e3 88 06 fa beqz a3, 0x80002538 <__call_exitprocs+0x6c> +8000258c: 83 27 89 18 lw a5, 392(s2) +80002590: 33 97 8a 00 sll a4, s5, s0 +80002594: 03 2c 49 00 lw s8, 4(s2) +80002598: b3 77 f7 00 and a5, a4, a5 +8000259c: 63 92 07 02 bnez a5, 0x800025c0 <__call_exitprocs+0xf4> +800025a0: e7 80 06 00 jalr a3 +800025a4: 03 27 49 00 lw a4, 4(s2) +800025a8: 83 27 8a 14 lw a5, 328(s4) +800025ac: 63 14 87 01 bne a4, s8, 0x800025b4 <__call_exitprocs+0xe8> +800025b0: e3 84 27 f9 beq a5, s2, 0x80002538 <__call_exitprocs+0x6c> +800025b4: e3 88 07 f8 beqz a5, 0x80002544 <__call_exitprocs+0x78> +800025b8: 13 89 07 00 mv s2, a5 +800025bc: 6f f0 df f5 j 0x80002518 <__call_exitprocs+0x4c> +800025c0: 83 27 c9 18 lw a5, 396(s2) +800025c4: 83 a5 44 08 lw a1, 132(s1) +800025c8: 33 77 f7 00 and a4, a4, a5 +800025cc: 63 1c 07 00 bnez a4, 0x800025e4 <__call_exitprocs+0x118> +800025d0: 13 05 0b 00 mv a0, s6 +800025d4: e7 80 06 00 jalr a3 +800025d8: 6f f0 df fc j 0x800025a4 <__call_exitprocs+0xd8> +800025dc: 23 22 89 00 sw s0, 4(s2) +800025e0: 6f f0 9f fa j 0x80002588 <__call_exitprocs+0xbc> +800025e4: 13 85 05 00 mv a0, a1 +800025e8: e7 80 06 00 jalr a3 +800025ec: 6f f0 9f fb j 0x800025a4 <__call_exitprocs+0xd8> + +800025f0 <__clzsi2>: +800025f0: b7 07 01 00 lui a5, 16 +800025f4: 63 7a f5 02 bgeu a0, a5, 0x80002628 <__clzsi2+0x38> +800025f8: 93 37 05 10 sltiu a5, a0, 256 +800025fc: 93 c7 17 00 xori a5, a5, 1 +80002600: 93 97 37 00 slli a5, a5, 3 +80002604: 13 07 00 02 li a4, 32 +80002608: 33 07 f7 40 sub a4, a4, a5 +8000260c: 33 55 f5 00 srl a0, a0, a5 +80002610: 97 07 00 00 auipc a5, 0 +80002614: 93 87 47 40 addi a5, a5, 1028 +80002618: b3 87 a7 00 add a5, a5, a0 +8000261c: 03 c5 07 00 lbu a0, 0(a5) +80002620: 33 05 a7 40 sub a0, a4, a0 +80002624: 67 80 00 00 ret +80002628: 37 07 00 01 lui a4, 4096 +8000262c: 93 07 00 01 li a5, 16 +80002630: e3 6a e5 fc bltu a0, a4, 0x80002604 <__clzsi2+0x14> +80002634: 93 07 80 01 li a5, 24 +80002638: 6f f0 df fc j 0x80002604 <__clzsi2+0x14> + +Disassembly of section .rodata: + +8000263c <.rodata>: +8000263c: db 0f c9 c0 +80002640: 00 00 +80002642: 80 3d + +80002644 : +80002644: 00 0f +80002646: c9 3f +80002648: 00 0f +8000264a: 49 40 +8000264c: 00 cb +8000264e: 96 40 +80002650: 00 0f +80002652: c9 40 +80002654: 00 53 +80002656: fb 40 00 cb +8000265a: 16 41 +8000265c: 00 ed +8000265e: 2f 41 00 0f +80002662: 49 41 +80002664: 00 31 +80002666: 62 41 +80002668: 00 53 +8000266a: 7b 41 00 3a +8000266e: 8a 41 +80002670: 00 cb +80002672: 96 41 +80002674: 00 5c +80002676: a3 41 00 ed +8000267a: af 41 00 7e +8000267e: bc 41 +80002680: 00 0f +80002682: c9 41 +80002684: 00 a0 +80002686: d5 41 +80002688: 00 31 +8000268a: e2 41 +8000268c: 00 c2 +8000268e: ee 41 +80002690: 00 53 +80002692: fb 41 00 f2 +80002696: 03 42 00 3a lbu tp, 928(zero) +8000269a: 0a 42 +8000269c: 00 83 +8000269e: 10 42 +800026a0: 00 cb +800026a2: 16 42 +800026a4: 00 14 +800026a6: 1d 42 +800026a8: 00 5c +800026aa: 23 42 00 a5 +800026ae: 29 42 +800026b0: 00 ed +800026b2: 2f 42 00 36 +800026b6: 36 42 +800026b8: 00 7e +800026ba: 3c 42 +800026bc: 00 c7 +800026be: 42 42 +800026c0: 00 0f +800026c2: 49 42 + +800026c4 : +800026c4: a2 00 +800026c6: 00 00 +800026c8: f9 00 +800026ca: 00 00 +800026cc: 83 00 00 00 lb ra, 0(zero) +800026d0: 6e 00 +800026d2: 00 00 +800026d4: 4e 00 +800026d6: 00 00 +800026d8: 44 00 +800026da: 00 00 +800026dc: 15 00 +800026de: 00 00 +800026e0: 29 00 +800026e2: 00 00 +800026e4: fc 00 +800026e6: 00 00 +800026e8: 27 00 00 00 +800026ec: 57 00 00 00 +800026f0: d1 00 +800026f2: 00 00 +800026f4: f5 00 +800026f6: 00 00 +800026f8: 34 00 +800026fa: 00 00 +800026fc: dd 00 +800026fe: 00 00 +80002700: c0 00 +80002702: 00 00 +80002704: db 00 00 00 +80002708: 62 00 +8000270a: 00 00 +8000270c: 95 00 +8000270e: 00 00 +80002710: 99 00 +80002712: 00 00 +80002714: 3c 00 +80002716: 00 00 +80002718: 43 00 00 00 fmadd.s ft0, ft0, ft0, ft0, rne +8000271c: 90 00 +8000271e: 00 00 +80002720: 41 00 +80002722: 00 00 +80002724: fe 00 +80002726: 00 00 +80002728: 51 00 +8000272a: 00 00 +8000272c: 63 00 00 00 beqz zero, 0x8000272c +80002730: ab 00 00 00 vx_tex ra, 0, zero, zero, zero +80002734: de 00 +80002736: 00 00 +80002738: bb 00 00 00 +8000273c: c5 00 +8000273e: 00 00 +80002740: 61 00 +80002742: 00 00 +80002744: b7 00 00 00 lui ra, 0 +80002748: 24 00 +8000274a: 00 00 +8000274c: 6e 00 +8000274e: 00 00 +80002750: 3a 00 +80002752: 00 00 +80002754: 42 00 +80002756: 00 00 +80002758: 4d 00 +8000275a: 00 00 +8000275c: d2 00 +8000275e: 00 00 +80002760: e0 00 +80002762: 00 00 +80002764: 06 00 +80002766: 00 00 +80002768: 49 00 +8000276a: 00 00 +8000276c: 2e 00 +8000276e: 00 00 +80002770: ea 00 +80002772: 00 00 +80002774: 09 00 +80002776: 00 00 +80002778: d1 00 +8000277a: 00 00 +8000277c: 92 00 +8000277e: 00 00 +80002780: 1c 00 +80002782: 00 00 +80002784: fe 00 +80002786: 00 00 +80002788: 1d 00 +8000278a: 00 00 +8000278c: eb 00 00 00 +80002790: 1c 00 +80002792: 00 00 +80002794: b1 00 +80002796: 00 00 +80002798: 29 00 +8000279a: 00 00 +8000279c: a7 00 00 00 +800027a0: 3e 00 +800027a2: 00 00 +800027a4: e8 00 +800027a6: 00 00 +800027a8: 82 00 +800027aa: 00 00 +800027ac: 35 00 +800027ae: 00 00 +800027b0: f5 00 +800027b2: 00 00 +800027b4: 2e 00 +800027b6: 00 00 +800027b8: bb 00 00 00 +800027bc: 44 00 +800027be: 00 00 +800027c0: 84 00 +800027c2: 00 00 +800027c4: e9 00 +800027c6: 00 00 +800027c8: 9c 00 +800027ca: 00 00 +800027cc: 70 00 +800027ce: 00 00 +800027d0: 26 00 +800027d2: 00 00 +800027d4: b4 00 +800027d6: 00 00 +800027d8: 5f 00 00 00 +800027dc: 7e 00 +800027de: 00 00 +800027e0: 41 00 +800027e2: 00 00 +800027e4: 39 00 +800027e6: 00 00 +800027e8: 91 00 +800027ea: 00 00 +800027ec: d6 00 +800027ee: 00 00 +800027f0: 39 00 +800027f2: 00 00 +800027f4: 83 00 00 00 lb ra, 0(zero) +800027f8: 53 00 00 00 fadd.s ft0, ft0, ft0, rne +800027fc: 39 00 +800027fe: 00 00 +80002800: f4 00 +80002802: 00 00 +80002804: 9c 00 +80002806: 00 00 +80002808: 84 00 +8000280a: 00 00 +8000280c: 5f 00 00 00 +80002810: 8b 00 00 00 +80002814: bd 00 +80002816: 00 00 +80002818: f9 00 +8000281a: 00 00 +8000281c: 28 00 +8000281e: 00 00 +80002820: 3b 00 00 00 +80002824: 1f 00 00 00 +80002828: f8 00 +8000282a: 00 00 +8000282c: 97 00 00 00 auipc ra, 0 +80002830: ff 00 00 00 +80002834: de 00 +80002836: 00 00 +80002838: 05 00 +8000283a: 00 00 +8000283c: 98 00 +8000283e: 00 00 +80002840: 0f 00 00 00 fence 0, 0 +80002844: ef 00 00 00 jal 0x80002844 +80002848: 2f 00 00 00 +8000284c: 11 00 +8000284e: 00 00 +80002850: 8b 00 00 00 +80002854: 5a 00 +80002856: 00 00 +80002858: 0a 00 +8000285a: 00 00 +8000285c: 6d 00 +8000285e: 00 00 +80002860: 1f 00 00 00 +80002864: 6d 00 +80002866: 00 00 +80002868: 36 00 +8000286a: 00 00 +8000286c: 7e 00 +8000286e: 00 00 +80002870: cf 00 00 00 fnmadd.s ft1, ft0, ft0, ft0, rne +80002874: 27 00 00 00 +80002878: cb 00 00 00 fnmsub.s ft1, ft0, ft0, ft0, rne +8000287c: 09 00 +8000287e: 00 00 +80002880: b7 00 00 00 lui ra, 0 +80002884: 4f 00 00 00 fnmadd.s ft0, ft0, ft0, ft0, rne +80002888: 46 00 +8000288a: 00 00 +8000288c: 3f 00 00 00 +80002890: 66 00 +80002892: 00 00 +80002894: 9e 00 +80002896: 00 00 +80002898: 5f 00 00 00 +8000289c: ea 00 +8000289e: 00 00 +800028a0: 2d 00 +800028a2: 00 00 +800028a4: 75 00 +800028a6: 00 00 +800028a8: 27 00 00 00 +800028ac: ba 00 +800028ae: 00 00 +800028b0: c7 00 00 00 fmsub.s ft1, ft0, ft0, ft0, rne +800028b4: eb 00 00 00 +800028b8: e5 00 +800028ba: 00 00 +800028bc: f1 00 +800028be: 00 00 +800028c0: 7b 00 00 00 +800028c4: 3d 00 +800028c6: 00 00 +800028c8: 07 00 00 00 +800028cc: 39 00 +800028ce: 00 00 +800028d0: f7 00 00 00 +800028d4: 8a 00 +800028d6: 00 00 +800028d8: 52 00 +800028da: 00 00 +800028dc: 92 00 +800028de: 00 00 +800028e0: ea 00 +800028e2: 00 00 +800028e4: 6b 00 00 00 +800028e8: fb 00 00 00 +800028ec: 5f 00 00 00 +800028f0: b1 00 +800028f2: 00 00 +800028f4: 1f 00 00 00 +800028f8: 8d 00 +800028fa: 00 00 +800028fc: 5d 00 +800028fe: 00 00 +80002900: 08 00 +80002902: 00 00 +80002904: 56 00 +80002906: 00 00 +80002908: 03 00 00 00 lb zero, 0(zero) +8000290c: 30 00 +8000290e: 00 00 +80002910: 46 00 +80002912: 00 00 +80002914: fc 00 +80002916: 00 00 +80002918: 7b 00 00 00 +8000291c: 6b 00 00 00 +80002920: ab 00 00 00 vx_tex ra, 0, zero, zero, zero +80002924: f0 00 +80002926: 00 00 +80002928: cf 00 00 00 fnmadd.s ft1, ft0, ft0, ft0, rne +8000292c: bc 00 +8000292e: 00 00 +80002930: 20 00 +80002932: 00 00 +80002934: 9a 00 +80002936: 00 00 +80002938: f4 00 +8000293a: 00 00 +8000293c: 36 00 +8000293e: 00 00 +80002940: 1d 00 +80002942: 00 00 +80002944: a9 00 +80002946: 00 00 +80002948: e3 00 00 00 beqz zero, 0x80003148 <__clz_tab+0x734> +8000294c: 91 00 +8000294e: 00 00 +80002950: 61 00 +80002952: 00 00 +80002954: 5e 00 +80002956: 00 00 +80002958: e6 00 +8000295a: 00 00 +8000295c: 1b 00 00 00 +80002960: 08 00 +80002962: 00 00 +80002964: 65 00 +80002966: 00 00 +80002968: 99 00 +8000296a: 00 00 +8000296c: 85 00 +8000296e: 00 00 +80002970: 5f 00 00 00 +80002974: 14 00 +80002976: 00 00 +80002978: a0 00 +8000297a: 00 00 +8000297c: 68 00 +8000297e: 00 00 +80002980: 40 00 +80002982: 00 00 +80002984: 8d 00 +80002986: 00 00 +80002988: ff 00 00 00 +8000298c: d8 00 +8000298e: 00 00 +80002990: 80 00 +80002992: 00 00 +80002994: 4d 00 +80002996: 00 00 +80002998: 73 00 00 00 ecall +8000299c: 27 00 00 00 +800029a0: 31 00 +800029a2: 00 00 +800029a4: 06 00 +800029a6: 00 00 +800029a8: 06 00 +800029aa: 00 00 +800029ac: 15 00 +800029ae: 00 00 +800029b0: 56 00 +800029b2: 00 00 +800029b4: ca 00 +800029b6: 00 00 +800029b8: 73 00 00 00 ecall +800029bc: a8 00 +800029be: 00 00 +800029c0: c9 00 +800029c2: 00 00 +800029c4: 60 00 +800029c6: 00 00 +800029c8: e2 00 +800029ca: 00 00 +800029cc: 7b 00 00 00 +800029d0: c0 00 +800029d2: 00 00 +800029d4: 8c 00 +800029d6: 00 00 +800029d8: 6b 00 00 00 + +800029dc : +800029dc: 00 00 +800029de: c9 3f +800029e0: 00 00 +800029e2: f0 39 +800029e4: 00 00 +800029e6: da 37 +800029e8: 00 00 +800029ea: a2 33 +800029ec: 00 00 +800029ee: 84 2e +800029f0: 00 00 +800029f2: 50 2b +800029f4: 00 00 +800029f6: c2 27 +800029f8: 00 00 +800029fa: d0 22 +800029fc: 00 00 +800029fe: c4 1f +80002a00: 00 00 +80002a02: c6 1b +80002a04: 00 00 +80002a06: 44 17 + +80002a08 : +80002a08: 04 00 +80002a0a: 00 00 +80002a0c: 07 00 00 00 +80002a10: 09 00 +80002a12: 00 00 + +80002a14 <__clz_tab>: +80002a14: 00 01 +80002a16: 02 02 +80002a18: 03 03 03 03 lb t1, 48(t1) +80002a1c: 04 04 +80002a1e: 04 04 +80002a20: 04 04 +80002a22: 04 04 +80002a24: 05 05 +80002a26: 05 05 +80002a28: 05 05 +80002a2a: 05 05 +80002a2c: 05 05 +80002a2e: 05 05 +80002a30: 05 05 +80002a32: 05 05 +80002a34: 06 06 +80002a36: 06 06 +80002a38: 06 06 +80002a3a: 06 06 +80002a3c: 06 06 +80002a3e: 06 06 +80002a40: 06 06 +80002a42: 06 06 +80002a44: 06 06 +80002a46: 06 06 +80002a48: 06 06 +80002a4a: 06 06 +80002a4c: 06 06 +80002a4e: 06 06 +80002a50: 06 06 +80002a52: 06 06 +80002a54: 07 07 07 07 +80002a58: 07 07 07 07 +80002a5c: 07 07 07 07 +80002a60: 07 07 07 07 +80002a64: 07 07 07 07 +80002a68: 07 07 07 07 +80002a6c: 07 07 07 07 +80002a70: 07 07 07 07 +80002a74: 07 07 07 07 +80002a78: 07 07 07 07 +80002a7c: 07 07 07 07 +80002a80: 07 07 07 07 +80002a84: 07 07 07 07 +80002a88: 07 07 07 07 +80002a8c: 07 07 07 07 +80002a90: 07 07 07 07 +80002a94: 08 08 +80002a96: 08 08 +80002a98: 08 08 +80002a9a: 08 08 +80002a9c: 08 08 +80002a9e: 08 08 +80002aa0: 08 08 +80002aa2: 08 08 +80002aa4: 08 08 +80002aa6: 08 08 +80002aa8: 08 08 +80002aaa: 08 08 +80002aac: 08 08 +80002aae: 08 08 +80002ab0: 08 08 +80002ab2: 08 08 +80002ab4: 08 08 +80002ab6: 08 08 +80002ab8: 08 08 +80002aba: 08 08 +80002abc: 08 08 +80002abe: 08 08 +80002ac0: 08 08 +80002ac2: 08 08 +80002ac4: 08 08 +80002ac6: 08 08 +80002ac8: 08 08 +80002aca: 08 08 +80002acc: 08 08 +80002ace: 08 08 +80002ad0: 08 08 +80002ad2: 08 08 +80002ad4: 08 08 +80002ad6: 08 08 +80002ad8: 08 08 +80002ada: 08 08 +80002adc: 08 08 +80002ade: 08 08 +80002ae0: 08 08 +80002ae2: 08 08 +80002ae4: 08 08 +80002ae6: 08 08 +80002ae8: 08 08 +80002aea: 08 08 +80002aec: 08 08 +80002aee: 08 08 +80002af0: 08 08 +80002af2: 08 08 +80002af4: 08 08 +80002af6: 08 08 +80002af8: 08 08 +80002afa: 08 08 +80002afc: 08 08 +80002afe: 08 08 +80002b00: 08 08 +80002b02: 08 08 +80002b04: 08 08 +80002b06: 08 08 +80002b08: 08 08 +80002b0a: 08 08 +80002b0c: 08 08 +80002b0e: 08 08 +80002b10: 08 08 +80002b12: 08 08 + +Disassembly of section .init_array: + +80003b14 <__tdata_start>: +80003b14: b8 00 +80003b16: 00 80 + +Disassembly of section .data: + +80003b18 : +80003b18: 00 00 +80003b1a: 00 00 +80003b1c: 04 3e +80003b1e: 00 80 +80003b20: 6c 3e +80003b22: 00 80 +80003b24: d4 3e +80003b26: 00 80 + ... +80003bc0: 01 00 +80003bc2: 00 00 +80003bc4: 00 00 +80003bc6: 00 00 +80003bc8: 0e 33 +80003bca: cd ab +80003bcc: 34 12 +80003bce: 6d e6 +80003bd0: ec de +80003bd2: 05 00 +80003bd4: 0b 00 00 00 vx_tmc zero + ... + +Disassembly of section .sdata: + +80003f40 <__SDATA_BEGIN__>: +80003f40: 80 0f +80003f42: c9 3f +80003f44: 43 44 35 37 +80003f48: 00 44 +80003f4a: 35 37 +80003f4c: 08 a3 +80003f4e: 85 2e +80003f50: 84 f9 +80003f52: 22 3f +80003f54: 00 00 +80003f56: 00 3f +80003f58: 00 a3 +80003f5a: 85 2e +80003f5c: 32 31 +80003f5e: 8d 24 +80003f60: 00 00 +80003f62: 80 43 +80003f64: 00 00 +80003f66: 38 3f +80003f68: 00 00 +80003f6a: 90 3e +80003f6c: 00 00 +80003f6e: 80 3f +80003f70: 4e d7 +80003f72: 47 ad f6 74 +80003f76: 0f 31 7c f2 +80003f7a: 93 b4 01 0d sltiu s1, gp, 208 +80003f7e: d0 37 +80003f80: 61 0b +80003f82: b6 ba +80003f84: ab aa 2a 3d +80003f88: 00 00 +80003f8a: 80 3b +80003f8c: 00 00 +80003f8e: 00 3e +80003f90: 00 00 +80003f92: 00 41 +80003f94: 00 00 +80003f96: 00 80 +80003f98: d3 c9 2e 2f +80003f9c: 34 2f +80003f9e: d7 b2 1b ef +80003fa2: 38 36 +80003fa4: 01 0d +80003fa6: 50 b9 +80003fa8: 89 88 +80003faa: 08 3c +80003fac: ab aa 2a be +80003fb0: ab aa 2a 3e +80003fb4: 00 00 +80003fb6: 80 bf +80003fb8: ca f2 +80003fba: 49 71 +80003fbc: 00 00 +80003fbe: 00 4c +80003fc0: 60 42 +80003fc2: a2 0d +80003fc4: 00 00 +80003fc6: 00 33 + +80003fc8 <_global_impure_ptr>: +80003fc8: 18 3b +80003fca: 00 80 + +Disassembly of section .bss: + +80003fcc : +... + +Disassembly of section .comment: + +00000000 <.comment>: + 0: 63 6c 61 6e bltu sp, t1, 0x6f8 <.comment+0x6f8> + 4: 67 20 76 65 + 8: 72 73 + a: 69 6f + c: 6e 20 + e: 31 36 + 10: 2e 30 + 12: 2e 36 + 14: 20 28 + 16: 68 74 + 18: 74 70 + 1a: 73 3a 2f 2f csrrc s4, 754, t5 + 1e: 67 69 74 68 + 22: 75 62 + 24: 2e 63 + 26: 6f 6d 2f 76 jal s10, 0xf6788 <.comment+0xf6788> + 2a: 6f 72 74 65 jal tp, 0x47e80 <.comment+0x47e80> + 2e: 78 67 + 30: 70 67 + 32: 70 75 + 34: 2f 6c 6c 76 + 38: 6d 2e + 3a: 67 69 74 20 + 3e: 35 38 + 40: 38 31 + 42: 31 62 + 44: 66 61 + 46: 36 31 + 48: 61 35 + 4a: 30 33 + 4c: 66 64 + 4e: 34 61 + 50: 35 66 + 52: 30 64 + 54: 63 37 62 35 + 58: 37 38 30 32 lui a6, 205571 + 5c: 66 61 + 5e: 65 35 + 60: 31 63 + 62: 33 66 35 64 + 66: 29 00 + 68: 47 43 43 3a + 6c: 20 28 + 6e: 67 32 65 65 + 72: 35 65 + 74: 34 33 + 76: 30 30 + 78: 31 38 + 7a: 2d 64 + 7c: 69 72 + 7e: 74 79 + 80: 29 20 + 82: 31 32 + 84: 2e 32 + 86: 2e 30 + 88: 00 47 + 8a: 43 43 3a 20 fmadd.s ft6, fs4, ft3, ft4, rmm + 8e: 28 47 + 90: 4e 55 + 92: 29 20 + 94: 31 32 + 96: 2e 32 + 98: 2e 30 + 9a: 00 + +Disassembly of section .riscv.attributes: + +00000000 <.riscv.attributes>: + 0: 41 40 + 2: 00 00 + 4: 00 72 + 6: 69 73 + 8: 63 76 00 01 bgeu zero, a6, 0x14 <.comment+0x14> + c: 36 00 + e: 00 00 + 10: 04 10 + 12: 05 72 + 14: 76 33 + 16: 32 69 + 18: 32 70 + 1a: 31 5f + 1c: 6d 32 + 1e: 70 30 + 20: 5f 61 32 70 + 24: 31 5f + 26: 66 32 + 28: 70 32 + 2a: 5f 7a 69 63 + 2e: 73 72 32 70 csrrci tp, 1795, 4 + 32: 30 5f + 34: 7a 6d + 36: 6d 75 + 38: 6c 31 + 3a: 70 30 + 3c: 00 08 + 3e: 01 0a + 40: 0b + +Disassembly of section .debug_aranges: + +00000000 <.debug_aranges>: + 0: 1c 00 + 2: 00 00 + 4: 02 00 + 6: 00 00 + 8: 00 00 + a: 04 00 + c: 00 00 + e: 00 00 + 10: f0 25 + 12: 00 80 + 14: 4c 00 + ... + 1e: 00 00 + 20: 14 00 + 22: 00 00 + 24: 02 00 + 26: 42 01 + 28: 00 00 + 2a: 04 00 + ... + +Disassembly of section .debug_info: + +00000000 <.debug_info>: + 0: 3e 01 + 2: 00 00 + 4: 05 00 + 6: 01 04 + 8: 00 00 + a: 00 00 + c: 04 2b + e: 00 00 + 10: 00 1d + 12: 00 00 + 14: 00 00 + 16: 21 00 + 18: 00 00 + 1a: f0 25 + 1c: 00 80 + 1e: 4c 00 + 20: 00 00 + 22: 00 00 + 24: 00 00 + 26: 05 04 + 28: 05 69 + 2a: 6e 74 + 2c: 00 01 + 2e: 04 07 + 30: f2 00 + 32: 00 00 + 34: 01 08 + 36: 05 00 + 38: 00 00 + 3a: 00 01 + 3c: 10 04 + 3e: 1f 01 00 00 + 42: 01 01 + 44: 06 01 + 46: 01 00 + 48: 00 01 + 4a: 01 08 + 4c: ff 00 00 00 + 50: 01 02 + 52: 05 5c + 54: 01 00 + 56: 00 01 + 58: 02 07 + 5a: 2b 01 00 00 vx_tex sp, 0, zero, zero, zero + 5e: 01 04 + 60: 05 05 + 62: 00 00 + 64: 00 01 + 66: 04 07 + 68: ed 00 + 6a: 00 00 + 6c: 01 08 + 6e: 07 e8 00 00 + 72: 00 01 + 74: 01 08 + 76: 08 01 + 78: 00 00 + 7a: 02 4c + 7c: 01 00 + 7e: 00 7b + 80: 16 49 + 82: 00 00 + 84: 00 03 + 86: 7a 00 + 88: 00 00 + 8a: 02 55 + 8c: 01 00 + 8e: 00 80 + 90: 0f 26 00 00 + 94: 00 02 + 96: 54 01 + 98: 00 00 + 9a: 81 16 + 9c: 2d 00 + 9e: 00 00 + a0: 01 04 + a2: 04 46 + a4: 01 00 + a6: 00 01 + a8: 08 03 + aa: 3e 01 + ac: 00 00 + ae: 01 08 + b0: 04 24 + b2: 01 00 + b4: 00 01 + b6: 10 03 + b8: 17 00 00 00 auipc zero, 0 + bc: 01 20 + be: 03 17 01 00 lh a4, 0(sp) + c2: 00 06 + c4: 85 00 + c6: 00 00 + c8: d3 00 00 00 fadd.s ft1, ft0, ft0, rne + cc: 07 2d 00 00 flw fs10, 0(zero) + d0: 00 ff + d2: 00 03 + d4: c3 00 00 00 fmadd.s ft1, ft0, ft0, ft0, rne + d8: 08 0d + da: 01 00 + dc: 00 02 + de: 02 02 + e0: 16 d3 + e2: 00 00 + e4: 00 09 + e6: 0e 00 + e8: 00 00 + ea: 01 ae + ec: 02 01 + ee: 26 00 + f0: 00 00 + f2: f0 25 + f4: 00 80 + f6: 4c 00 + f8: 00 00 + fa: 01 9c + fc: 0a 78 + fe: 00 01 + 100: ae 02 + 102: 12 95 + 104: 00 00 + 106: 00 0c + 108: 00 00 + 10a: 00 0b + 10c: 72 65 + 10e: 74 00 + 110: 01 b0 + 112: 02 09 + 114: 8a 00 + 116: 00 00 + 118: 0c 0c + 11a: 00 00 + 11c: 00 0d + 11e: 26 00 + 120: 00 00 + 122: 01 b2 + 124: 02 03 + 126: 95 00 + 128: 00 00 + 12a: 31 00 + 12c: 00 00 + 12e: 0e 5f + 130: 5f 61 00 01 + 134: b2 02 + 136: 03 95 00 00 lh a0, 0(ra) + 13a: 00 56 + 13c: 00 00 + 13e: 00 00 + 140: 00 00 + 142: d4 00 + 144: 00 00 + 146: 05 00 + 148: 01 04 + 14a: ca 00 + 14c: 00 00 + 14e: 03 2b 00 00 lw s6, 0(zero) + 152: 00 1d + 154: 00 00 + 156: 00 00 + 158: 21 00 + 15a: 00 00 + 15c: cb 00 00 00 fnmsub.s ft1, ft0, ft0, ft0, rne + 160: 04 04 + 162: 05 69 + 164: 6e 74 + 166: 00 01 + 168: 04 07 + 16a: f2 00 + 16c: 00 00 + 16e: 01 08 + 170: 05 00 + 172: 00 00 + 174: 00 01 + 176: 10 04 + 178: 1f 01 00 00 + 17c: 01 01 + 17e: 06 01 + 180: 01 00 + 182: 00 01 + 184: 01 08 + 186: ff 00 00 00 + 18a: 01 02 + 18c: 05 5c + 18e: 01 00 + 190: 00 01 + 192: 02 07 + 194: 2b 01 00 00 vx_tex sp, 0, zero, zero, zero + 198: 01 04 + 19a: 05 05 + 19c: 00 00 + 19e: 00 01 + 1a0: 04 07 + 1a2: ed 00 + 1a4: 00 00 + 1a6: 01 08 + 1a8: 07 e8 00 00 + 1ac: 00 01 + 1ae: 01 08 + 1b0: 08 01 + 1b2: 00 00 + 1b4: 05 4c + 1b6: 01 00 + 1b8: 00 01 + 1ba: 7b 16 41 00 + 1be: 00 00 + 1c0: 02 72 + 1c2: 00 00 + 1c4: 00 01 + 1c6: 04 04 + 1c8: 46 01 + 1ca: 00 00 + 1cc: 01 08 + 1ce: 03 3e 01 00 + 1d2: 00 01 + 1d4: 08 04 + 1d6: 24 01 + 1d8: 00 00 + 1da: 01 10 + 1dc: 03 17 00 00 lh a4, 0(zero) + 1e0: 00 01 + 1e2: 20 03 + 1e4: 17 01 00 00 auipc sp, 0 + 1e8: 06 7e + 1ea: 00 00 + 1ec: 00 b6 + 1ee: 00 00 + 1f0: 00 07 + 1f2: 25 00 + 1f4: 00 00 + 1f6: ff 00 02 a6 + 1fa: 00 00 + 1fc: 00 08 + 1fe: 0d 01 + 200: 00 00 + 202: 01 02 + 204: 02 16 + 206: b6 00 + 208: 00 00 + 20a: 09 bb + 20c: 00 00 + 20e: 00 02 + 210: 9e 02 + 212: 0f 05 03 14 + 216: 2a 00 + 218: 80 00 + +Disassembly of section .debug_abbrev: + +00000000 <.debug_abbrev>: + 0: 01 24 + 2: 00 0b + 4: 0b 3e 0b 03 + 8: 0e 00 + a: 00 02 + c: 16 00 + e: 03 0e 3a 21 lb t3, 531(s4) + 12: 02 3b + 14: 0b 39 0b 49 + 18: 13 00 00 03 li zero, 48 + 1c: 26 00 + 1e: 49 13 + 20: 00 00 + 22: 04 11 + 24: 01 25 + 26: 0e 13 + 28: 0b 03 1f 1b + 2c: 1f 11 01 12 + 30: 06 10 + 32: 17 00 00 05 auipc zero, 20480 + 36: 24 00 + 38: 0b 0b 3e 0b + 3c: 03 08 00 00 lb a6, 0(zero) + 40: 06 01 + 42: 01 49 + 44: 13 01 13 00 addi sp, t1, 1 + 48: 00 07 + 4a: 21 00 + 4c: 49 13 + 4e: 2f 0b 00 00 + 52: 08 34 + 54: 00 03 + 56: 0e 3a + 58: 0b 3b 05 39 + 5c: 0b 49 13 3f + 60: 19 3c + 62: 19 00 + 64: 00 09 + 66: 2e 01 + 68: 3f 19 03 0e + 6c: 3a 0b + 6e: 3b 05 39 0b + 72: 27 19 49 13 + 76: 11 01 + 78: 12 06 + 7a: 40 18 + 7c: 7a 19 + 7e: 00 00 + 80: 0a 05 + 82: 00 03 + 84: 08 3a + 86: 0b 3b 05 39 + 8a: 0b 49 13 02 + 8e: 17 00 00 0b auipc zero, 45056 + 92: 34 00 + 94: 03 08 3a 0b lb a6, 179(s4) + 98: 3b 05 39 0b + 9c: 49 13 + 9e: 00 00 + a0: 0c 0b + a2: 01 55 + a4: 17 00 00 0d auipc zero, 53248 + a8: 34 00 + aa: 03 0e 3a 0b lb t3, 179(s4) + ae: 3b 05 39 0b + b2: 49 13 + b4: 02 17 + b6: 00 00 + b8: 0e 34 + ba: 00 03 + bc: 08 3a + be: 0b 3b 05 39 + c2: 0b 49 13 02 + c6: 17 00 00 00 auipc zero, 0 + ca: 01 24 + cc: 00 0b + ce: 0b 3e 0b 03 + d2: 0e 00 + d4: 00 02 + d6: 26 00 + d8: 49 13 + da: 00 00 + dc: 03 11 01 25 lh sp, 592(sp) + e0: 0e 13 + e2: 0b 03 1f 1b + e6: 1f 10 17 00 + ea: 00 04 + ec: 24 00 + ee: 0b 0b 3e 0b + f2: 03 08 00 00 lb a6, 0(zero) + f6: 05 16 + f8: 00 03 + fa: 0e 3a + fc: 0b 3b 0b 39 + 100: 0b 49 13 00 + 104: 00 06 + 106: 01 01 + 108: 49 13 + 10a: 01 13 + 10c: 00 00 + 10e: 07 21 00 49 flw ft2, 1168(zero) + 112: 13 2f 0b 00 slti t5, s6, 0 + 116: 00 08 + 118: 34 00 + 11a: 03 0e 3a 0b lb t3, 179(s4) + 11e: 3b 05 39 0b + 122: 49 13 + 124: 3f 19 3c 19 + 128: 00 00 + 12a: 09 34 + 12c: 00 47 + 12e: 13 3a 0b 3b sltiu s4, s6, 944 + 132: 05 39 + 134: 0b 02 18 00 + 138: 00 00 + +Disassembly of section .debug_line: + +00000000 <.debug_line>: + 0: c7 00 00 00 fmsub.s ft1, ft0, ft0, ft0, rne + 4: 05 00 + 6: 04 00 + 8: 33 00 00 00 add zero, zero, zero + c: 01 01 + e: 01 fb + 10: 0e 0d + 12: 00 01 + 14: 01 01 + 16: 01 00 + 18: 00 00 + 1a: 01 00 + 1c: 00 01 + 1e: 01 01 + 20: 1f 02 21 00 + 24: 00 00 + 26: 81 00 + 28: 00 00 + 2a: 02 01 + 2c: 1f 02 0f 03 + 30: 17 00 00 00 auipc zero, 0 + 34: 01 17 + 36: 00 00 + 38: 00 01 + 3a: 98 00 + 3c: 00 00 + 3e: 01 05 + 40: 01 00 + 42: 05 02 + 44: f0 25 + 46: 00 80 + 48: 03 ae 05 01 lw t3, 16(a1) + 4c: 05 03 + 4e: 03 01 09 00 lb sp, 0(s2) + 52: 00 01 + 54: 03 02 09 00 lb tp, 0(s2) + 58: 00 01 + 5a: 03 00 09 00 lb zero, 0(s2) + 5e: 00 01 + 60: 03 00 09 00 lb zero, 0(s2) + 64: 00 01 + 66: 03 00 09 00 lb zero, 0(s2) + 6a: 00 01 + 6c: 03 00 09 00 lb zero, 0(s2) + 70: 00 01 + 72: 00 02 + 74: 04 03 + 76: 06 03 + 78: 00 09 + 7a: 08 00 + 7c: 01 00 + 7e: 02 04 + 80: 0e 06 + 82: 03 00 09 0c lb zero, 192(s2) + 86: 00 01 + 88: 00 02 + 8a: 04 0e + 8c: 03 00 09 00 lb zero, 0(s2) + 90: 00 01 + 92: 00 02 + 94: 04 0e + 96: 03 02 09 00 lb tp, 0(s2) + 9a: 00 01 + 9c: 00 02 + 9e: 04 0e + a0: 06 03 + a2: 7e 09 + a4: 00 00 + a6: 01 05 + a8: 01 00 + aa: 02 04 + ac: 0e 03 + ae: 03 09 1c 00 lb s2, 1(s8) + b2: 01 05 + b4: 03 00 02 04 lb zero, 64(tp) + b8: 04 03 + ba: 7d 09 + bc: 08 00 + be: 01 03 + c0: 00 09 + c2: 0c 00 + c4: 01 09 + c6: 08 00 + c8: 00 01 + ca: 01 3b + cc: 00 00 + ce: 00 05 + d0: 00 04 + d2: 00 33 + d4: 00 00 + d6: 00 01 + d8: 01 01 + da: fb 0e 0d 00 + de: 01 01 + e0: 01 01 + e2: 00 00 + e4: 00 01 + e6: 00 00 + e8: 01 01 + ea: 01 1f + ec: 02 21 + ee: 00 00 + f0: 00 81 + f2: 00 00 + f4: 00 02 + f6: 01 1f + f8: 02 0f + fa: 03 17 00 00 lh a4, 0(zero) + fe: 00 01 + 100: 98 00 + 102: 00 00 + 104: 01 17 + 106: 00 00 + 108: 00 01 + +Disassembly of section .debug_frame: + +00000000 <.debug_frame>: + 0: 0c 00 + 2: 00 00 + 4: ff ff ff ff + 8: 03 00 01 7c lb zero, 1984(sp) + c: 01 0d + e: 02 00 + 10: 0c 00 + 12: 00 00 + 14: 00 00 + 16: 00 00 + 18: f0 25 + 1a: 00 80 + 1c: 4c 00 + 1e: 00 00 + +Disassembly of section .debug_str: + +00000000 <.debug_str>: + 0: 6c 6f + 2: 6e 67 + 4: 20 6c + 6: 6f 6e 67 20 jal t3, 0x7620c <.debug_info+0x7620c> + a: 69 6e + c: 74 00 + e: 5f 5f 63 6c + 12: 7a 73 + 14: 69 32 + 16: 00 63 + 18: 6f 6d 70 6c jal s10, 0x6ede <.debug_info+0x6ede> + 1c: 65 78 + 1e: 20 64 + 20: 6f 75 62 6c jal a0, 0x276e6 <.debug_info+0x276e6> + 24: 65 00 + 26: 5f 5f 78 72 + 2a: 00 47 + 2c: 4e 55 + 2e: 20 43 + 30: 31 37 + 32: 20 31 + 34: 32 2e + 36: 32 2e + 38: 30 20 + 3a: 2d 6d + 3c: 63 6d 6f 64 bltu t5, t1, 0x696 <.debug_info+0x696> + 40: 65 6c + 42: 3d 6d + 44: 65 64 + 46: 61 6e + 48: 79 20 + 4a: 2d 6d + 4c: 63 6d 6f 64 bltu t5, t1, 0x6a6 <.debug_info+0x6a6> + 50: 65 6c + 52: 3d 6d + 54: 65 64 + 56: 61 6e + 58: 79 20 + 5a: 2d 6d + 5c: 74 75 + 5e: 6e 65 + 60: 3d 72 + 62: 6f 63 6b 65 jal t1, 0xb66b8 <.debug_info+0xb66b8> + 66: 74 20 + 68: 2d 6d + 6a: 61 62 + 6c: 69 3d + 6e: 69 6c + 70: 70 33 + 72: 32 66 + 74: 20 2d + 76: 6d 69 + 78: 73 61 2d 73 csrrsi sp, mhpmevent18h, 26 + 7c: 70 65 + 7e: 63 3d 32 30 + 82: 31 39 + 84: 31 32 + 86: 31 33 + 88: 20 2d + 8a: 6d 61 + 8c: 72 63 + 8e: 68 3d + 90: 72 76 + 92: 33 32 69 6d + 96: 66 5f + 98: 7a 69 + 9a: 63 73 72 20 bgeu tp, t2, 0x2a0 <.debug_info+0x2a0> + 9e: 2d 67 + a0: 20 2d + a2: 4f 73 20 2d + a6: 4f 32 20 2d + aa: 4f 73 20 2d + ae: 66 62 + b0: 75 69 + b2: 6c 64 + b4: 69 6e + b6: 67 2d 6c 69 + ba: 62 67 + bc: 63 63 20 2d bltu zero, s2, 0x382 <.debug_info+0x382> + c0: 66 6e + c2: 6f 2d 73 74 jal s10, 0x33008 <.debug_info+0x33008> + c6: 61 63 + c8: 6b 2d 70 72 + cc: 6f 74 65 63 jal s0, 0x57702 <.debug_info+0x57702> + d0: 74 6f + d2: 72 20 + d4: 2d 66 + d6: 76 69 + d8: 73 69 62 69 csrrsi s2, 1686, 4 + dc: 6c 69 + de: 74 79 + e0: 3d 68 + e2: 69 64 + e4: 64 65 + e6: 6e 00 + e8: 6c 6f + ea: 6e 67 + ec: 20 6c + ee: 6f 6e 67 20 jal t3, 0x762f4 <.debug_info+0x762f4> + f2: 75 6e + f4: 73 69 67 6e csrrsi s2, 1766, 14 + f8: 65 64 + fa: 20 69 + fc: 6e 74 + fe: 00 75 + 100: 6e 73 + 102: 69 67 + 104: 6e 65 + 106: 64 20 + 108: 63 68 61 72 bltu sp, t1, 0x838 <.debug_info+0x838> + 10c: 00 5f + 10e: 5f 63 6c 7a + 112: 5f 74 61 62 + 116: 00 63 + 118: 6f 6d 70 6c jal s10, 0x6fde <.debug_info+0x6fde> + 11c: 65 78 + 11e: 20 6c + 120: 6f 6e 67 20 jal t3, 0x76326 <.debug_info+0x76326> + 124: 64 6f + 126: 75 62 + 128: 6c 65 + 12a: 00 73 + 12c: 68 6f + 12e: 72 74 + 130: 20 75 + 132: 6e 73 + 134: 69 67 + 136: 6e 65 + 138: 64 20 + 13a: 69 6e + 13c: 74 00 + 13e: 63 6f 6d 70 bltu s10, t1, 0x85c <.debug_info+0x85c> + 142: 6c 65 + 144: 78 20 + 146: 66 6c + 148: 6f 61 74 00 jal sp, 0x4694e <.debug_info+0x4694e> + 14c: 55 51 + 14e: 49 74 + 150: 79 70 + 152: 65 00 + 154: 55 53 + 156: 49 74 + 158: 79 70 + 15a: 65 00 + 15c: 73 68 6f 72 csrrsi a6, mhpmevent6h, 30 + 160: 74 20 + 162: 69 6e + 164: 74 00 + +Disassembly of section .debug_loclists: + +00000000 <.debug_loclists>: + 0: 5e 00 + 2: 00 00 + 4: 05 00 + 6: 04 00 + 8: 00 00 + a: 00 00 + c: 07 f0 25 00 + 10: 80 10 + 12: 26 00 + 14: 80 01 + 16: 5a 07 + 18: 10 26 + 1a: 00 80 + 1c: 28 26 + 1e: 00 80 + 20: 04 a3 + 22: 01 5a + 24: 9f 07 28 26 + 28: 00 80 + 2a: 3c 26 + 2c: 00 80 + 2e: 01 5a + 30: 00 07 + 32: f0 25 + 34: 00 80 + 36: 10 26 + 38: 00 80 + 3a: 01 5a + 3c: 07 10 26 00 + 40: 80 28 + 42: 26 00 + 44: 80 04 + 46: a3 01 5a 9f sb s5, -1565(s4) + 4a: 07 28 26 00 flw fa6, 2(a2) + 4e: 80 3c + 50: 26 00 + 52: 80 01 + 54: 5a 00 + 56: 07 04 26 00 + 5a: 80 18 + 5c: 26 00 + 5e: 80 01 + 60: 5f + 61: 00 + +Disassembly of section .debug_rnglists: + +00000000 <.debug_rnglists>: + 0: 24 00 + 2: 00 00 + 4: 05 00 + 6: 04 00 + 8: 00 00 + a: 00 00 + c: 06 f0 + e: 25 00 + 10: 80 04 + 12: 26 00 + 14: 80 06 + 16: 04 26 + 18: 00 80 + 1a: 20 26 + 1c: 00 80 + 1e: 06 28 + 20: 26 00 + 22: 80 3c + 24: 26 00 + 26: 80 00 + +Disassembly of section .debug_line_str: + +00000000 <.debug_line_str>: + 0: 2e 2e + 2: 2f 2e 2e 2f + 6: 2e 2e + 8: 2f 2e 2e 2f + c: 67 63 63 2f + 10: 6c 69 + 12: 62 67 + 14: 63 63 2f 6c bltu t5, sp, 0x6da <.debug_info+0x6da> + 18: 69 62 + 1a: 67 63 63 32 + 1e: 2e 63 + 20: 00 2f + 22: 68 6f + 24: 6d 65 + 26: 2f 62 6c 61 + 2a: 69 73 + 2c: 65 2f + 2e: 64 65 + 30: 76 2f + 32: 72 69 + 34: 73 63 76 2d csrrsi t1, 727, 12 + 38: 67 6e 75 2d + 3c: 74 6f + 3e: 6f 6c 63 68 jal s8, 0x366c4 <.debug_info+0x366c4> + 42: 61 69 + 44: 6e 2f + 46: 62 75 + 48: 69 6c + 4a: 64 33 + 4c: 32 2f + 4e: 62 75 + 50: 69 6c + 52: 64 2d + 54: 67 63 63 2d + 58: 6e 65 + 5a: 77 6c 69 62 + 5e: 2d 73 + 60: 74 61 + 62: 67 65 32 2f + 66: 72 69 + 68: 73 63 76 33 csrrsi t1, mhpmevent23, 12 + 6c: 32 2d + 6e: 75 6e + 70: 6b 6e 6f 77 + 74: 6e 2d + 76: 65 6c + 78: 66 2f + 7a: 6c 69 + 7c: 62 67 + 7e: 63 63 00 2e bltu zero, zero, 0x364 <.debug_info+0x364> + 82: 2e 2f + 84: 2e 2e + 86: 2f 2e 2e 2f + 8a: 2e 2e + 8c: 2f 67 63 63 + 90: 2f 6c 69 62 + 94: 67 63 63 00 + 98: 6c 69 + 9a: 62 67 + 9c: 63 63 32 2e bltu tp, gp, 0x382 <.debug_info+0x382> + a0: 68 00 + +Disassembly of section .symtab: + +00000000 <.symtab>: + ... + 14: 00 00 + 16: 00 80 + 18: 00 00 + 1a: 00 00 + 1c: 03 00 01 00 lb zero, 0(sp) + 20: 00 00 + 22: 00 00 + 24: 84 00 + 26: 00 80 + 28: 00 00 + 2a: 00 00 + 2c: 03 00 02 00 lb zero, 0(tp) + 30: 00 00 + 32: 00 00 + 34: 3c 26 + 36: 00 80 + 38: 00 00 + 3a: 00 00 + 3c: 03 00 03 00 lb zero, 0(t1) + 40: 00 00 + 42: 00 00 + 44: 14 3b + 46: 00 80 + 48: 00 00 + 4a: 00 00 + 4c: 03 00 04 00 lb zero, 0(s0) + 50: 00 00 + 52: 00 00 + 54: 18 3b + 56: 00 80 + 58: 00 00 + 5a: 00 00 + 5c: 03 00 05 00 lb zero, 0(a0) + 60: 00 00 + 62: 00 00 + 64: 40 3f + 66: 00 80 + 68: 00 00 + 6a: 00 00 + 6c: 03 00 06 00 lb zero, 0(a2) + 70: 00 00 + 72: 00 00 + 74: cc 3f + 76: 00 80 + 78: 00 00 + 7a: 00 00 + 7c: 03 00 07 00 lb zero, 0(a4) + ... + 8c: 03 00 08 00 lb zero, 0(a6) + ... + 9c: 03 00 09 00 lb zero, 0(s2) + ... + ac: 03 00 0a 00 lb zero, 0(s4) + ... + bc: 03 00 0b 00 lb zero, 0(s6) + ... + cc: 03 00 0c 00 lb zero, 0(s8) + ... + dc: 03 00 0d 00 lb zero, 0(s10) + ... + ec: 03 00 0e 00 lb zero, 0(t3) + ... + fc: 03 00 0f 00 lb zero, 0(t5) + ... + 10c: 03 00 10 00 lb zero, 1(zero) + ... + 11c: 03 00 11 00 lb zero, 1(sp) + ... + 12c: 03 00 12 00 lb zero, 1(tp) + 130: 01 00 + ... + 13a: 00 00 + 13c: 04 00 + 13e: f1 ff + 140: 0e 00 + 142: 00 00 + 144: 00 00 + 146: 00 80 + 148: 00 00 + 14a: 00 00 + 14c: 00 00 + 14e: 01 00 + 150: 3a 00 + 152: 00 00 + 154: d8 08 + 156: 00 80 + 158: 00 00 + 15a: 00 00 + 15c: 02 00 + 15e: 02 00 + 160: 48 00 + 162: 00 00 + 164: a4 08 + 166: 00 80 + 168: 00 00 + 16a: 00 00 + 16c: 02 00 + 16e: 02 00 + 170: 52 00 + 172: 00 00 + 174: ec 08 + 176: 00 80 + 178: 00 00 + 17a: 00 00 + 17c: 02 00 + 17e: 02 00 + 180: 0e 00 + 182: 00 00 + 184: 94 08 + 186: 00 80 + 188: 00 00 + 18a: 00 00 + 18c: 00 00 + 18e: 02 00 + 190: e6 01 + ... + 19a: 00 00 + 19c: 04 00 + 19e: f1 ff + 1a0: 5f 00 00 00 + 1a4: 84 00 + 1a6: 00 80 + 1a8: 00 00 + 1aa: 00 00 + 1ac: 00 00 + 1ae: 02 00 + 1b0: 86 00 + ... + 1ba: 00 00 + 1bc: 04 00 + 1be: f1 ff + 1c0: 96 00 + 1c2: 00 00 + 1c4: b8 00 + 1c6: 00 80 + 1c8: 18 00 + 1ca: 00 00 + 1cc: 02 00 + 1ce: 02 00 + 1d0: 5f 00 00 00 + 1d4: b8 00 + 1d6: 00 80 + 1d8: 00 00 + 1da: 00 00 + 1dc: 00 00 + 1de: 02 00 + 1e0: 5f 00 00 00 + 1e4: cc 24 + 1e6: 00 80 + 1e8: 00 00 + 1ea: 00 00 + 1ec: 00 00 + 1ee: 02 00 + 1f0: a4 00 + ... + 1fa: 00 00 + 1fc: 04 00 + 1fe: f1 ff + 200: c0 00 + ... + 20a: 00 00 + 20c: 04 00 + 20e: f1 ff + 210: cc 00 + 212: 00 00 + 214: fc 00 + 216: 00 80 + 218: 24 00 + 21a: 00 00 + 21c: 02 00 + 21e: 02 00 + 220: d8 00 + 222: 00 00 + 224: 20 01 + 226: 00 80 + 228: 24 00 + 22a: 00 00 + 22c: 02 00 + 22e: 02 00 + 230: e4 00 + ... + 23a: 00 00 + 23c: 04 00 + 23e: f1 ff + 240: 0e 00 + 242: 00 00 + 244: 10 09 + 246: 00 80 + 248: 00 00 + 24a: 00 00 + 24c: 00 00 + 24e: 02 00 + 250: 0e 00 + 252: 00 00 + 254: 54 09 + 256: 00 80 + 258: 00 00 + 25a: 00 00 + 25c: 00 00 + 25e: 02 00 + 260: 0e 00 + 262: 00 00 + 264: e8 09 + 266: 00 80 + 268: 00 00 + 26a: 00 00 + 26c: 00 00 + 26e: 02 00 + 270: f2 00 + ... + 27a: 00 00 + 27c: 04 00 + 27e: f1 ff + 280: fd 00 + 282: 00 00 + 284: 44 0a + 286: 00 80 + 288: 5c 01 + 28a: 00 00 + 28c: 02 00 + 28e: 02 00 + 290: 0e 00 + 292: 00 00 + 294: 44 0a + 296: 00 80 + 298: 00 00 + 29a: 00 00 + 29c: 00 00 + 29e: 02 00 + 2a0: 13 01 00 00 li sp, 0 + 2a4: a0 0b + 2a6: 00 80 + 2a8: 84 00 + 2aa: 00 00 + 2ac: 02 00 + 2ae: 02 00 + 2b0: 0e 00 + 2b2: 00 00 + 2b4: a0 0b + 2b6: 00 80 + 2b8: 00 00 + 2ba: 00 00 + 2bc: 00 00 + 2be: 02 00 + 2c0: 29 01 + 2c2: 00 00 + 2c4: 24 0c + 2c6: 00 80 + 2c8: 24 00 + 2ca: 00 00 + 2cc: 02 00 + 2ce: 02 00 + 2d0: 0e 00 + 2d2: 00 00 + 2d4: 24 0c + 2d6: 00 80 + 2d8: 00 00 + 2da: 00 00 + 2dc: 00 00 + 2de: 02 00 + 2e0: 0e 00 + 2e2: 00 00 + 2e4: 48 0c + 2e6: 00 80 + 2e8: 00 00 + 2ea: 00 00 + 2ec: 00 00 + 2ee: 02 00 + 2f0: 3d 01 + ... + 2fa: 00 00 + 2fc: 04 00 + 2fe: f1 ff + 300: 0e 00 + 302: 00 00 + 304: 40 0e + 306: 00 80 + 308: 00 00 + 30a: 00 00 + 30c: 00 00 + 30e: 02 00 + 310: 47 01 00 00 fmsub.s ft2, ft0, ft0, ft0, rne + ... + 31c: 04 00 + 31e: f1 ff + 320: 5f 00 00 00 + 324: 58 10 + 326: 00 80 + 328: 00 00 + 32a: 00 00 + 32c: 00 00 + 32e: 02 00 + 330: 50 01 + ... + 33a: 00 00 + 33c: 04 00 + 33e: f1 ff + 340: 5f 00 00 00 + 344: f8 10 + 346: 00 80 + 348: 00 00 + 34a: 00 00 + 34c: 00 00 + 34e: 02 00 + 350: 59 01 + ... + 35a: 00 00 + 35c: 04 00 + 35e: f1 ff + 360: 5f 00 00 00 + 364: 9c 11 + 366: 00 80 + 368: 00 00 + 36a: 00 00 + 36c: 00 00 + 36e: 02 00 + 370: 67 01 00 00 jalr sp, zero + 374: c4 26 + 376: 00 80 + 378: 18 03 + 37a: 00 00 + 37c: 01 00 + 37e: 03 00 73 01 lb zero, 23(t1) + 382: 00 00 + 384: 44 26 + 386: 00 80 + 388: 80 00 + 38a: 00 00 + 38c: 01 00 + 38e: 03 00 7c 01 lb zero, 23(s8) + ... + 39a: 00 00 + 39c: 04 00 + 39e: f1 ff + 3a0: 5f 00 00 00 + 3a4: b8 14 + 3a6: 00 80 + 3a8: 00 00 + 3aa: 00 00 + 3ac: 00 00 + 3ae: 02 00 + 3b0: 85 01 + ... + 3ba: 00 00 + 3bc: 04 00 + 3be: f1 ff + 3c0: 5f 00 00 00 + 3c4: 04 16 + 3c6: 00 80 + 3c8: 00 00 + 3ca: 00 00 + 3cc: 00 00 + 3ce: 02 00 + 3d0: 93 01 00 00 li gp, 0 + 3d4: 08 2a + 3d6: 00 80 + 3d8: 0c 00 + 3da: 00 00 + 3dc: 01 00 + 3de: 03 00 9b 01 lb zero, 25(s6) + 3e2: 00 00 + 3e4: dc 29 + 3e6: 00 80 + 3e8: 2c 00 + 3ea: 00 00 + 3ec: 01 00 + 3ee: 03 00 a0 01 lb zero, 26(zero) + ... + 3fa: 00 00 + 3fc: 04 00 + 3fe: f1 ff + 400: 5f 00 00 00 + 404: f4 1e + 406: 00 80 + 408: 00 00 + 40a: 00 00 + 40c: 00 00 + 40e: 02 00 + 410: a9 01 + ... + 41a: 00 00 + 41c: 04 00 + 41e: f1 ff + 420: 5f 00 00 00 + 424: a0 1f + 426: 00 80 + 428: 00 00 + 42a: 00 00 + 42c: 00 00 + 42e: 02 00 + 430: b3 01 00 00 add gp, zero, zero + ... + 43c: 04 00 + 43e: f1 ff + 440: 5f 00 00 00 + 444: a8 1f + 446: 00 80 + 448: 00 00 + 44a: 00 00 + 44c: 00 00 + 44e: 02 00 + 450: be 01 + ... + 45a: 00 00 + 45c: 04 00 + 45e: f1 ff + 460: 5f 00 00 00 + 464: 74 20 + 466: 00 80 + 468: 00 00 + 46a: 00 00 + 46c: 00 00 + 46e: 02 00 + 470: e4 01 + ... + 47a: 00 00 + 47c: 04 00 + 47e: f1 ff + 480: 5f 00 00 00 + 484: 9c 21 + 486: 00 80 + 488: 00 00 + 48a: 00 00 + 48c: 00 00 + 48e: 02 00 + 490: ca 01 + ... + 49a: 00 00 + 49c: 04 00 + 49e: f1 ff + 4a0: 5f 00 00 00 + 4a4: b0 21 + 4a6: 00 80 + 4a8: 00 00 + 4aa: 00 00 + 4ac: 00 00 + 4ae: 02 00 + 4b0: d3 01 00 00 fadd.s ft3, ft0, ft0, rne + ... + 4bc: 04 00 + 4be: f1 ff + 4c0: 5f 00 00 00 + 4c4: 54 23 + 4c6: 00 80 + 4c8: 00 00 + 4ca: 00 00 + 4cc: 00 00 + 4ce: 02 00 + 4d0: e2 01 + ... + 4da: 00 00 + 4dc: 04 00 + 4de: f1 ff + 4e0: 5f 00 00 00 + 4e4: 30 24 + 4e6: 00 80 + 4e8: 00 00 + 4ea: 00 00 + 4ec: 00 00 + 4ee: 02 00 + 4f0: ed 01 + ... + 4fa: 00 00 + 4fc: 04 00 + 4fe: f1 ff + 500: 5f 00 00 00 + 504: f0 25 + 506: 00 80 + 508: 00 00 + 50a: 00 00 + 50c: 00 00 + 50e: 02 00 + 510: ed 01 + ... + 51a: 00 00 + 51c: 04 00 + 51e: f1 ff + 520: f7 01 00 00 + ... + 52c: 04 00 + 52e: f1 ff + 530: 00 02 + 532: 00 00 + 534: 18 3b + 536: 00 80 + 538: 28 04 + 53a: 00 00 + 53c: 01 00 + 53e: 05 00 + ... + 54c: 04 00 + 54e: f1 ff + 550: 0c 02 + 552: 00 00 + 554: 18 3b + 556: 00 80 + 558: 00 00 + 55a: 00 00 + 55c: 00 00 + 55e: 05 00 + 560: 1d 02 + 562: 00 00 + 564: 14 3b + 566: 00 80 + 568: 00 00 + 56a: 00 00 + 56c: 00 00 + 56e: 04 00 + 570: 2a 02 + 572: 00 00 + 574: 18 3b + 576: 00 80 + 578: 00 00 + 57a: 00 00 + 57c: 00 00 + 57e: 05 00 + 580: 3d 02 + 582: 00 00 + 584: 14 3b + 586: 00 80 + 588: 00 00 + 58a: 00 00 + 58c: 00 00 + 58e: 04 00 + 590: 4b 02 00 00 fnmsub.s ft4, ft0, ft0, ft0, rne + 594: 18 3b + 596: 00 80 + 598: 00 00 + 59a: 00 00 + 59c: 00 00 + 59e: 04 00 + 5a0: 5c 02 + ... + 5ae: f1 ff + 5b0: 6a 02 + 5b2: 00 00 + 5b4: 14 3b + 5b6: 00 80 + 5b8: 00 00 + 5ba: 00 00 + 5bc: 00 00 + 5be: 04 00 + 5c0: 7e 02 + 5c2: 00 00 + 5c4: 14 3b + 5c6: 00 80 + 5c8: 00 00 + 5ca: 00 00 + 5cc: 00 00 + 5ce: 04 00 + 5d0: 89 02 + 5d2: 00 00 + 5d4: 14 3b + 5d6: 00 80 + 5d8: 00 00 + 5da: 00 00 + 5dc: 00 00 + 5de: 04 00 + 5e0: 9c 02 + 5e2: 00 00 + 5e4: 14 3b + 5e6: 00 80 + 5e8: 00 00 + 5ea: 00 00 + 5ec: 00 00 + 5ee: 04 00 + 5f0: b2 02 + 5f2: 00 00 + 5f4: 9c 11 + 5f6: 00 80 + 5f8: 1c 03 + 5fa: 00 00 + 5fc: 12 00 + 5fe: 02 00 + 600: c6 02 + 602: 00 00 + 604: cc 3f + 606: 00 80 + 608: 00 10 + 60a: 00 00 + 60c: 11 00 + 60e: 07 00 d4 02 + 612: 00 00 + 614: 40 3f + 616: 00 80 + 618: 00 00 + 61a: 00 00 + 61c: 10 00 + 61e: 06 00 + 620: e4 02 + 622: 00 00 + 624: 00 09 + 626: 00 80 + 628: 00 00 + 62a: 00 00 + 62c: 12 00 + 62e: 02 00 + 630: f3 02 00 00 + 634: b0 21 + 636: 00 80 + 638: a4 01 + 63a: 00 00 + 63c: 12 00 + 63e: 02 00 + 640: fa 02 + 642: 00 00 + 644: 40 47 + 646: 00 80 + 648: 00 00 + 64a: 00 00 + 64c: 10 00 + 64e: f1 ff + 650: 0b 03 00 00 + 654: 44 01 + 656: 00 80 + 658: 50 07 + 65a: 00 00 + 65c: 12 00 + 65e: 02 00 + 660: 2d 03 + 662: 00 00 + 664: a0 1f + 666: 00 80 + 668: 08 00 + 66a: 00 00 + 66c: 12 00 + 66e: 02 00 + 670: 33 03 00 00 add t1, zero, zero + 674: c8 3f + 676: 00 80 + 678: 04 00 + 67a: 00 00 + 67c: 11 00 + 67e: 06 00 + 680: 46 03 + 682: 00 00 + 684: 54 09 + 686: 00 80 + 688: 94 00 + 68a: 00 00 + 68c: 12 00 + 68e: 02 00 + 690: 58 03 + 692: 00 00 + 694: f4 1e + 696: 00 80 + 698: ac 00 + 69a: 00 00 + 69c: 12 00 + 69e: 02 00 + 6a0: 66 03 + 6a2: 00 00 + 6a4: 10 09 + 6a6: 00 80 + 6a8: 44 00 + 6aa: 00 00 + 6ac: 12 00 + 6ae: 02 00 + 6b0: d3 00 00 00 fadd.s ft1, ft0, ft0, rne + 6b4: 58 10 + 6b6: 00 80 + 6b8: a0 00 + 6ba: 00 00 + 6bc: 12 00 + 6be: 02 00 + 6c0: 71 03 + 6c2: 00 00 + 6c4: e8 09 + 6c6: 00 80 + 6c8: 5c 00 + 6ca: 00 00 + 6cc: 12 00 + 6ce: 02 00 + 6d0: 83 03 00 00 lb t2, 0(zero) + 6d4: b8 14 + 6d6: 00 80 + 6d8: 4c 01 + 6da: 00 00 + 6dc: 12 00 + 6de: 02 00 + 6e0: 91 03 + ... + 6ea: 00 00 + 6ec: 10 00 + 6ee: f1 ff + 6f0: 9e 03 + ... + 6fa: 00 00 + 6fc: 10 00 + 6fe: f1 ff + 700: aa 03 + 702: 00 00 + 704: f0 25 + 706: 00 80 + 708: 4c 00 + 70a: 00 00 + 70c: 12 02 + 70e: 02 00 + 710: b3 03 00 00 add t2, zero, zero + 714: cc 24 + 716: 00 80 + 718: 24 01 + 71a: 00 00 + 71c: 12 00 + 71e: 02 00 + 720: 44 02 + 722: 00 00 + 724: 00 00 + 726: 00 80 + 728: 84 00 + 72a: 00 00 + 72c: 12 00 + 72e: 01 00 + 730: c4 03 + 732: 00 00 + 734: 30 24 + 736: 00 80 + 738: 9c 00 + 73a: 00 00 + 73c: 12 00 + 73e: 02 00 + 740: d8 03 + 742: 00 00 + 744: cc 4f + 746: 00 80 + 748: 00 00 + 74a: 00 00 + 74c: 10 00 + 74e: 07 00 e4 03 + 752: 00 00 + 754: 74 20 + 756: 00 80 + 758: 28 01 + 75a: 00 00 + 75c: 12 00 + 75e: 02 00 + 760: ec 03 + 762: 00 00 + 764: cc 3f + 766: 00 80 + 768: 00 00 + 76a: 00 00 + 76c: 10 00 + 76e: 07 00 f8 03 + 772: 00 00 + 774: 54 23 + 776: 00 80 + 778: dc 00 + 77a: 00 00 + 77c: 12 00 + 77e: 02 00 + 780: ff 03 00 00 + 784: d0 00 + 786: 00 80 + 788: 2c 00 + 78a: 00 00 + 78c: 12 00 + 78e: 02 00 + 790: 04 04 + 792: 00 00 + 794: 14 2a + 796: 00 80 + 798: 00 01 + 79a: 00 00 + 79c: 11 02 + 79e: 03 00 0e 04 lb zero, 64(t3) + 7a2: 00 00 + 7a4: 9c 21 + 7a6: 00 80 + 7a8: 14 00 + 7aa: 00 00 + 7ac: 12 00 + 7ae: 02 00 + 7b0: 15 04 + ... + 7ba: 00 00 + 7bc: 10 00 + 7be: f1 ff + 7c0: 28 04 + 7c2: 00 00 + 7c4: 00 00 + 7c6: 00 80 + 7c8: 00 00 + 7ca: 00 00 + 7cc: 10 00 + 7ce: f1 ff + 7d0: df 00 00 00 + 7d4: f8 10 + 7d6: 00 80 + 7d8: a4 00 + 7da: 00 00 + 7dc: 12 00 + 7de: 02 00 + 7e0: 35 04 + 7e2: 00 00 + 7e4: 18 3b + 7e6: 00 80 + 7e8: 00 00 + 7ea: 00 00 + 7ec: 10 00 + 7ee: 05 00 + 7f0: 44 04 + 7f2: 00 00 + 7f4: cc 3f + 7f6: 00 80 + 7f8: 00 00 + 7fa: 00 00 + 7fc: 10 00 + 7fe: 06 00 + 800: 84 02 + 802: 00 00 + 804: cc 4f + 806: 00 80 + 808: 00 00 + 80a: 00 00 + 80c: 10 00 + 80e: 07 00 59 04 + 812: 00 00 + 814: 84 00 + 816: 00 80 + 818: 34 00 + 81a: 00 00 + 81c: 12 00 + 81e: 02 00 + 820: 4b 04 00 00 fnmsub.s fs0, ft0, ft0, ft0, rne + 824: 40 0e + 826: 00 80 + 828: 18 02 + 82a: 00 00 + 82c: 12 00 + 82e: 02 00 + 830: 58 04 + 832: 00 00 + 834: 94 08 + 836: 00 80 + 838: 00 00 + 83a: 00 00 + 83c: 12 00 + 83e: 02 00 + 840: 5e 04 + 842: 00 00 + 844: 04 16 + 846: 00 80 + 848: f0 08 + 84a: 00 00 + 84c: 12 00 + 84e: 02 00 + 850: 71 04 + 852: 00 00 + 854: a8 1f + 856: 00 80 + 858: cc 00 + 85a: 00 00 + 85c: 12 00 + 85e: 02 00 + 860: 78 04 + 862: 00 00 + 864: 48 0c + 866: 00 80 + 868: f8 01 + 86a: 00 00 + 86c: 12 00 + 86e: 02 00 + +Disassembly of section .strtab: + +00000000 <.strtab>: + 0: 00 76 + 2: 78 5f + 4: 73 74 61 72 csrrci s0, mhpmevent6h, 2 + 8: 74 2e + a: 53 2e 6f 00 fadd.s ft8, ft10, ft6, rdn + e: 24 78 + 10: 72 76 + 12: 33 32 69 32 + 16: 70 31 + 18: 5f 6d 32 70 + 1c: 30 5f + 1e: 61 32 + 20: 70 31 + 22: 5f 66 32 70 + 26: 32 5f + 28: 7a 69 + 2a: 63 73 72 32 bgeu tp, t2, 0x350 <.symtab+0x350> + 2e: 70 30 + 30: 5f 7a 6d 6d + 34: 75 6c + 36: 31 70 + 38: 30 00 + 3a: 69 6e + 3c: 69 74 + 3e: 5f 72 65 67 + 42: 73 5f 61 6c csrrwi t5, 1734, 2 + 46: 6c 00 + 48: 69 6e + 4a: 69 74 + 4c: 5f 72 65 67 + 50: 73 00 69 6e + 54: 69 74 + 56: 5f 74 6c 73 + 5a: 5f 61 6c 6c + 5e: 00 24 + 60: 78 72 + 62: 76 33 + 64: 32 69 + 66: 32 70 + 68: 31 5f + 6a: 6d 32 + 6c: 70 30 + 6e: 5f 66 32 70 + 72: 32 5f + 74: 7a 69 + 76: 63 73 72 32 bgeu tp, t2, 0x39c <.symtab+0x39c> + 7a: 70 30 + 7c: 5f 7a 6d 6d + 80: 75 6c + 82: 31 70 + 84: 30 00 + 86: 5f 5f 63 61 + 8a: 6c 6c + 8c: 5f 61 74 65 + 90: 78 69 + 92: 74 2e + 94: 63 00 72 65 beq tp, s7, 0x6d4 <.symtab+0x6d4> + 98: 67 69 73 74 + 9c: 65 72 + 9e: 5f 66 69 6e + a2: 69 00 + a4: 70 6f + a6: 63 6c 5f 76 bltu t5, t0, 0x81e <.symtab+0x81e> + aa: 6f 72 74 65 jal tp, 0x47f00 <.symtab+0x47f00> + ae: 78 5f + b0: 6b 65 72 6e + b4: 65 6c + b6: 5f 33 69 37 + ba: 4d 30 + bc: 62 2e + be: 63 00 70 61 beq zero, s7, 0x6be <.symtab+0x6be> + c2: 72 61 + c4: 6c 6c + c6: 65 6c + c8: 5f 62 63 00 + cc: 5f 5a 37 5f + d0: 63 6c 5f 63 bltu t5, s5, 0x708 <.symtab+0x708> + d4: 6f 73 66 00 jal t1, 0x670da <.symtab+0x670da> + d8: 5f 5a 37 5f + dc: 63 6c 5f 73 bltu t5, s5, 0x814 <.symtab+0x814> + e0: 69 6e + e2: 66 00 + e4: 76 78 + e6: 5f 73 79 73 + ea: 63 61 6c 6c bltu s8, t1, 0x7ac <.symtab+0x7ac> + ee: 73 2e 63 00 csrrs t3, 6, t1 + f2: 76 78 + f4: 5f 73 70 61 + f8: 77 6e 2e 63 + fc: 00 73 + fe: 70 61 + 100: 77 6e 5f 6b + 104: 65 72 + 106: 6e 65 + 108: 6c 5f + 10a: 61 6c + 10c: 6c 5f + 10e: 73 74 75 62 csrrci s0, 1575, 10 + 112: 00 73 + 114: 70 61 + 116: 77 6e 5f 6b + 11a: 65 72 + 11c: 6e 65 + 11e: 6c 5f + 120: 72 65 + 122: 6d 5f + 124: 73 74 75 62 csrrci s0, 1575, 10 + 128: 00 73 + 12a: 70 61 + 12c: 77 6e 5f 6b + 130: 65 72 + 132: 6e 65 + 134: 6c 5f + 136: 61 6c + 138: 6c 5f + 13a: 63 62 00 76 bltu zero, zero, 0x89e <.symtab+0x89e> + 13e: 78 5f + 140: 70 65 + 142: 72 66 + 144: 2e 63 + 146: 00 73 + 148: 66 5f + 14a: 63 6f 73 2e bltu t1, t2, 0x448 <.symtab+0x448> + 14e: 63 00 73 66 beq t1, t2, 0x7ae <.symtab+0x7ae> + 152: 5f 73 69 6e + 156: 2e 63 + 158: 00 65 + 15a: 66 5f + 15c: 72 65 + 15e: 6d 5f + 160: 70 69 + 162: 6f 32 2e 63 jal tp, 0xe3794 <.symtab+0xe3794> + 166: 00 74 + 168: 77 6f 5f 6f + 16c: 76 65 + 16e: 72 5f + 170: 70 69 + 172: 00 6e + 174: 70 69 + 176: 6f 32 5f 68 jal tp, 0xf3ffa <.symtab+0xf3ffa> + 17a: 77 00 6b 66 + 17e: 5f 63 6f 73 + 182: 2e 63 + 184: 00 6b + 186: 66 5f + 188: 72 65 + 18a: 6d 5f + 18c: 70 69 + 18e: 6f 32 2e 63 jal tp, 0xe37c0 <.symtab+0xe37c0> + 192: 00 69 + 194: 6e 69 + 196: 74 5f + 198: 6a 6b + 19a: 00 50 + 19c: 49 6f + 19e: 32 00 + 1a0: 6b 66 5f 73 + 1a4: 69 6e + 1a6: 2e 63 + 1a8: 00 73 + 1aa: 66 5f + 1ac: 66 61 + 1ae: 62 73 + 1b0: 2e 63 + 1b2: 00 73 + 1b4: 66 5f + 1b6: 66 6c + 1b8: 6f 6f 72 2e jal t5, 0x26c9e <.symtab+0x26c9e> + 1bc: 63 00 73 66 beq t1, t2, 0x81c <.symtab+0x81c> + 1c0: 5f 73 63 61 + 1c4: 6c 62 + 1c6: 6e 2e + 1c8: 63 00 6d 65 beq s10, s6, 0x808 <.symtab+0x808> + 1cc: 6d 63 + 1ce: 70 79 + 1d0: 2e 63 + 1d2: 00 6c + 1d4: 69 62 + 1d6: 5f 61 2d 6d + 1da: 65 6d + 1dc: 73 65 74 2e csrrsi a0, 743, 8 + 1e0: 6f 00 5f 5f j 0xf0fd4 <.symtab+0xf0fd4> + 1e4: 61 74 + 1e6: 65 78 + 1e8: 69 74 + 1ea: 2e 63 + 1ec: 00 6c + 1ee: 69 62 + 1f0: 67 63 63 32 + 1f4: 2e 63 + 1f6: 00 69 + 1f8: 6d 70 + 1fa: 75 72 + 1fc: 65 2e + 1fe: 63 00 69 6d beq s2, s6, 0x8be <.symtab+0x8be> + 202: 70 75 + 204: 72 65 + 206: 5f 64 61 74 + 20a: 61 00 + 20c: 5f 5f 66 69 + 210: 6e 69 + 212: 5f 61 72 72 + 216: 61 79 + 218: 5f 65 6e 64 + 21c: 00 5f + 21e: 5f 74 62 73 + 222: 73 5f 73 74 csrrwi t5, mseccfg, 6 + 226: 61 72 + 228: 74 00 + 22a: 5f 5f 66 69 + 22e: 6e 69 + 230: 5f 61 72 72 + 234: 61 79 + 236: 5f 73 74 61 + 23a: 72 74 + 23c: 00 5f + 23e: 5f 74 64 61 + 242: 74 61 + 244: 5f 73 74 61 + 248: 72 74 + 24a: 00 5f + 24c: 5f 69 6e 69 + 250: 74 5f + 252: 61 72 + 254: 72 61 + 256: 79 5f + 258: 65 6e + 25a: 64 00 + 25c: 5f 5f 74 62 + 260: 73 73 5f 6f csrrci t1, 1781, 30 + 264: 66 66 + 266: 73 65 74 00 csrrsi a0, 7, 8 + 26a: 5f 5f 70 72 + 26e: 65 69 + 270: 6e 69 + 272: 74 5f + 274: 61 72 + 276: 72 61 + 278: 79 5f + 27a: 65 6e + 27c: 64 00 + 27e: 5f 5f 74 62 + 282: 73 73 5f 65 csrrci t1, 1621, 30 + 286: 6e 64 + 288: 00 5f + 28a: 5f 69 6e 69 + 28e: 74 5f + 290: 61 72 + 292: 72 61 + 294: 79 5f + 296: 73 74 61 72 csrrci s0, mhpmevent6h, 2 + 29a: 74 00 + 29c: 5f 5f 70 72 + 2a0: 65 69 + 2a2: 6e 69 + 2a4: 74 5f + 2a6: 61 72 + 2a8: 72 61 + 2aa: 79 5f + 2ac: 73 74 61 72 csrrci s0, mhpmevent6h, 2 + 2b0: 74 00 + 2b2: 5f 5f 69 65 + 2b6: 65 65 + 2b8: 37 35 34 5f lui a0, 389955 + 2bc: 72 65 + 2be: 6d 5f + 2c0: 70 69 + 2c2: 6f 32 66 00 jal tp, 0x632c8 <.symtab+0x632c8> + 2c6: 67 5f 77 73 + 2ca: 70 61 + 2cc: 77 6e 5f 61 + 2d0: 72 67 + 2d2: 73 00 5f 5f + 2d6: 53 44 41 54 + 2da: 41 5f + 2dc: 42 45 + 2de: 47 49 4e 5f + 2e2: 5f 00 76 78 + 2e6: 5f 77 73 70 + 2ea: 61 77 + 2ec: 6e 5f + 2ee: 77 61 69 74 + 2f2: 00 6d + 2f4: 65 6d + 2f6: 63 70 79 00 bgeu s2, t2, 0x2f6 <.symtab+0x2f6> + 2fa: 5f 5f 67 6c + 2fe: 6f 62 61 6c jal tp, 0x169c4 <.symtab+0x169c4> + 302: 5f 70 6f 69 + 306: 6e 74 + 308: 65 72 + 30a: 00 5f + 30c: 70 6f + 30e: 63 6c 5f 6b bltu t5, s5, 0x9c6 <.symtab+0x9c6> + 312: 65 72 + 314: 6e 65 + 316: 6c 5f + 318: 66 66 + 31a: 74 5f + 31c: 72 61 + 31e: 64 69 + 320: 78 34 + 322: 5f 77 6f 72 + 326: 6b 67 72 6f + 32a: 75 70 + 32c: 00 66 + 32e: 61 62 + 330: 73 66 00 5f csrrsi a2, 1520, 0 + 334: 67 6c 6f 62 + 338: 61 6c + 33a: 5f 69 6d 70 + 33e: 75 72 + 340: 65 5f + 342: 70 74 + 344: 72 00 + 346: 5f 5f 6c 69 + 34a: 62 63 + 34c: 5f 69 6e 69 + 350: 74 5f + 352: 61 72 + 354: 72 61 + 356: 79 00 + 358: 5f 5f 6b 65 + 35c: 72 6e + 35e: 65 6c + 360: 5f 73 69 6e + 364: 66 00 + 366: 5f 5f 69 6e + 36a: 69 74 + 36c: 5f 74 6c 73 + 370: 00 5f + 372: 5f 6c 69 62 + 376: 63 5f 66 69 bge a2, s6, 0xa14 <.symtab+0xa14> + 37a: 6e 69 + 37c: 5f 61 72 72 + 380: 61 79 + 382: 00 5f + 384: 5f 6b 65 72 + 388: 6e 65 + 38a: 6c 5f + 38c: 63 6f 73 66 bltu t1, t2, 0xa0a <.symtab+0xa0a> + 390: 00 5f + 392: 5f 74 64 61 + 396: 74 61 + 398: 5f 73 69 7a + 39c: 65 00 + 39e: 5f 5f 74 62 + 3a2: 73 73 5f 73 csrrci t1, mhpmevent21h, 30 + 3a6: 69 7a + 3a8: 65 00 + 3aa: 5f 5f 63 6c + 3ae: 7a 73 + 3b0: 69 32 + 3b2: 00 5f + 3b4: 5f 63 61 6c + 3b8: 6c 5f + 3ba: 65 78 + 3bc: 69 74 + 3be: 70 72 + 3c0: 6f 63 73 00 jal t1, 0x36bc6 <.symtab+0x36bc6> + 3c4: 5f 5f 72 65 + 3c8: 67 69 73 74 + 3cc: 65 72 + 3ce: 5f 65 78 69 + 3d2: 74 70 + 3d4: 72 6f + 3d6: 63 00 5f 5f beq t5, s5, 0x9b6 <.symtab+0x9b6> + 3da: 42 53 + 3dc: 53 5f 45 4e + 3e0: 44 5f + 3e2: 5f 00 73 63 + 3e6: 61 6c + 3e8: 62 6e + 3ea: 66 00 + 3ec: 5f 5f 62 73 + 3f0: 73 5f 73 74 csrrwi t5, mseccfg, 6 + 3f4: 61 72 + 3f6: 74 00 + 3f8: 6d 65 + 3fa: 6d 73 + 3fc: 65 74 + 3fe: 00 6d + 400: 61 69 + 402: 6e 00 + 404: 5f 5f 63 6c + 408: 7a 5f + 40a: 74 61 + 40c: 62 00 + 40e: 61 74 + 410: 65 78 + 412: 69 74 + 414: 00 5f + 416: 5f 74 63 62 + 41a: 5f 61 6c 69 + 41e: 67 6e 65 64 + 422: 5f 73 69 7a + 426: 65 00 + 428: 53 54 41 52 + 42c: 54 55 + 42e: 50 5f + 430: 41 44 + 432: 44 52 + 434: 00 5f + 436: 5f 44 41 54 + 43a: 41 5f + 43c: 42 45 + 43e: 47 49 4e 5f + 442: 5f 00 5f 65 + 446: 64 61 + 448: 74 61 + 44a: 00 76 + 44c: 78 5f + 44e: 70 65 + 450: 72 66 + 452: 5f 64 75 6d + 456: 70 00 + 458: 5f 65 78 69 + 45c: 74 00 + 45e: 5f 5f 6b 65 + 462: 72 6e + 464: 65 6c + 466: 5f 72 65 6d + 46a: 5f 70 69 6f + 46e: 32 66 + 470: 00 66 + 472: 6c 6f + 474: 6f 72 66 00 jal tp, 0x6747a <.symtab+0x6747a> + 478: 76 78 + 47a: 5f 73 70 61 + 47e: 77 6e 5f 6b + 482: 65 72 + 484: 6e 65 + 486: 6c 00 + +Disassembly of section .shstrtab: + +00000000 <.shstrtab>: + 0: 00 2e + 2: 73 79 6d 74 csrrci s2, 1862, 26 + 6: 61 62 + 8: 00 2e + a: 73 74 72 74 csrrci s0, mseccfg, 4 + e: 61 62 + 10: 00 2e + 12: 73 68 73 74 csrrsi a6, mseccfg, 6 + 16: 72 74 + 18: 61 62 + 1a: 00 2e + 1c: 69 6e + 1e: 69 74 + 20: 00 2e + 22: 74 65 + 24: 78 74 + 26: 00 2e + 28: 72 6f + 2a: 64 61 + 2c: 74 61 + 2e: 00 2e + 30: 69 6e + 32: 69 74 + 34: 5f 61 72 72 + 38: 61 79 + 3a: 00 2e + 3c: 64 61 + 3e: 74 61 + 40: 00 2e + 42: 73 64 61 74 csrrsi s0, 1862, 2 + 46: 61 00 + 48: 2e 62 + 4a: 73 73 00 2e csrrci t1, 736, 0 + 4e: 63 6f 6d 6d bltu s10, s6, 0x72c <.symtab+0x72c> + 52: 65 6e + 54: 74 00 + 56: 2e 72 + 58: 69 73 + 5a: 63 76 2e 61 bgeu t3, s2, 0x666 <.symtab+0x666> + 5e: 74 74 + 60: 72 69 + 62: 62 75 + 64: 74 65 + 66: 73 00 2e 64 + 6a: 65 62 + 6c: 75 67 + 6e: 5f 61 72 61 + 72: 6e 67 + 74: 65 73 + 76: 00 2e + 78: 64 65 + 7a: 62 75 + 7c: 67 5f 69 6e + 80: 66 6f + 82: 00 2e + 84: 64 65 + 86: 62 75 + 88: 67 5f 61 62 + 8c: 62 72 + 8e: 65 76 + 90: 00 2e + 92: 64 65 + 94: 62 75 + 96: 67 5f 6c 69 + 9a: 6e 65 + 9c: 00 2e + 9e: 64 65 + a0: 62 75 + a2: 67 5f 66 72 + a6: 61 6d + a8: 65 00 + aa: 2e 64 + ac: 65 62 + ae: 75 67 + b0: 5f 73 74 72 + b4: 00 2e + b6: 64 65 + b8: 62 75 + ba: 67 5f 6c 6f + be: 63 6c 69 73 bltu s2, s6, 0x7f6 <.symtab+0x7f6> + c2: 74 73 + c4: 00 2e + c6: 64 65 + c8: 62 75 + ca: 67 5f 72 6e + ce: 67 6c 69 73 + d2: 74 73 + d4: 00 2e + d6: 64 65 + d8: 62 75 + da: 67 5f 6c 69 + de: 6e 65 + e0: 5f 73 74 72 + e4: 00 diff --git a/tests/opencl/fft/kernel.cl b/tests/opencl/fft/kernel.cl new file mode 100644 index 00000000..3e47282c --- /dev/null +++ b/tests/opencl/fft/kernel.cl @@ -0,0 +1,63 @@ +#include "common.h" + +__kernel void fft_radix4(__global float2* input, __global float2* output, const unsigned int N) { + int globalId = get_global_id(0); + int localId = get_local_id(0); + int groupId = get_group_id(0); + + // Allocate local memory to store intermediate results and twiddle factors + __local float2 localData[LOCAL_SIZE]; + __local float2 twiddleFactors[LOCAL_SIZE / 4]; + + // Calculate twiddle factors for this FFT stage and store in local memory + if (localId < LOCAL_SIZE / 4) { + float angle = -2 * M_PI * localId / LOCAL_SIZE; + twiddleFactors[localId] = (float2)(cos(angle), sin(angle)); + } + barrier(CLK_LOCAL_MEM_FENCE); + + // Calculate the offset for the data this work-group will process + int offset = groupId * LOCAL_SIZE; + + // Load a chunk of input into local memory for faster access + if (globalId < N) { + localData[localId] = input[globalId]; + } + barrier(CLK_LOCAL_MEM_FENCE); + + // Perform the Radix-4 FFT on the data chunk in local memory + for (unsigned int stride = 1; stride < LOCAL_SIZE; stride *= 4) { + int twiddleIndex = (localId / stride) % 4; + float2 twiddle = twiddleFactors[twiddleIndex * (LOCAL_SIZE / (4 * stride))]; + + // Load data + float2 data0 = localData[localId]; + float2 data1 = localData[localId + stride]; + float2 data2 = localData[localId + 2 * stride]; + float2 data3 = localData[localId + 3 * stride]; + + // Apply twiddle factors + data1 *= twiddle; + data2 *= twiddle * twiddle; + data3 *= twiddle * twiddle * twiddle; + + // Radix-4 butterfly operations + float2 t0 = data0 + data2; + float2 t1 = data0 - data2; + float2 t2 = data1 + data3; + float2 t3 = (data1 - data3) * (float2)(0, -1); + + // Store results + localData[localId] = t0 + t2; + localData[localId + stride] = t1 + t3; + localData[localId + 2 * stride] = t0 - t2; + localData[localId + 3 * stride] = t1 - t3; + + barrier(CLK_LOCAL_MEM_FENCE); + } + + // Write the results back to global memory + if (globalId < N) { + output[globalId] = localData[localId]; + } +} diff --git a/tests/opencl/fft/kernel.pocl b/tests/opencl/fft/kernel.pocl new file mode 100644 index 0000000000000000000000000000000000000000..0923f2cd6835a2c775e4c5fdb2d8d384415153fb GIT binary patch literal 74401 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 H05JRy;4_00 literal 0 HcmV?d00001 diff --git a/tests/opencl/sgemm2/main.cc b/tests/opencl/fft/main.cc similarity index 61% rename from tests/opencl/sgemm2/main.cc rename to tests/opencl/fft/main.cc index 21ec3a54..b10b225a 100644 --- a/tests/opencl/sgemm2/main.cc +++ b/tests/opencl/fft/main.cc @@ -7,12 +7,31 @@ #include #include #include +#include +#include "common.h" -#define LOCAL_SIZE 16 +#define KERNEL_NAME "fft_radix4" #define FLOAT_ULP 6 -#define KERNEL_NAME "sgemm2" +struct float2 { + float x; + float y; + + float2(float real = 0.0f, float imag = 0.0f) : x(real), y(imag) {} + + float2 operator+(const float2& other) const { + return {x + other.x, y + other.y}; + } + + float2 operator-(const float2& other) const { + return {x - other.x, y - other.y}; + } + + float2 operator*(const float2& other) const { + return {x * other.x - y * other.y, x * other.y + y * other.x}; + } +}; #define CL_CHECK(_expr) \ do { \ @@ -45,7 +64,6 @@ static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) fprintf(stderr, "Failed to load kernel."); return -1; } - fseek(fp , 0 , SEEK_END); long fsize = ftell(fp); rewind(fp); @@ -58,25 +76,33 @@ static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) return 0; } -static bool compare_equal(float a, float b) { - union fi_t { float f; int32_t i; }; - fi_t fa, fb; - fa.f = a; - fb.f = b; - auto d = std::abs(fa.i - fb.i); - return d <= FLOAT_ULP; +static std::vector referenceDFT(const std::vector& input) { + std::vector output(input.size()); + for (unsigned int k = 0; k < input.size(); ++k) { // For each output element + output[k] = {0, 0}; // Initialize to zero + for (unsigned int n = 0; n < input.size(); ++n) { // For each input element + float angle = -2 * M_PI * k * n / input.size(); + float2 twiddle = {cos(angle), sin(angle)}; + output[k].x += input[n].x * twiddle.x - input[n].y * twiddle.y; + output[k].y += input[n].x * twiddle.y + input[n].y * twiddle.x; + } + } + return output; } -static void matmul_cpu(float *C, float *A, float *B, int N) { - for (int i = 0; i < N; i++) { - for (int j = 0; j < N; j++) { - float sum = 0.0f; - for (int k = 0; k < N; k++) { - sum += A[i * N + k] * B[k * N + j]; - } - C[i * N + j] = sum; - } +static int verifyOutput(const std::vector& output, + const std::vector& reference, + unsigned int N) { + int errors = 0; + for (unsigned int i = 0; i < N; ++i) { + float2 diff = {output[i].x - reference[i].x, output[i].y - reference[i].y}; + float error = sqrt(diff.x * diff.x + diff.y * diff.y); + if (error > 1e-5) { + printf("*** error: [%d] expected=(%f,%f), actual=(%f,%f)\n", i, reference[i].x, reference[i].y, output[i].x, output[i].y); + ++errors; } + } + return errors; } cl_device_id device_id = NULL; @@ -84,24 +110,22 @@ cl_context context = NULL; cl_command_queue commandQueue = NULL; cl_program program = NULL; cl_kernel kernel = NULL; -cl_mem a_memobj = NULL; -cl_mem b_memobj = NULL; -cl_mem c_memobj = NULL; +cl_mem i_memobj = NULL; +cl_mem o_memobj = NULL; uint8_t *kernel_bin = NULL; static void cleanup() { if (commandQueue) clReleaseCommandQueue(commandQueue); if (kernel) clReleaseKernel(kernel); if (program) clReleaseProgram(program); - if (a_memobj) clReleaseMemObject(a_memobj); - if (b_memobj) clReleaseMemObject(b_memobj); - if (c_memobj) clReleaseMemObject(c_memobj); + if (i_memobj) clReleaseMemObject(i_memobj); + if (o_memobj) clReleaseMemObject(o_memobj); if (context) clReleaseContext(context); if (device_id) clReleaseDevice(device_id); if (kernel_bin) free(kernel_bin); } -int size = 32; +int size = 64; static void show_usage() { printf("Usage: [-n size] [-h: help]\n"); @@ -124,19 +148,13 @@ static void parse_args(int argc, char **argv) { exit(-1); } } + + printf("Workload size=%d\n", size); } int main (int argc, char **argv) { // parse command arguments parse_args(argc, argv); - - uint32_t num_points = size * size; - - printf("Matrix size=%d\n", size); - if ((size / LOCAL_SIZE) * LOCAL_SIZE != size) { - printf("Error: matrix size must be a multiple of %d\n", LOCAL_SIZE); - return -1; - } cl_platform_id platform_id; size_t kernel_size; @@ -148,15 +166,10 @@ int main (int argc, char **argv) { printf("Create context\n"); context = CL_CHECK2(clCreateContext(NULL, 1, &device_id, NULL, NULL, &_err)); - char device_string[1024]; - clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); - printf("Using device: %s\n", device_string); - printf("Allocate device buffers\n"); - size_t nbytes = num_points * sizeof(float); - a_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY, nbytes, NULL, &_err)); - b_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY, nbytes, NULL, &_err)); - c_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, nbytes, NULL, &_err)); + size_t nbytes = size * sizeof(float2); + i_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY, nbytes, NULL, &_err)); + o_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, nbytes, NULL, &_err)); printf("Create program from kernel source\n"); #ifdef HOSTGPU @@ -169,11 +182,7 @@ int main (int argc, char **argv) { return -1; program = CL_CHECK2(clCreateProgramWithBinary( context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, NULL, &_err)); -#endif - if (program == NULL) { - cleanup(); - return -1; - } +#endif // Build program CL_CHECK(clBuildProgram(program, 1, &device_id, NULL, NULL, NULL)); @@ -181,61 +190,47 @@ int main (int argc, char **argv) { // Create kernel kernel = CL_CHECK2(clCreateKernel(program, KERNEL_NAME, &_err)); - size_t global_size[2] = {size, size}; - size_t local_size[2] = {LOCAL_SIZE, LOCAL_SIZE}; - // Set kernel arguments - CL_CHECK(clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&a_memobj)); - CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&b_memobj)); - CL_CHECK(clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *)&c_memobj)); - CL_CHECK(clSetKernelArg(kernel, 3, sizeof(uint32_t), &size)); - CL_CHECK(clSetKernelArg(kernel, 4, local_size[0]*local_size[1]*sizeof(float), NULL)); - CL_CHECK(clSetKernelArg(kernel, 5, local_size[0]*local_size[1]*sizeof(float), NULL)); + CL_CHECK(clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&i_memobj)); + CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&o_memobj)); + CL_CHECK(clSetKernelArg(kernel, 2, sizeof(int), (void *)&size)); - // Allocate memories for input arrays and output arrays. - std::vector h_a(num_points); - std::vector h_b(num_points); - std::vector h_c(num_points); + // Allocate memories for input arrays and output arrays. + std::vector h_i(size); + std::vector h_o(size); // Generate input values - for (uint32_t i = 0; i < num_points; ++i) { - h_a[i] = static_cast(rand()) / RAND_MAX; - h_b[i] = static_cast(rand()) / RAND_MAX; + for (int i = 0; i < size; ++i) { + h_i[i].x = sin(2 * M_PI * i / size); // Sine wave as an example + h_i[i].y = 0.0f; // Zero imaginary part } // Creating command queue commandQueue = CL_CHECK2(clCreateCommandQueue(context, device_id, 0, &_err)); printf("Upload source buffers\n"); - CL_CHECK(clEnqueueWriteBuffer(commandQueue, a_memobj, CL_TRUE, 0, nbytes, h_a.data(), 0, NULL, NULL)); - CL_CHECK(clEnqueueWriteBuffer(commandQueue, b_memobj, CL_TRUE, 0, nbytes, h_b.data(), 0, NULL, NULL)); + CL_CHECK(clEnqueueWriteBuffer(commandQueue, i_memobj, CL_TRUE, 0, nbytes, h_i.data(), 0, NULL, NULL)); printf("Execute the kernel\n"); + size_t global_work_size[1] = {size}; + size_t local_work_size[1] = {LOCAL_SIZE}; auto time_start = std::chrono::high_resolution_clock::now(); - CL_CHECK(clEnqueueNDRangeKernel(commandQueue, kernel, 2, NULL, global_size, local_size, 0, NULL, NULL)); + CL_CHECK(clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL, global_work_size, local_work_size, 0, NULL, NULL)); CL_CHECK(clFinish(commandQueue)); auto time_end = std::chrono::high_resolution_clock::now(); double elapsed = std::chrono::duration_cast(time_end - time_start).count(); printf("Elapsed time: %lg ms\n", elapsed); printf("Download destination buffer\n"); - CL_CHECK(clEnqueueReadBuffer(commandQueue, c_memobj, CL_TRUE, 0, nbytes, h_c.data(), 0, NULL, NULL)); + CL_CHECK(clEnqueueReadBuffer(commandQueue, o_memobj, CL_TRUE, 0, nbytes, h_o.data(), 0, NULL, NULL)); printf("Verify result\n"); - std::vector ref_vec(num_points); - matmul_cpu(ref_vec.data(), h_a.data(), h_b.data(), size); - int errors = 0; - for (uint32_t i = 0; i < num_points; ++i) { - if (!compare_equal(h_c[i], ref_vec[i])) { - if (errors < 100) - printf("*** error: [%d] expected=%f, actual=%f\n", i, ref_vec[i], h_c[i]); - ++errors; - } - } - if (errors != 0) { - printf("FAILED! - %d errors\n", errors); - } else { + std::vector reference = referenceDFT(h_i); + auto errors = verifyOutput(h_o, reference, size); + if (0 == errors) { printf("PASSED!\n"); + } else { + printf("FAILED! - %d errors\n", errors); } // Clean up diff --git a/tests/opencl/fft/main.cc.o b/tests/opencl/fft/main.cc.o new file mode 100644 index 0000000000000000000000000000000000000000..e3f30c90822ce9fddb7745f61c868737af43a331 GIT binary patch literal 15368 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 z_RY;@%HeqJmnp=t@MV=E@E{eavv-J@@7Zd2osn-sF^8qFpjc9@cC9H0wR_EPCnyC}8m4r*U| zD^>2gi4tb6r*8+=(34v$X~oZFRK|A+9SmAXr5*F=aP8UDqFF5EY&(szc8H2lg<}iH7LF|(TR66GEO0DvEO0Dv zEO0DvEO0DvEO0DvjNGdua4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{v za4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c}F zaIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2w zaIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2w zaIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2w zaIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2waIA2w zaIA1Fa4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{v za4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{va4c{v za4c{va4c{va4c{va4c{va4c{v|8wl!&KWvs&9bn-*##W!%w$JEDeL$c_{GsS*4I>; zQq&ZhP|J9Y?rMI-k22vErklG57MuE|H=3in_nA_~j+yn_E|_eE@0qC^Uz>jgewuO@ z-RNViCvC2mo;s(^LOGIh(zPl1DYj-|s*$P$xt=UXaTACls#K#8_qz1#NMl+tx)rsg zj^y*NJ0-^VrSZcf$x&eh{r)|gnztTLdk;^d4B4krpP@78%#B%8sN6gnw_qVX__lU@P}zRRY3{j`^dTgX z>P|mLo8DZc6m_mr=Pfr#Qs1E*;rD6i=|^-m;2D*e{E}uoe?zaUeV`iaKhxUe-zg^V zFFKs&FYWA_jKA)2;WZy!`9f}YZcQHiw?T4l)HDS@u9Nb=?3kIwlZU?cWV1Il7ay30 zmlp8i6X(46L!Y$V+&vwaicQDP4Bni7sy8qB?alQ%r|0ma={ZZb3>@7(10Ua(fz!Rg z-+6twOhX@TKE#Jz7W#1goj%;*hz~bJriGouea45w#fKkk^WpvTeAs=k58ub-1WL})qdfTJ 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

1r#xbGVmc3tkqp7lI< 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 KKn?um2L1=Sy+cv} diff --git a/tests/opencl/mri-q/Makefile b/tests/opencl/mri-q/Makefile deleted file mode 100644 index dbff34f9..00000000 --- a/tests/opencl/mri-q/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -PROJECT = mri-q - -SRCS = main.cc args.c parboil_opencl.c ocl.c gpu_info.c file.cc computeQ.c - -CXXFLAGS += -I. - -OPTS ?= - -include ../common.mk diff --git a/tests/opencl/mri-q/args.c b/tests/opencl/mri-q/args.c deleted file mode 100644 index 9d751e29..00000000 --- a/tests/opencl/mri-q/args.c +++ /dev/null @@ -1,617 +0,0 @@ - -#include -#include -#include -#include -#include -#include - -/*****************************************************************************/ -/* Memory management routines */ - -/* Free an array of owned strings. */ -void -pb_FreeStringArray(char **string_array) -{ - char **p; - - if (!string_array) return; - for (p = string_array; *p; p++) free(*p); - free(string_array); -} - -struct pb_PlatformParam * -pb_PlatformParam(char *name, char *version) -{ - if (name == NULL) { - fprintf(stderr, "pb_PlatformParam: Invalid argument\n"); - exit(-1); - } - - struct pb_PlatformParam *ret = - (struct pb_PlatformParam *)malloc(sizeof (struct pb_PlatformParam)); - - ret->name = name; - ret->version = version; - return ret; -} - -void -pb_FreePlatformParam(struct pb_PlatformParam *p) -{ - if (p == NULL) return; - - free(p->name); - free(p->version); - free(p); -} - -struct pb_DeviceParam * -pb_DeviceParam_index(int index) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_INDEX; - ret->index = index; - return ret; -} - -struct pb_DeviceParam * -pb_DeviceParam_cpu(void) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_CPU; - return ret; -} - -struct pb_DeviceParam * -pb_DeviceParam_gpu(void) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_GPU; - return ret; -} - -struct pb_DeviceParam * -pb_DeviceParam_accelerator(void) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_ACCELERATOR; - return ret; -} - -struct pb_DeviceParam * -pb_DeviceParam_name(char *name) -{ - struct pb_DeviceParam *ret = - (struct pb_DeviceParam *)malloc(sizeof (struct pb_DeviceParam)); - ret->criterion = pb_Device_NAME; - ret->name = name; - return ret; -} - -void -pb_FreeDeviceParam(struct pb_DeviceParam *p) -{ - if (p == NULL) return; - - switch(p->criterion) { - case pb_Device_NAME: - free(p->name); - break; - case pb_Device_INDEX: - case pb_Device_CPU: - case pb_Device_ACCELERATOR: - break; - default: - fprintf(stderr, "pb_FreeDeviceParam: Invalid argument\n"); - exit(-1); - } -} - -void -pb_FreeParameters(struct pb_Parameters *p) -{ - free(p->outFile); - pb_FreeStringArray(p->inpFiles); - pb_FreePlatformParam(p->platform); - pb_FreeDeviceParam(p->device); - free(p); -} - -/*****************************************************************************/ - -/* Parse a comma-delimited list of strings into an - * array of strings. */ -static char ** -read_string_array(char *in) -{ - char **ret; - int i; - int count; /* Number of items in the input */ - char *substring; /* Current substring within 'in' */ - - /* Count the number of items in the string */ - count = 1; - for (i = 0; in[i]; i++) if (in[i] == ',') count++; - - /* Allocate storage */ - ret = (char **)malloc((count + 1) * sizeof(char *)); - - /* Create copies of the strings from the list */ - substring = in; - for (i = 0; i < count; i++) { - char *substring_end; - int substring_length; - - /* Find length of substring */ - for (substring_end = substring; - (*substring_end != ',') && (*substring_end != 0); - substring_end++); - - substring_length = substring_end - substring; - - /* Allocate memory and copy the substring */ - ret[i] = (char *)malloc(substring_length + 1); - memcpy(ret[i], substring, substring_length); - ret[i][substring_length] = 0; - - /* go to next substring */ - substring = substring_end + 1; - } - ret[i] = NULL; /* Write the sentinel value */ - - return ret; -} - -static void -report_parse_error(const char *str) -{ - fputs(str, stderr); -} - -/* Interpret a string as a 'pb_DeviceParam' value. - * Return a pointer to a new value, or NULL on failure. - */ -static struct pb_DeviceParam * -read_device_param(char *str) -{ - /* Try different ways of interpreting 'device_string' until one works */ - - /* If argument is an integer, then interpret it as a device index */ - errno = 0; - char *end; - long device_int = strtol(str, &end, 10); - if (!errno) { - /* Negative numbers are not valid */ - if (device_int < 0 || device_int > INT_MAX) return NULL; - - return pb_DeviceParam_index(device_int); - } - - /* Match against predefined strings */ - if (strcmp(str, "CPU") == 0) - return pb_DeviceParam_cpu(); - if (strcmp(str, "GPU") == 0) - return pb_DeviceParam_gpu(); - if (strcmp(str, "ACCELERATOR") == 0) - return pb_DeviceParam_accelerator(); - - /* Assume any other string is a device name */ - return pb_DeviceParam_name(strdup(str)); -} - -/* Interpret a string as a 'pb_PlatformParam' value. - * Return a pointer to a new value, or NULL on failure. - */ -static struct pb_PlatformParam * -read_platform_param(char *str) -{ - int separator_index; /* Index of the '-' character separating - * name and version number. It's -1 if - * there's no '-' character. */ - - /* Find the last occurrence of '-' in 'str' */ - { - char *cur; - separator_index = -1; - for (cur = str; *cur; cur++) { - if (*cur == '-') separator_index = cur - str; - } - } - - /* The platform name is either the entire string, or all characters before - * the separator */ - int name_length = separator_index == -1 ? strlen(str) : separator_index; - char *name_str = (char *)malloc(name_length + 1); - memcpy(name_str, str, name_length); - name_str[name_length] = 0; - - /* The version is either NULL, or all characters after the separator */ - char *version_str; - if (separator_index == -1) { - version_str = NULL; - } - else { - const char *version_input_str = str + separator_index + 1; - int version_length = strlen(version_input_str); - - version_str = (char *)malloc(version_length + 1); - memcpy(version_str, version_input_str, version_length); - version_str[version_length] = 0; - } - - /* Create output structure */ - return pb_PlatformParam(name_str, version_str); -} - -/****************************************************************************/ -/* Argument parsing state */ - -/* Argument parsing state. - * - * Arguments that are interpreted by the argument parser are removed from - * the list. Variables 'argc' and 'argn' do not count arguments that have - * been removed. - * - * During argument parsing, the array of arguments is compacted, overwriting - * the erased arguments. Variable 'argv_put' points to the array element - * where the next argument will be written. Variable 'argv_get' points to - * the array element where the next argument will be read from. - */ -struct argparse { - int argc; /* Number of arguments. Mutable. */ - int argn; /* Current argument index. */ - char **argv_get; /* Argument value being read. */ - char **argv_put; /* Argument value being written. - * argv_put <= argv_get. */ -}; - -static void -initialize_argparse(struct argparse *ap, int argc, char **argv) -{ - ap->argc = argc; - ap->argn = 0; - ap->argv_get = ap->argv_put = argv; -} - -/* Finish argument parsing, without processing the remaining arguments. - * Write new argument count into _argc. */ -static void -finalize_argparse(struct argparse *ap, int *_argc, char **argv) -{ - /* Move the remaining arguments */ - for(; ap->argn < ap->argc; ap->argn++) - *ap->argv_put++ = *ap->argv_get++; - - /* Update the argument count */ - *_argc = ap->argc; - - /* Insert a terminating NULL */ - argv[ap->argc] = NULL; -} - -/* Delete the current argument. The argument will not be visible - * when argument parsing is done. */ -static void -delete_argument(struct argparse *ap) -{ - if (ap->argn >= ap->argc) { - fprintf(stderr, "delete_argument\n"); - } - ap->argc--; - ap->argv_get++; -} - -/* Go to the next argument. Also, move the current argument to its - * final location in argv. */ -static void -next_argument(struct argparse *ap) -{ - if (ap->argn >= ap->argc) { - fprintf(stderr, "next_argument\n"); - } - /* Move argument to its new location. */ - *ap->argv_put++ = *ap->argv_get++; - ap->argn++; -} - -static int -is_end_of_arguments(struct argparse *ap) -{ - return ap->argn == ap->argc; -} - -/* Get the current argument */ -static char * -get_argument(struct argparse *ap) -{ - return *ap->argv_get; -} - -/* Get the current argument, and also delete it */ -static char * -consume_argument(struct argparse *ap) -{ - char *ret = get_argument(ap); - delete_argument(ap); - return ret; -} - -/****************************************************************************/ - -/* The result of parsing a command-line argument */ -typedef enum { - ARGPARSE_OK, /* Success */ - ARGPARSE_ERROR, /* Error */ - ARGPARSE_DONE /* Success, and do not continue parsing */ -} result; - -typedef result parse_action(struct argparse *ap, struct pb_Parameters *params); - - -/* A command-line option */ -struct option { - char short_name; /* If not 0, the one-character - * name of this option */ - const char *long_name; /* If not NULL, the long name of this option */ - parse_action *action; /* What to do when this option occurs. - * Sentinel value is NULL. - */ -}; - -/* Output file - * - * -o FILE - */ -static result -parse_output_file(struct argparse *ap, struct pb_Parameters *params) -{ - if (is_end_of_arguments(ap)) - { - report_parse_error("Expecting file name after '-o'\n"); - return ARGPARSE_ERROR; - } - - /* Replace the output file name */ - free(params->outFile); - params->outFile = strdup(consume_argument(ap)); - - return ARGPARSE_OK; -} - -/* Input files - * - * -i FILE,FILE,... - */ -static result -parse_input_files(struct argparse *ap, struct pb_Parameters *params) -{ - if (is_end_of_arguments(ap)) - { - report_parse_error("Expecting file name after '-i'\n"); - return ARGPARSE_ERROR; - } - - /* Replace the input file list */ - pb_FreeStringArray(params->inpFiles); - params->inpFiles = read_string_array(consume_argument(ap)); - return ARGPARSE_OK; -} - -/* End of options - * - * -- - */ - -static result -parse_end_options(struct argparse *ap, struct pb_Parameters *params) -{ - return ARGPARSE_DONE; -} - -/* OpenCL device - * - * --device X - */ - -static result -parse_device(struct argparse *ap, struct pb_Parameters *params) -{ - /* Read the next argument, which specifies a device */ - - if (is_end_of_arguments(ap)) - { - report_parse_error("Expecting device specification after '--device'\n"); - return ARGPARSE_ERROR; - } - - char *device_string = consume_argument(ap); - struct pb_DeviceParam *device_param = read_device_param(device_string); - - if (!device_param) { - report_parse_error("Unrecognized device specification format on command line\n"); - return ARGPARSE_ERROR; - } - - /* Save the result */ - pb_FreeDeviceParam(params->device); - params->device = device_param; - - return ARGPARSE_OK; -} - -static result -parse_platform(struct argparse *ap, struct pb_Parameters *params) -{ - /* Read the next argument, which specifies a platform */ - - if (is_end_of_arguments(ap)) - { - report_parse_error("Expecting device specification after '--platform'\n"); - return ARGPARSE_ERROR; - } - - char *platform_string = consume_argument(ap); - struct pb_PlatformParam *platform_param = read_platform_param(platform_string); - - if (!platform_param) { - report_parse_error("Unrecognized platform specification format on command line\n"); - return ARGPARSE_ERROR; - } - - /* Save the result */ - pb_FreePlatformParam(params->platform); - params->platform = platform_param; - - return ARGPARSE_OK; -} - - -static struct option options[] = { - { 'o', NULL, &parse_output_file }, - { 'i', NULL, &parse_input_files }, - { '-', NULL, &parse_end_options }, - { 0, "device", &parse_device }, - { 0, "platform", &parse_platform }, - { 0, NULL, NULL } -}; - -static int -is_last_option(struct option *op) -{ - return op->action == NULL; -} - -/****************************************************************************/ - -/* Parse command-line parameters. - * Return zero on error, nonzero otherwise. - * On error, the other outputs may be invalid. - * - * The information collected from parameters is used to update - * 'ret'. 'ret' should be initialized. - * - * '_argc' and 'argv' are updated to contain only the unprocessed arguments. - */ -static int -pb_ParseParameters (struct pb_Parameters *ret, int *_argc, char **argv) -{ - char *err_message; - struct argparse ap; - - /* Each argument */ - initialize_argparse(&ap, *_argc, argv); - while(!is_end_of_arguments(&ap)) { - result arg_result; /* Result of parsing this option */ - char *arg = get_argument(&ap); - - /* Process this argument */ - if (arg[0] == '-') { - /* Single-character flag */ - if ((arg[1] != 0) && (arg[2] == 0)) { - delete_argument(&ap); /* This argument is consumed here */ - - /* Find a matching short option */ - struct option *op; - for (op = options; !is_last_option(op); op++) { - if (op->short_name == arg[1]) { - arg_result = (*op->action)(&ap, ret); - goto option_was_processed; - } - } - - /* No option matches */ - report_parse_error("Unexpected command-line parameter\n"); - arg_result = ARGPARSE_ERROR; - goto option_was_processed; - } - - /* Long flag */ - if (arg[1] == '-') { - delete_argument(&ap); /* This argument is consumed here */ - - /* Find a matching long option */ - struct option *op; - for (op = options; !is_last_option(op); op++) { - if (op->long_name && strcmp(&arg[2], op->long_name) == 0) { - arg_result = (*op->action)(&ap, ret); - goto option_was_processed; - } - } - - /* No option matches */ - report_parse_error("Unexpected command-line parameter\n"); - arg_result = ARGPARSE_ERROR; - goto option_was_processed; - } - } - else { - /* Other arguments are ignored */ - next_argument(&ap); - arg_result = ARGPARSE_OK; - goto option_was_processed; - } - - option_was_processed: - /* Decide what to do next based on 'arg_result' */ - switch(arg_result) { - case ARGPARSE_OK: - /* Continue processing */ - break; - - case ARGPARSE_ERROR: - /* Error exit from the function */ - return 0; - - case ARGPARSE_DONE: - /* Normal exit from the argument parsing loop */ - goto end_of_options; - } - } /* end for each argument */ - - /* If all arguments were processed, then normal exit from the loop */ - - end_of_options: - finalize_argparse(&ap, _argc, argv); - return 1; -} - -/*****************************************************************************/ -/* Other exported functions */ - -struct pb_Parameters * -pb_ReadParameters(int *_argc, char **argv) -{ - struct pb_Parameters *ret = - (struct pb_Parameters *)malloc(sizeof(struct pb_Parameters)); - - /* Initialize the parameters structure */ - ret->outFile = NULL; - ret->inpFiles = (char **)malloc(sizeof(char *)); - ret->inpFiles[0] = NULL; - ret->platform = NULL; - ret->device = NULL; - - /* Read parameters and update _argc, argv */ - if (!pb_ParseParameters(ret, _argc, argv)) { - /* Parse error */ - pb_FreeParameters(ret); - return NULL; - } - - return ret; -} - -int -pb_Parameters_CountInputs(struct pb_Parameters *p) -{ - int n; - - for (n = 0; p->inpFiles[n]; n++); - return n; -} - diff --git a/tests/opencl/mri-q/computeQ.c b/tests/opencl/mri-q/computeQ.c deleted file mode 100644 index 65ed6f4d..00000000 --- a/tests/opencl/mri-q/computeQ.c +++ /dev/null @@ -1,118 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2007 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#include -#include -#include -#include "ocl.h" -#include "macros.h" -#include "computeQ.h" -#include "parboil.h" - -#define NC 1 - -void computePhiMag_GPU(int numK,cl_mem phiR_d,cl_mem phiI_d,cl_mem phiMag_d,clPrmtr* clPrm) -{ - int phiMagBlocks = numK / KERNEL_PHI_MAG_THREADS_PER_BLOCK; - if (numK % KERNEL_PHI_MAG_THREADS_PER_BLOCK) - phiMagBlocks++; - - size_t DimPhiMagBlock = KERNEL_PHI_MAG_THREADS_PER_BLOCK; - size_t DimPhiMagGrid = phiMagBlocks*KERNEL_PHI_MAG_THREADS_PER_BLOCK; - - cl_int clStatus; - clStatus = clSetKernelArg(clPrm->clKernel,0,sizeof(cl_mem),&phiR_d); - clStatus = clSetKernelArg(clPrm->clKernel,1,sizeof(cl_mem),&phiI_d); - clStatus = clSetKernelArg(clPrm->clKernel,2,sizeof(cl_mem),&phiMag_d); - clStatus = clSetKernelArg(clPrm->clKernel,3,sizeof(int),&numK); - CHECK_ERROR("clSetKernelArg") - - clStatus = clEnqueueNDRangeKernel(clPrm->clCommandQueue,clPrm->clKernel,1,NULL,&DimPhiMagGrid,&DimPhiMagBlock,0,NULL,NULL); - CHECK_ERROR("clEnqueueNDRangeKernel") -} - -static -unsigned long long int -readElapsedTime(cl_event internal) -{ - cl_int status; - cl_ulong t_begin, t_end; - status = clGetEventProfilingInfo(internal, CL_PROFILING_COMMAND_START, - sizeof(cl_ulong), &t_begin, NULL); - if (status != CL_SUCCESS) return 0; - status = clGetEventProfilingInfo(internal, CL_PROFILING_COMMAND_END, - sizeof(cl_ulong), &t_end, NULL); - if (status != CL_SUCCESS) return 0; - return (unsigned long long int)(t_end - t_begin); -} - - -void computeQ_GPU (int numK,int numX, - cl_mem x_d, cl_mem y_d, cl_mem z_d, - struct kValues* kVals, - cl_mem Qr_d, cl_mem Qi_d, - clPrmtr* clPrm) -{ - int QGrids = numK / KERNEL_Q_K_ELEMS_PER_GRID; - if (numK % KERNEL_Q_K_ELEMS_PER_GRID) - QGrids++; - int QBlocks = numX / KERNEL_Q_THREADS_PER_BLOCK; - if (numX % KERNEL_Q_THREADS_PER_BLOCK) - QBlocks++; - - size_t DimQBlock = KERNEL_Q_THREADS_PER_BLOCK/NC; - size_t DimQGrid = QBlocks*KERNEL_Q_THREADS_PER_BLOCK/NC; - - cl_int clStatus; - cl_mem ck; - ck = clCreateBuffer(clPrm->clContext,CL_MEM_READ_WRITE,KERNEL_Q_K_ELEMS_PER_GRID*sizeof(struct kValues),NULL,&clStatus); - - int QGrid; - for (QGrid = 0; QGrid < QGrids; QGrid++) { - // Put the tile of K values into constant mem - int QGridBase = QGrid * KERNEL_Q_K_ELEMS_PER_GRID; - struct kValues* kValsTile = kVals + QGridBase; - int numElems = MIN(KERNEL_Q_K_ELEMS_PER_GRID, numK - QGridBase); - - clStatus = clEnqueueWriteBuffer(clPrm->clCommandQueue,ck,CL_TRUE,0,numElems*sizeof(struct kValues),kValsTile,0,NULL,NULL); - CHECK_ERROR("clEnqueueWriteBuffer") - - clStatus = clSetKernelArg(clPrm->clKernel,0,sizeof(int),&numK); - clStatus = clSetKernelArg(clPrm->clKernel,1,sizeof(int),&QGridBase); - clStatus = clSetKernelArg(clPrm->clKernel,2,sizeof(cl_mem),&x_d); - clStatus = clSetKernelArg(clPrm->clKernel,3,sizeof(cl_mem),&y_d); - clStatus = clSetKernelArg(clPrm->clKernel,4,sizeof(cl_mem),&z_d); - clStatus = clSetKernelArg(clPrm->clKernel,5,sizeof(cl_mem),&Qr_d); - clStatus = clSetKernelArg(clPrm->clKernel,6,sizeof(cl_mem),&Qi_d); - clStatus = clSetKernelArg(clPrm->clKernel,7,sizeof(cl_mem),&ck); - CHECK_ERROR("clSetKernelArg") - - printf ("Grid: %d, Block: %d\n", DimQGrid, DimQBlock); - - #define TIMED_EXECUTION - #ifdef TIMED_EXECUTION - cl_event e; - clStatus = clEnqueueNDRangeKernel(clPrm->clCommandQueue,clPrm->clKernel,1,NULL,&DimQGrid,&DimQBlock,0,NULL,&e); - CHECK_ERROR("clEnqueueNDRangeKernel") - clWaitForEvents(1, &e); - printf ("%llu\n", readElapsedTime(e)); - #else - clStatus = clEnqueueNDRangeKernel(clPrm->clCommandQueue,clPrm->clKernel,1,NULL,&DimQGrid,&DimQBlock,0,NULL,NULL); - CHECK_ERROR("clEnqueueNDRangeKernel") - #endif - } -} - -void createDataStructsCPU(int numK, int numX, float** phiMag, - float** Qr, float** Qi) -{ - *phiMag = (float* ) memalign(16, numK * sizeof(float)); - *Qr = (float*) memalign(16, numX * sizeof (float)); - *Qi = (float*) memalign(16, numX * sizeof (float)); -} - diff --git a/tests/opencl/mri-q/computeQ.h b/tests/opencl/mri-q/computeQ.h deleted file mode 100644 index 3312902f..00000000 --- a/tests/opencl/mri-q/computeQ.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __COMPUTEQ__ -#define __COMPUTEQ__ - -#ifdef __cplusplus -extern "C" { -#endif - -void computePhiMag_GPU(int numK,cl_mem phiR_d,cl_mem phiI_d,cl_mem phiMag_d,clPrmtr* clPrm); -void computeQ_GPU (int numK,int numX, - cl_mem x_d, cl_mem y_d, cl_mem z_d, - struct kValues* kVals, - cl_mem Qr_d, cl_mem Qi_d, - clPrmtr* clPrm); - -void createDataStructsCPU(int numK, int numX, float** phiMag, - float** Qr, float** Qi); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tests/opencl/mri-q/file.cc b/tests/opencl/mri-q/file.cc deleted file mode 100644 index 15b07075..00000000 --- a/tests/opencl/mri-q/file.cc +++ /dev/null @@ -1,78 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2007 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -//#include -#include -#include -#include -#include - -#include "file.h" - -#if __BYTE_ORDER != __LITTLE_ENDIAN -# error "File I/O is not implemented for this system: wrong endianness." -#endif - -extern "C" -void inputData(char* fName, int* _numK, int* _numX, - float** kx, float** ky, float** kz, - float** x, float** y, float** z, - float** phiR, float** phiI) -{ - int numK, numX; - FILE* fid = fopen(fName, "r"); - - if (fid == NULL) - { - fprintf(stderr, "Cannot open input file\n"); - exit(-1); - } - fread (&numK, sizeof (int), 1, fid); - *_numK = numK; - fread (&numX, sizeof (int), 1, fid); - *_numX = numX; - *kx = (float *) memalign(16, numK * sizeof (float)); - fread (*kx, sizeof (float), numK, fid); - *ky = (float *) memalign(16, numK * sizeof (float)); - fread (*ky, sizeof (float), numK, fid); - *kz = (float *) memalign(16, numK * sizeof (float)); - fread (*kz, sizeof (float), numK, fid); - *x = (float *) memalign(16, numX * sizeof (float)); - fread (*x, sizeof (float), numX, fid); - *y = (float *) memalign(16, numX * sizeof (float)); - fread (*y, sizeof (float), numX, fid); - *z = (float *) memalign(16, numX * sizeof (float)); - fread (*z, sizeof (float), numX, fid); - *phiR = (float *) memalign(16, numK * sizeof (float)); - fread (*phiR, sizeof (float), numK, fid); - *phiI = (float *) memalign(16, numK * sizeof (float)); - fread (*phiI, sizeof (float), numK, fid); - fclose (fid); -} - -extern "C" -void outputData(char* fName, float* outR, float* outI, int numX) -{ - FILE* fid = fopen(fName, "w"); - uint32_t tmp32; - - if (fid == NULL) - { - fprintf(stderr, "Cannot open output file\n"); - exit(-1); - } - - /* Write the data size */ - tmp32 = numX; - fwrite(&tmp32, sizeof(uint32_t), 1, fid); - - /* Write the reconstructed data */ - fwrite (outR, sizeof (float), numX, fid); - fwrite (outI, sizeof (float), numX, fid); - fclose (fid); -} diff --git a/tests/opencl/mri-q/file.h b/tests/opencl/mri-q/file.h deleted file mode 100644 index c6a61ef4..00000000 --- a/tests/opencl/mri-q/file.h +++ /dev/null @@ -1,22 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2007 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#ifdef __cplusplus -extern "C" { -#endif - -void inputData(char* fName, int* _numK, int* _numX, - float** kx, float** ky, float** kz, - float** x, float** y, float** z, - float** phiR, float** phiI); - -void outputData(char* fName, float* outR, float* outI, int numX); - -#ifdef __cplusplus -} -#endif diff --git a/tests/opencl/mri-q/gpu_info.c b/tests/opencl/mri-q/gpu_info.c deleted file mode 100644 index 4d641f81..00000000 --- a/tests/opencl/mri-q/gpu_info.c +++ /dev/null @@ -1,55 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ -//#include -#include -#include -#include -#include - -#include "gpu_info.h" - -void compute_active_thread(size_t *thread, - size_t *grid, - int task, - int pad, - int major, - int minor, - int sm) -{ - int max_thread; - int max_block=8; - if(major==1) - { - if(minor>=2) - max_thread=1024; - else - max_thread=768; - } - else if(major==2) - max_thread=1536; - else - //newer GPU //keep using 2.0 - max_thread=1536; - - int _grid; - int _thread; - - if(task*pad>sm*max_thread) - { - _thread=max_thread/max_block; - _grid = ((task*pad+_thread-1)/_thread)*_thread; - } - else - { - _thread=pad; - _grid=task*pad; - } - - thread[0]=_thread; - grid[0]=_grid; -} diff --git a/tests/opencl/mri-q/gpu_info.h b/tests/opencl/mri-q/gpu_info.h deleted file mode 100644 index 5d433968..00000000 --- a/tests/opencl/mri-q/gpu_info.h +++ /dev/null @@ -1,28 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2010 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -#ifndef __GPUINFOH__ -#define __GPUINFOH__ - -#ifdef __cplusplus -extern "C" { -#endif - -void compute_active_thread(size_t *thread, - size_t *grid, - int task, - int pad, - int major, - int minor, - int sm); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tests/opencl/mri-q/kernel.cl b/tests/opencl/mri-q/kernel.cl deleted file mode 100644 index 39a1842e..00000000 --- a/tests/opencl/mri-q/kernel.cl +++ /dev/null @@ -1,51 +0,0 @@ -#include "macros.h" - -__kernel void -ComputePhiMag_GPU(__global float* phiR, __global float* phiI, __global float* phiMag, int numK) { - int indexK = get_global_id(0); - float real = indexK; - float imag = indexK; - if (indexK < numK) { - /*float*/ real = phiR[indexK]; - /*float*/ imag = phiI[indexK]; - phiMag[indexK] = real*real + imag*imag; - } -} - -__kernel void -ComputeQ_GPU(int numK, int kGlobalIndex, - __global float* x, __global float* y, __global float* z, - __global float* Qr, __global float* Qi, __global struct kValues* ck) -{ - float sX; - float sY; - float sZ; - float sQr; - float sQi; - - // Determine the element of the X arrays computed by this thread - int xIndex = get_group_id(0)*KERNEL_Q_THREADS_PER_BLOCK + get_local_id(0); - - // Read block's X values from global mem to shared mem - sX = x[xIndex]; - sY = y[xIndex]; - sZ = z[xIndex]; - sQr = Qr[xIndex]; - sQi = Qi[xIndex]; - - int kIndex = 0; - for (; (kIndex < KERNEL_Q_K_ELEMS_PER_GRID); kIndex++) { - if (kGlobalIndex < numK) { - float expArg; - expArg = PIx2 * (ck[kIndex].Kx * sX + - ck[kIndex].Ky * sY + - ck[kIndex].Kz * sZ); - sQr = sQr + ck[kIndex].PhiMag * cos(expArg); // native_cos(expArg); - sQi = sQi + ck[kIndex].PhiMag * sin(expArg); // native_sin(expArg); - } - kGlobalIndex++; - } - - Qr[xIndex] = sQr; - Qi[xIndex] = sQi; -} diff --git a/tests/opencl/mri-q/macros.h b/tests/opencl/mri-q/macros.h deleted file mode 100644 index 501ead7e..00000000 --- a/tests/opencl/mri-q/macros.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __MACROS__ -#define __MACROS__ - -#define PI 3.1415926535897932384626433832795029f -#define PIx2 6.2831853071795864769252867665590058f - -#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) -#define K_ELEMS_PER_GRID 2048 - -#define KERNEL_PHI_MAG_THREADS_PER_BLOCK 256 -#define KERNEL_Q_THREADS_PER_BLOCK 256 -#define KERNEL_Q_K_ELEMS_PER_GRID 1024 - -struct kValues { - float Kx; - float Ky; - float Kz; - float PhiMag; -}; - -#endif diff --git a/tests/opencl/mri-q/main.cc b/tests/opencl/mri-q/main.cc deleted file mode 100644 index 0f1a809b..00000000 --- a/tests/opencl/mri-q/main.cc +++ /dev/null @@ -1,321 +0,0 @@ -/*************************************************************************** - *cr - *cr (C) Copyright 2007 The Board of Trustees of the - *cr University of Illinois - *cr All Rights Reserved - *cr - ***************************************************************************/ - -/* - * C code for creating the Q data structure for fast convolution-based - * Hessian multiplication for arbitrary k-space trajectories. - * - * Inputs: - * kx - VECTOR of kx values, same length as ky and kz - * ky - VECTOR of ky values, same length as kx and kz - * kz - VECTOR of kz values, same length as kx and ky - * x - VECTOR of x values, same length as y and z - * y - VECTOR of y values, same length as x and z - * z - VECTOR of z values, same length as x and y - * phi - VECTOR of the Fourier transform of the spatial basis - * function, evaluated at [kx, ky, kz]. Same length as kx, ky, and kz. - * - * recommended g++ options: - * -O3 -lm -ffast-math -funroll-all-loops - */ - -#include -#include -#include -#include - -#include "ocl.h" -#include "file.h" -#include "macros.h" -#include "computeQ.h" - -static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { - if (nullptr == filename || nullptr == data || 0 == size) - return CL_INVALID_VALUE; - - FILE* fp = fopen(filename, "r"); - if (NULL == fp) { - fprintf(stderr, "Failed to load kernel."); - return CL_INVALID_VALUE; - } - fseek(fp , 0 , SEEK_END); - long fsize = ftell(fp); - rewind(fp); - - *data = (uint8_t*)malloc(fsize); - *size = fread(*data, 1, fsize, fp); - - fclose(fp); - - return CL_SUCCESS; -} - -static void -setupMemoryGPU(int num, int size, cl_mem* dev_ptr, float* host_ptr,clPrmtr* clPrm) -{ - cl_int clStatus; - *dev_ptr = clCreateBuffer(clPrm->clContext,CL_MEM_READ_ONLY,num*size,NULL,&clStatus); - CHECK_ERROR("clCreateBuffer"); - clStatus = clEnqueueWriteBuffer(clPrm->clCommandQueue,*dev_ptr,CL_TRUE,0,num*size,host_ptr,0,NULL,NULL); - CHECK_ERROR("clEnequeueWriteBuffer"); -} - -static void -cleanupMemoryGPU(int num, int size, cl_mem* dev_ptr, float* host_ptr, clPrmtr* clPrm) -{ - cl_int clStatus; - clStatus = clEnqueueReadBuffer(clPrm->clCommandQueue,*dev_ptr,CL_TRUE,0,num*size,host_ptr,0,NULL,NULL); - CHECK_ERROR("clEnqueueReadBuffer") - clStatus = clReleaseMemObject(*dev_ptr); - CHECK_ERROR("clReleaseMemObject") -} - -int -main (int argc, char *argv[]) { - int numX, numK; /* Number of X and K values */ - int original_numK; /* Number of K values in input file */ - float *kx, *ky, *kz; /* K trajectory (3D vectors) */ - float *x, *y, *z; /* X coordinates (3D vectors) */ - float *phiR, *phiI; /* Phi values (complex) */ - float *phiMag; /* Magnitude of Phi */ - float *Qr, *Qi; /* Q signal (complex) */ - - struct kValues* kVals; - - struct pb_Parameters *params; - struct pb_TimerSet timers; - - pb_InitializeTimerSet(&timers); - - /* Read command line */ - params = pb_ReadParameters(&argc, argv); - - params->inpFiles = (char **)malloc(sizeof(char *) * 2); - params->inpFiles[0] = (char *)malloc(100); - params->inpFiles[1] = NULL; - strncpy(params->inpFiles[0], "32_32_32_dataset.bin", 100); - - if ((params->inpFiles[0] == NULL) || (params->inpFiles[1] != NULL)) - { - fprintf(stderr, "Expecting one input filename\n"); - exit(-1); - } - - /* Read in data */ - pb_SwitchToTimer(&timers, pb_TimerID_IO); - inputData(params->inpFiles[0], - &original_numK, &numX, - &kx, &ky, &kz, - &x, &y, &z, - &phiR, &phiI); - - /* Reduce the number of k-space samples if a number is given - * on the command line */ - if (argc < 2) - numK = original_numK; - else - { - int inputK; - char *end; - inputK = strtol(argv[1], &end, 10); - if (end == argv[1]) - { - fprintf(stderr, "Expecting an integer parameter\n"); - exit(-1); - } - - numK = MIN(inputK, original_numK); - } - - printf("%d pixels in output; %d samples in trajectory; using %d samples\n", - numX, original_numK, numK); - - pb_SwitchToTimer(&timers, pb_TimerID_COMPUTE); - - clPrmtr clPrm; - - pb_Context* pb_context; - pb_context = pb_InitOpenCLContext(params); - if (pb_context == NULL) { - fprintf (stderr, "Error: No OpenCL platform/device can be found."); - return -1; - } - - cl_int clStatus; - cl_device_id clDevice = (cl_device_id) pb_context->clDeviceId; - cl_platform_id clPlatform = (cl_platform_id) pb_context->clPlatformId; - clPrm.clContext = (cl_context) pb_context->clContext; - - clPrm.clCommandQueue = clCreateCommandQueue(clPrm.clContext,clDevice,CL_QUEUE_PROFILING_ENABLE,&clStatus); - CHECK_ERROR("clCreateCommandQueue") - - pb_SetOpenCL(&(clPrm.clContext), &(clPrm.clCommandQueue)); - -#ifdef HOSTGPU - const char* clSource[] = {readFile("kernel.cl")}; - CHECK_ERROR("clCreateProgramWithSource") - cl_program clProgram = clCreateProgramWithSource(clPrm.clContext,1,clSource,NULL,&clStatus); -#else - uint8_t *kernel_bin = NULL; - size_t kernel_size; - cl_int binary_status = 0; - CHECK_ERROR("read_kernel_file") - clStatus = read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size); - CHECK_ERROR("clCreateProgramWithSource") - cl_program clProgram = clCreateProgramWithBinary( - clPrm.clContext, 1, &clDevice, &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &clStatus); -#endif - - char options[50]; - sprintf(options,"-I src/opencl_nvidia"); - clStatus = clBuildProgram(clProgram,0,NULL,options,NULL,NULL); - if (clStatus != CL_SUCCESS) { - char buf[4096]; - clGetProgramBuildInfo(clProgram, clDevice, CL_PROGRAM_BUILD_LOG, 4096, buf, NULL); - printf ("%s\n", buf); - CHECK_ERROR("clBuildProgram") - } - - /* Create CPU data structures */ - createDataStructsCPU(numK, numX, &phiMag, &Qr, &Qi); - - /* GPU section 1 (precompute PhiMag) */ - { - clPrm.clKernel = clCreateKernel(clProgram,"ComputePhiMag_GPU",&clStatus); - CHECK_ERROR("clCreateKernel") - - /* Mirror several data structures on the device */ - cl_mem phiR_d; - cl_mem phiI_d; - cl_mem phiMag_d; - - pb_SwitchToTimer(&timers, pb_TimerID_COPY); - - setupMemoryGPU(numK,sizeof(float),&phiR_d,phiR,&clPrm); - setupMemoryGPU(numK,sizeof(float),&phiI_d,phiI,&clPrm); - phiMag_d = clCreateBuffer(clPrm.clContext,CL_MEM_WRITE_ONLY,numK*sizeof(float),NULL,&clStatus); - CHECK_ERROR("clCreateBuffer") - - clStatus = clFinish(clPrm.clCommandQueue); - CHECK_ERROR("clFinish") - - pb_SwitchToTimer(&timers, pb_TimerID_KERNEL); - - computePhiMag_GPU(numK, phiR_d, phiI_d, phiMag_d, &clPrm); - - clStatus = clFinish(clPrm.clCommandQueue); - CHECK_ERROR("clFinish") - - pb_SwitchToTimer(&timers, pb_TimerID_COPY); - - cleanupMemoryGPU(numK,sizeof(float),&phiMag_d,phiMag,&clPrm); - - clStatus = clReleaseMemObject(phiR_d); - CHECK_ERROR("clReleaseMemObject") - clStatus = clReleaseMemObject(phiI_d); - CHECK_ERROR("clReleaseMemObject") - } - - pb_SwitchToTimer(&timers, pb_TimerID_COMPUTE); - - kVals = (struct kValues*)calloc(numK, sizeof (struct kValues)); - - int k; - for (k = 0; k < numK; k++) { - kVals[k].Kx = kx[k]; - kVals[k].Ky = ky[k]; - kVals[k].Kz = kz[k]; - kVals[k].PhiMag = phiMag[k]; - } - - free(phiMag); - - clStatus = clReleaseKernel(clPrm.clKernel); - - /* GPU section 2 */ - { - clPrm.clKernel = clCreateKernel(clProgram,"ComputeQ_GPU",&clStatus); - CHECK_ERROR("clCreateKernel") - - cl_mem x_d; - cl_mem y_d; - cl_mem z_d; - cl_mem Qr_d; - cl_mem Qi_d; - - pb_SwitchToTimer(&timers, pb_TimerID_COPY); - - setupMemoryGPU(numX,sizeof(float),&x_d,x,&clPrm); - setupMemoryGPU(numX,sizeof(float),&y_d,y,&clPrm); - setupMemoryGPU(numX,sizeof(float),&z_d,z,&clPrm); - - Qr_d = clCreateBuffer(clPrm.clContext,CL_MEM_READ_WRITE,numX*sizeof(float),NULL,&clStatus); - CHECK_ERROR("clCreateBuffer") - clMemSet(&clPrm,Qr_d,0,numX*sizeof(float)); - Qi_d = clCreateBuffer(clPrm.clContext,CL_MEM_READ_WRITE,numX*sizeof(float),NULL,&clStatus); - CHECK_ERROR("clCreateBuffer") - clMemSet(&clPrm,Qi_d,0,numX*sizeof(float)); - - clStatus = clFinish(clPrm.clCommandQueue); - CHECK_ERROR("clFinish") - - pb_SwitchToTimer(&timers, pb_TimerID_KERNEL); - - computeQ_GPU(numK, numX, x_d, y_d, z_d, kVals, Qr_d, Qi_d, &clPrm); - - clStatus = clFinish(clPrm.clCommandQueue); - CHECK_ERROR("clFinish") - - pb_SwitchToTimer(&timers, pb_TimerID_COPY); - - clStatus = clReleaseMemObject(x_d); - CHECK_ERROR("clReleaseMemObject") - clStatus = clReleaseMemObject(y_d); - CHECK_ERROR("clReleaseMemObject") - clStatus = clReleaseMemObject(z_d); - CHECK_ERROR("clReleaseMemObject") - cleanupMemoryGPU(numX,sizeof(float),&Qr_d,Qr,&clPrm); - cleanupMemoryGPU(numX,sizeof(float),&Qi_d,Qi,&clPrm); - } - - pb_SwitchToTimer(&timers, pb_TimerID_COMPUTE); - - if (params->outFile) - { - /* Write Q to file */ - pb_SwitchToTimer(&timers, pb_TimerID_IO); - outputData(params->outFile, Qr, Qi, numX); - pb_SwitchToTimer(&timers, pb_TimerID_COMPUTE); - } - - free (kx); - free (ky); - free (kz); - free (x); - free (y); - free (z); - free (phiR); - free (phiI); - free (kVals); - free (Qr); - free (Qi); - - //free((void*)clSource[0]); - - clStatus = clReleaseKernel(clPrm.clKernel); - clStatus = clReleaseProgram(clProgram); - clStatus = clReleaseCommandQueue(clPrm.clCommandQueue); - clStatus = clReleaseContext(clPrm.clContext); - - pb_SwitchToTimer(&timers, pb_TimerID_NONE); - pb_PrintTimerSet(&timers); - - pb_FreeParameters(params); - - return 0; -} diff --git a/tests/opencl/mri-q/ocl copy.c b/tests/opencl/mri-q/ocl copy.c deleted file mode 100644 index 9ce9a2f5..00000000 --- a/tests/opencl/mri-q/ocl copy.c +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include -#include -#include "ocl.h" - -char* readFile(const char* fileName) -{ - FILE* fp; - fp = fopen(fileName,"r"); - if(fp == NULL) - { - printf("Error 1!\n"); - exit(1); - } - - fseek(fp,0,SEEK_END); - long size = ftell(fp); - rewind(fp); - - char* buffer = (char*)malloc(sizeof(char)*(size+1)); - if(buffer == NULL) - { - printf("Error 2!\n"); - fclose(fp); - exit(1); - } - - size_t res = fread(buffer,1,size,fp); - if(res != size) - { - printf("Error 3!\n"); - fclose(fp); - exit(1); - } - - buffer[size] = 0; - fclose(fp); - return buffer; -} - -void clMemSet(cl_command_queue clCommandQueue, cl_mem buf, int val, size_t size) -{ - cl_int clStatus; - char* temp = (char*)malloc(size); - memset(temp,val,size); - clStatus = clEnqueueWriteBuffer(clCommandQueue,buf,CL_TRUE,0,size,temp,0,NULL,NULL); - CHECK_ERROR("clEnqueueWriteBuffer") - free(temp); -} diff --git a/tests/opencl/mri-q/ocl copy.h b/tests/opencl/mri-q/ocl copy.h deleted file mode 100644 index 8840a868..00000000 --- a/tests/opencl/mri-q/ocl copy.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __OCLH__ -#define __OCLH__ - -typedef struct { - cl_uint major; - cl_uint minor; - cl_uint multiProcessorCount; -} OpenCLDeviceProp; - -void clMemSet(cl_command_queue, cl_mem, int, size_t); -char* readFile(const char*); - -#define CHECK_ERROR(errorMessage) \ - if(clStatus != CL_SUCCESS) \ - { \ - printf("Error: %s!\n",errorMessage); \ - printf("Line: %d\n",__LINE__); \ - exit(1); \ - } - -#endif diff --git a/tests/opencl/mri-q/ocl.c b/tests/opencl/mri-q/ocl.c deleted file mode 100644 index 61cd5fe6..00000000 --- a/tests/opencl/mri-q/ocl.c +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include -#include "ocl.h" -#include - -char* readFile(const char* fileName) -{ - FILE* fp; - fp = fopen(fileName,"r"); - if(fp == NULL) - { - printf("Error 1!\n"); - exit(1); - } - - fseek(fp,0,SEEK_END); - long size = ftell(fp); - rewind(fp); - - char* buffer = (char*)malloc(sizeof(char)*(size+1)); - if(buffer == NULL) - { - printf("Error 2!\n"); - fclose(fp); - exit(1); - } - - size_t res = fread(buffer,1,size,fp); - if(res != size) - { - printf("Error 3!\n"); - fclose(fp); - exit(1); - } - - buffer[size] = 0; - fclose(fp); - return buffer; -} - -void clMemSet(clPrmtr* clPrm, cl_mem buf, int val, size_t size) -{ - cl_int clStatus; - char* temp = (char*)malloc(size); - memset(temp,val,size); - clStatus = clEnqueueWriteBuffer(clPrm->clCommandQueue,buf,CL_TRUE,0,size,temp,0,NULL,NULL); - CHECK_ERROR("clEnqueueWriteBuffer") - free(temp); -} diff --git a/tests/opencl/mri-q/ocl.h b/tests/opencl/mri-q/ocl.h deleted file mode 100644 index ce2876a7..00000000 --- a/tests/opencl/mri-q/ocl.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __OCLH__ -#define __OCLH__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - cl_context clContext; - cl_command_queue clCommandQueue; - cl_kernel clKernel; -} clPrmtr; - -void clMemSet(clPrmtr*, cl_mem, int, size_t); -char* readFile(const char*); - -#define CHECK_ERROR(errorMessage) \ - if(clStatus != CL_SUCCESS) \ - { \ - printf("Error: %s!\n",errorMessage); \ - printf("Line: %d\n",__LINE__); \ - exit(1); \ - } - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/tests/opencl/mri-q/parboil.h b/tests/opencl/mri-q/parboil.h deleted file mode 100644 index 4c9a8b5e..00000000 --- a/tests/opencl/mri-q/parboil.h +++ /dev/null @@ -1,348 +0,0 @@ -/* - * (c) 2010 The Board of Trustees of the University of Illinois. - */ -#ifndef PARBOIL_HEADER -#define PARBOIL_HEADER - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* A platform as specified by the user on the command line */ -struct pb_PlatformParam { - char *name; /* The platform name. This string is owned. */ - char *version; /* The platform version; may be NULL. - * This string is owned. */ -}; - -/* Create a PlatformParam from the given strings. - * 'name' must not be NULL. 'version' may be NULL. - * If not NULL, the strings should have been allocated by malloc(), - * and they will be owned by the returned object. - */ -struct pb_PlatformParam * -pb_PlatformParam(char *name, char *version); - -void -pb_FreePlatformParam(struct pb_PlatformParam *); - -/* A criterion for how to select a device */ -enum pb_DeviceSelectionCriterion { - pb_Device_INDEX, /* Enumerate the devices and select one - * by its number */ - pb_Device_CPU, /* Select a CPU device */ - pb_Device_GPU, /* Select a GPU device */ - pb_Device_ACCELERATOR, /* Select an accelerator device */ - pb_Device_NAME /* Select a device by name */ -}; - -/* A device as specified by the user on the command line */ -struct pb_DeviceParam { - enum pb_DeviceSelectionCriterion criterion; - union { - int index; /* If criterion == pb_Device_INDEX, - * the index of the device */ - char *name; /* If criterion == pb_Device_NAME, - * the name of the device. - * This string is owned. */ - }; -}; - -struct pb_DeviceParam * -pb_DeviceParam_index(int index); - -struct pb_DeviceParam * -pb_DeviceParam_cpu(void); - -struct pb_DeviceParam * -pb_DeviceParam_gpu(void); - -struct pb_DeviceParam * -pb_DeviceParam_accelerator(void); - -/* Create a by-name device selection criterion. - * The string should have been allocated by malloc(), and it will will be - * owned by the returned object. - */ -struct pb_DeviceParam * -pb_DeviceParam_name(char *name); - -void -pb_FreeDeviceParam(struct pb_DeviceParam *); - -/* Command line parameters for benchmarks */ -struct pb_Parameters { - char *outFile; /* If not NULL, the raw output of the - * computation should be saved to this - * file. The string is owned. */ - char **inpFiles; /* A NULL-terminated array of strings - * holding the input file(s) for the - * computation. The array and strings - * are owned. */ - struct pb_PlatformParam *platform; /* If not NULL, the platform - * specified on the command line. */ - struct pb_DeviceParam *device; /* If not NULL, the device - * specified on the command line. */ -}; - -/* Read command-line parameters. - * - * The argc and argv parameters to main are read, and any parameters - * interpreted by this function are removed from the argument list. - * - * A new instance of struct pb_Parameters is returned. - * If there is an error, then an error message is printed on stderr - * and NULL is returned. - */ -struct pb_Parameters * -pb_ReadParameters(int *_argc, char **argv); - -/* Free an instance of struct pb_Parameters. - */ -void -pb_FreeParameters(struct pb_Parameters *p); - -void -pb_FreeStringArray(char **); - -/* Count the number of input files in a pb_Parameters instance. - */ -int -pb_Parameters_CountInputs(struct pb_Parameters *p); - -/* A time or duration. */ -//#if _POSIX_VERSION >= 200112L -typedef unsigned long long pb_Timestamp; /* time in microseconds */ -//#else -//# error "Timestamps not implemented" -//#endif - -enum pb_TimerState { - pb_Timer_STOPPED, - pb_Timer_RUNNING, -}; - -struct pb_Timer { - enum pb_TimerState state; - pb_Timestamp elapsed; /* Amount of time elapsed so far */ - pb_Timestamp init; /* Beginning of the current time interval, - * if state is RUNNING. End of the last - * recorded time interfal otherwise. */ -}; - -/* Reset a timer. - * Use this to initialize a timer or to clear - * its elapsed time. The reset timer is stopped. - */ -void -pb_ResetTimer(struct pb_Timer *timer); - -/* Start a timer. The timer is set to RUNNING mode and - * time elapsed while the timer is running is added to - * the timer. - * The timer should not already be running. - */ -void -pb_StartTimer(struct pb_Timer *timer); - -/* Stop a timer. - * This stops adding elapsed time to the timer. - * The timer should not already be stopped. - */ -void -pb_StopTimer(struct pb_Timer *timer); - -/* Get the elapsed time in seconds. */ -double -pb_GetElapsedTime(struct pb_Timer *timer); - -/* Execution time is assigned to one of these categories. */ -enum pb_TimerID { - pb_TimerID_NONE = 0, - pb_TimerID_IO, /* Time spent in input/output */ - pb_TimerID_KERNEL, /* Time spent computing on the device, - * recorded asynchronously */ - pb_TimerID_COPY, /* Time spent synchronously moving data - * to/from device and allocating/freeing - * memory on the device */ - pb_TimerID_DRIVER, /* Time spent in the host interacting with the - * driver, primarily for recording the time - * spent queueing asynchronous operations */ - pb_TimerID_COPY_ASYNC, /* Time spent in asynchronous transfers */ - pb_TimerID_COMPUTE, /* Time for all program execution other - * than parsing command line arguments, - * I/O, kernel, and copy */ - pb_TimerID_OVERLAP, /* Time double-counted in asynchronous and - * host activity: automatically filled in, - * not intended for direct usage */ - pb_TimerID_LAST /* Number of timer IDs */ -}; - -/* Dynamic list of asynchronously tracked times between events */ -struct pb_async_time_marker_list { - char *label; // actually just a pointer to a string - enum pb_TimerID timerID; /* The ID to which the interval beginning - * with this marker should be attributed */ - void * marker; - //cudaEvent_t marker; /* The driver event for this marker */ - struct pb_async_time_marker_list *next; -}; - -struct pb_SubTimer { - char *label; - struct pb_Timer timer; - struct pb_SubTimer *next; -}; - -struct pb_SubTimerList { - struct pb_SubTimer *current; - struct pb_SubTimer *subtimer_list; -}; - -/* A set of timers for recording execution times. */ -struct pb_TimerSet { - enum pb_TimerID current; - struct pb_async_time_marker_list* async_markers; - pb_Timestamp async_begin; - pb_Timestamp wall_begin; - struct pb_Timer timers[pb_TimerID_LAST]; - struct pb_SubTimerList *sub_timer_list[pb_TimerID_LAST]; -}; - -/* Reset all timers in the set. */ -void -pb_InitializeTimerSet(struct pb_TimerSet *timers); - -void -pb_AddSubTimer(struct pb_TimerSet *timers, char *label, enum pb_TimerID pb_Category); - -/* Select which timer the next interval of time should be accounted - * to. The selected timer is started and other timers are stopped. - * Using pb_TimerID_NONE stops all timers. */ -void -pb_SwitchToTimer(struct pb_TimerSet *timers, enum pb_TimerID timer); - -void -pb_SwitchToSubTimer(struct pb_TimerSet *timers, char *label, enum pb_TimerID category); - -/* Print timer values to standard output. */ -void -pb_PrintTimerSet(struct pb_TimerSet *timers); - -/* Release timer resources */ -void -pb_DestroyTimerSet(struct pb_TimerSet * timers); - -void -pb_SetOpenCL(void *clContextPtr, void *clCommandQueuePtr); - - -typedef struct pb_Device_tag { - char* name; - void* clDevice; - int id; - unsigned int in_use; - unsigned int available; -} pb_Device; - -struct pb_Context_tag; -typedef struct pb_Context_tag pb_Context; - -typedef struct pb_Platform_tag { - char* name; - char* version; - void* clPlatform; - unsigned int in_use; - pb_Context** contexts; - pb_Device** devices; -} pb_Platform; - -struct pb_Context_tag { - void* clPlatformId; - void* clContext; - void* clDeviceId; - pb_Platform* pb_platform; - pb_Device* pb_device; -}; - -// verbosely print out list of platforms and their devices to the console. -pb_Platform** -pb_GetPlatforms(); - -// Choose a platform according to the given platform specification -pb_Platform* -pb_GetPlatform(struct pb_PlatformParam *platform); - -// choose a platform: by name, name & version -pb_Platform* -pb_GetPlatformByName(const char* name); - -pb_Platform* -pb_GetPlatformByNameAndVersion(const char* name, const char* version); - -// Choose a device according to the given device specification -pb_Device* -pb_GetDevice(pb_Platform* pb_platform, struct pb_DeviceParam *device); - -pb_Device** -pb_GetDevices(pb_Platform* pb_platform); - -// choose a device by name. -pb_Device* -pb_GetDeviceByName(pb_Platform* pb_platform, const char* name); - -pb_Platform* -pb_GetPlatformByEnvVars(); - -pb_Context* -pb_InitOpenCLContext(struct pb_Parameters* parameters); - -void -pb_ReleasePlatforms(); - -void -pb_ReleaseContext(pb_Context* c); - -void -pb_PrintPlatformInfo(pb_Context* c); - -void -perf_init(); - -//#define MEASURE_KERNEL_TIME - -#include - -#ifdef MEASURE_KERNEL_TIME -#define clEnqueueNDRangeKernel(q,k,d,o,dg,db,a,b,c) pb_clEnqueueNDRangeKernel((q), (k), (d), (o), (dg), (db), (a), (b), (c)) -cl_int -pb_clEnqueueNDRangeKernel(cl_command_queue /* command_queue */, - cl_kernel /* kernel */, - cl_uint /* work_dim */, - const size_t * /* global_work_offset */, - const size_t * /* global_work_size */, - const size_t * /* local_work_size */, - cl_uint /* num_events_in_wait_list */, - const cl_event * /* event_wait_list */, - cl_event * /* event */); -#endif - -enum { T_FLOAT, T_DOUBLE, T_SHORT, T_INT, T_UCHAR }; -void pb_sig_float(char*, float*, int); -void pb_sig_double(char*, double*, int); -void pb_sig_short(char*, short*, int); -void pb_sig_int(char*, int*, int); -void pb_sig_uchar(char*, unsigned char*, unsigned int); -void pb_sig_clmem(char*, cl_command_queue, cl_mem, int); - -#ifdef __cplusplus -} -#endif - -#endif //PARBOIL_HEADER - diff --git a/tests/opencl/mri-q/parboil_opencl.c b/tests/opencl/mri-q/parboil_opencl.c deleted file mode 100644 index a4db1680..00000000 --- a/tests/opencl/mri-q/parboil_opencl.c +++ /dev/null @@ -1,1394 +0,0 @@ -/* - * (c) 2007 The Board of Trustees of the University of Illinois. - */ - -#include -#include -#include -#include -#include -#include - -#if _POSIX_VERSION >= 200112L -# include -#endif - -//#include "perfmon.h" - -cl_context *clContextPtr; -cl_command_queue *clCommandQueuePtr; - -// #define DISABLE_PARBOIL_TIMER - -/*****************************************************************************/ -/* Timer routines */ - -static int is_async(enum pb_TimerID timer) -{ - return (timer == pb_TimerID_KERNEL) || - (timer == pb_TimerID_COPY_ASYNC); -} - -static int is_blocking(enum pb_TimerID timer) -{ - return (timer == pb_TimerID_COPY) || (timer == pb_TimerID_NONE); -} - -#define INVALID_TIMERID pb_TimerID_LAST - -static int asyncs_outstanding(struct pb_TimerSet* timers) -{ - return (timers->async_markers != NULL) && - (timers->async_markers->timerID != INVALID_TIMERID); -} - -static struct pb_async_time_marker_list * -get_last_async(struct pb_TimerSet* timers) -{ - /* Find the last event recorded thus far */ - struct pb_async_time_marker_list * last_event = timers->async_markers; - if(last_event != NULL && last_event->timerID != INVALID_TIMERID) { - while(last_event->next != NULL && - last_event->next->timerID != INVALID_TIMERID) - last_event = last_event->next; - return last_event; - } else - return NULL; -} - -static void insert_marker(struct pb_TimerSet* tset, enum pb_TimerID timer) -{ - cl_int ciErrNum = CL_SUCCESS; - struct pb_async_time_marker_list ** new_event = &(tset->async_markers); - - while(*new_event != NULL && (*new_event)->timerID != INVALID_TIMERID) { - new_event = &((*new_event)->next); - } - - if(*new_event == NULL) { - *new_event = (struct pb_async_time_marker_list *) - malloc(sizeof(struct pb_async_time_marker_list)); - (*new_event)->marker = calloc(1, sizeof(cl_event)); - /* - // I don't think this is needed at all. I believe clEnqueueMarker 'creates' the event -#if ( __OPENCL_VERSION__ >= CL_VERSION_1_1 ) -fprintf(stderr, "Creating Marker [%d]\n", timer); - *((cl_event *)((*new_event)->marker)) = clCreateUserEvent(*clContextPtr, &ciErrNum); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Creating User Event Object!\n"); - } - ciErrNum = clSetUserEventStatus(*((cl_event *)((*new_event)->marker)), CL_QUEUED); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Setting User Event Status!\n"); - } -#endif -*/ - (*new_event)->next = NULL; - } - - /* valid event handle now aquired: insert the event record */ - (*new_event)->label = NULL; - (*new_event)->timerID = timer; - ciErrNum = clEnqueueMarker(*clCommandQueuePtr, (cl_event *)(*new_event)->marker); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Enqueueing Marker!\n"); - } - -} - -static void insert_submarker(struct pb_TimerSet* tset, char *label, enum pb_TimerID timer) -{ - cl_int ciErrNum = CL_SUCCESS; - struct pb_async_time_marker_list ** new_event = &(tset->async_markers); - - while(*new_event != NULL && (*new_event)->timerID != INVALID_TIMERID) { - new_event = &((*new_event)->next); - } - - if(*new_event == NULL) { - *new_event = (struct pb_async_time_marker_list *) - malloc(sizeof(struct pb_async_time_marker_list)); - (*new_event)->marker = calloc(1, sizeof(cl_event)); - /* -#if ( __OPENCL_VERSION__ >= CL_VERSION_1_1 ) -fprintf(stderr, "Creating SubMarker %s[%d]\n", label, timer); - *((cl_event *)((*new_event)->marker)) = clCreateUserEvent(*clContextPtr, &ciErrNum); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Creating User Event Object!\n"); - } - ciErrNum = clSetUserEventStatus(*((cl_event *)((*new_event)->marker)), CL_QUEUED); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Setting User Event Status!\n"); - } -#endif -*/ - (*new_event)->next = NULL; - } - - /* valid event handle now aquired: insert the event record */ - (*new_event)->label = label; - (*new_event)->timerID = timer; - ciErrNum = clEnqueueMarker(*clCommandQueuePtr, (cl_event *)(*new_event)->marker); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Enqueueing Marker!\n"); - } - -} - - -/* Assumes that all recorded events have completed */ -static pb_Timestamp record_async_times(struct pb_TimerSet* tset) -{ - struct pb_async_time_marker_list * next_interval = NULL; - struct pb_async_time_marker_list * last_marker = get_last_async(tset); - pb_Timestamp total_async_time = 0; - enum pb_TimerID timer; - - for(next_interval = tset->async_markers; next_interval != last_marker; - next_interval = next_interval->next) { - cl_ulong command_start=0, command_end=0; - cl_int ciErrNum = CL_SUCCESS; - - ciErrNum = clGetEventProfilingInfo(*((cl_event *)next_interval->marker), CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &command_start, NULL); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error getting first EventProfilingInfo: %d\n", ciErrNum); - } - - ciErrNum = clGetEventProfilingInfo(*((cl_event *)next_interval->next->marker), CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &command_end, NULL); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error getting second EventProfilingInfo: %d\n", ciErrNum); - } - - pb_Timestamp interval = (pb_Timestamp) (((double)(command_end - command_start)) / 1e3); - tset->timers[next_interval->timerID].elapsed += interval; - if (next_interval->label != NULL) { - struct pb_SubTimer *subtimer = tset->sub_timer_list[next_interval->timerID]->subtimer_list; - while (subtimer != NULL) { - if ( strcmp(subtimer->label, next_interval->label) == 0) { - subtimer->timer.elapsed += interval; - break; - } - subtimer = subtimer->next; - } - } - total_async_time += interval; - next_interval->timerID = INVALID_TIMERID; - } - - if(next_interval != NULL) - next_interval->timerID = INVALID_TIMERID; - - return total_async_time; -} - -static void -accumulate_time(pb_Timestamp *accum, - pb_Timestamp start, - pb_Timestamp end) -{ -//#if _POSIX_VERSION >= 200112L - *accum += end - start; -//#else -//# error "Timestamps not implemented for this system" -//#endif -} - -//#if _POSIX_VERSION >= 200112L -static pb_Timestamp get_time() -{ - //struct timeval tv; - //gettimeofday(&tv, NULL); - //return (pb_Timestamp) (tv.tv_sec * 1000000LL + tv.tv_usec); - return 0; -} -//#else -//# error "no supported time libraries are available on this platform" -//#endif - -void -pb_ResetTimer(struct pb_Timer *timer) -{ -//#ifndef DISABLE_PARBOIL_TIMER - timer->state = pb_Timer_STOPPED; - -//#if _POSIX_VERSION >= 200112L - timer->elapsed = 0; -//#else -//# error "pb_ResetTimer: not implemented for this system" -//#endif -//#endif -} - -void -pb_StartTimer(struct pb_Timer *timer) -{ -/*#ifndef DISABLE_PARBOIL_TIMER - if (timer->state != pb_Timer_STOPPED) { - fputs("Ignoring attempt to start a running timer\n", stderr); - return; - } - - timer->state = pb_Timer_RUNNING; - -#if _POSIX_VERSION >= 200112L - { - struct timeval tv; - gettimeofday(&tv, NULL); - timer->init = tv.tv_sec * 1000000LL + tv.tv_usec; - } -#else -# error "pb_StartTimer: not implemented for this system" -#endif -#endif*/ -} - -void -pb_StartTimerAndSubTimer(struct pb_Timer *timer, struct pb_Timer *subtimer) -{ -/*#ifndef DISABLE_PARBOIL_TIMER - - unsigned int numNotStopped = 0x3; // 11 - if (timer->state != pb_Timer_STOPPED) { - fputs("Warning: Timer was not stopped\n", stderr); - numNotStopped &= 0x1; // Zero out 2^1 - } - if (subtimer->state != pb_Timer_STOPPED) { - fputs("Warning: Subtimer was not stopped\n", stderr); - numNotStopped &= 0x2; // Zero out 2^0 - } - if (numNotStopped == 0x0) { - fputs("Ignoring attempt to start running timer and subtimer\n", stderr); - return; - } - - timer->state = pb_Timer_RUNNING; - subtimer->state = pb_Timer_RUNNING; - -#if _POSIX_VERSION >= 200112L - { - struct timeval tv; - gettimeofday(&tv, NULL); - - if (numNotStopped & 0x2) { - timer->init = tv.tv_sec * 1000000LL + tv.tv_usec; - } - - if (numNotStopped & 0x1) { - subtimer->init = tv.tv_sec * 1000000LL + tv.tv_usec; - } - } -#else -# error "pb_StartTimer: not implemented for this system" -#endif - -#endif*/ -} - -void -pb_StopTimer(struct pb_Timer *timer) -{ -/*#ifndef DISABLE_PARBOIL_TIMER - - pb_Timestamp fini; - - if (timer->state != pb_Timer_RUNNING) { - fputs("Ignoring attempt to stop a stopped timer\n", stderr); - return; - } - - timer->state = pb_Timer_STOPPED; - -#if _POSIX_VERSION >= 200112L - { - struct timeval tv; - gettimeofday(&tv, NULL); - fini = tv.tv_sec * 1000000LL + tv.tv_usec; - } -#else -# error "pb_StopTimer: not implemented for this system" -#endif - - accumulate_time(&timer->elapsed, timer->init, fini); - timer->init = fini; - -#endif*/ -} - -void pb_StopTimerAndSubTimer(struct pb_Timer *timer, struct pb_Timer *subtimer) { -/*#ifndef DISABLE_PARBOIL_TIMER - - pb_Timestamp fini; - - unsigned int numNotRunning = 0x3; // 11 - if (timer->state != pb_Timer_RUNNING) { - fputs("Warning: Timer was not running\n", stderr); - numNotRunning &= 0x1; // Zero out 2^1 - } - if (subtimer->state != pb_Timer_RUNNING) { - fputs("Warning: Subtimer was not running\n", stderr); - numNotRunning &= 0x2; // Zero out 2^0 - } - if (numNotRunning == 0x0) { - fputs("Ignoring attempt to stop stopped timer and subtimer\n", stderr); - return; - } - - - timer->state = pb_Timer_STOPPED; - subtimer->state = pb_Timer_STOPPED; - -#if _POSIX_VERSION >= 200112L - { - struct timeval tv; - gettimeofday(&tv, NULL); - fini = tv.tv_sec * 1000000LL + tv.tv_usec; - } -#else -# error "pb_StopTimer: not implemented for this system" -#endif - - if (numNotRunning & 0x2) { - accumulate_time(&timer->elapsed, timer->init, fini); - timer->init = fini; - } - - if (numNotRunning & 0x1) { - accumulate_time(&subtimer->elapsed, subtimer->init, fini); - subtimer->init = fini; - } - -#endif*/ -} - -/* Get the elapsed time in seconds. */ -double -pb_GetElapsedTime(struct pb_Timer *timer) -{ - /*double ret; -#ifndef DISABLE_PARBOIL_TIMER - - if (timer->state != pb_Timer_STOPPED) { - fputs("Elapsed time from a running timer is inaccurate\n", stderr); - } - -#if _POSIX_VERSION >= 200112L - ret = timer->elapsed / 1e6; -#else -# error "pb_GetElapsedTime: not implemented for this system" -#endif -#endif - return ret;*/ - return 0; -} - -void -pb_InitializeTimerSet(struct pb_TimerSet *timers) -{ -/*#ifndef DISABLE_PARBOIL_TIMER - int n; - - timers->wall_begin = 0; //get_time(); - timers->current = pb_TimerID_NONE; - - timers->async_markers = NULL; - - for (n = 0; n < pb_TimerID_LAST; n++) { - pb_ResetTimer(&timers->timers[n]); - timers->sub_timer_list[n] = NULL; - } -#endif*/ -} - -void pb_SetOpenCL(void *p_clContextPtr, void *p_clCommandQueuePtr) { - clContextPtr = ((cl_context *)p_clContextPtr); - clCommandQueuePtr = ((cl_command_queue *)p_clCommandQueuePtr); -} - -void -pb_AddSubTimer(struct pb_TimerSet *timers, char *label, enum pb_TimerID pb_Category) { -/*#ifndef DISABLE_PARBOIL_TIMER - - struct pb_SubTimer *subtimer = (struct pb_SubTimer *) malloc - (sizeof(struct pb_SubTimer)); - - int len = strlen(label); - - subtimer->label = (char *) malloc (sizeof(char)*(len+1)); - sprintf(subtimer->label, "%s\0", label); - - pb_ResetTimer(&subtimer->timer); - subtimer->next = NULL; - - struct pb_SubTimerList *subtimerlist = timers->sub_timer_list[pb_Category]; - if (subtimerlist == NULL) { - subtimerlist = (struct pb_SubTimerList *) calloc - (1, sizeof(struct pb_SubTimerList)); - subtimerlist->subtimer_list = subtimer; - timers->sub_timer_list[pb_Category] = subtimerlist; - } else { - // Append to list - struct pb_SubTimer *element = subtimerlist->subtimer_list; - while (element->next != NULL) { - element = element->next; - } - element->next = subtimer; - } - -#endif*/ -} - -void -pb_SwitchToTimer(struct pb_TimerSet *timers, enum pb_TimerID timer) -{ -#if 0 -#ifndef DISABLE_PARBOIL_TIMER - - /* Stop the currently running timer */ - if (timers->current != pb_TimerID_NONE) { - struct pb_SubTimerList *subtimerlist = timers->sub_timer_list[timers->current]; - struct pb_SubTimer *currSubTimer = (subtimerlist != NULL) ? subtimerlist->current : NULL; - - if (!is_async(timers->current) ) { - if (timers->current != timer) { - if (currSubTimer != NULL) { - pb_StopTimerAndSubTimer(&timers->timers[timers->current], &currSubTimer->timer); - } else { - pb_StopTimer(&timers->timers[timers->current]); - } - } else { - if (currSubTimer != NULL) { - pb_StopTimer(&currSubTimer->timer); - } - } - } else { - insert_marker(timers, timer); - if (!is_async(timer)) { // if switching to async too, keep driver going - pb_StopTimer(&timers->timers[pb_TimerID_DRIVER]); - } - } - } - - pb_Timestamp currentTime = 0; //get_time(); - - /* The only cases we check for asynchronous task completion is - * when an overlapping CPU operation completes, or the next - * segment blocks on completion of previous async operations */ - if( asyncs_outstanding(timers) && - (!is_async(timers->current) || is_blocking(timer) ) ) { - - struct pb_async_time_marker_list * last_event = get_last_async(timers); - /* CL_COMPLETE if completed */ - - cl_int ciErrNum = CL_SUCCESS; - cl_int async_done = CL_COMPLETE; - - ciErrNum = clGetEventInfo(*((cl_event *)last_event->marker), CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(cl_int), &async_done, NULL); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Querying EventInfo!\n"); - } - - - if(is_blocking(timer)) { - /* Async operations completed after previous CPU operations: - * overlapped time is the total CPU time since this set of async - * operations were first issued */ - - // timer to switch to is COPY or NONE - if(async_done != CL_COMPLETE) { - accumulate_time(&(timers->timers[pb_TimerID_OVERLAP].elapsed), - timers->async_begin,currentTime); - } - - /* Wait on async operation completion */ - ciErrNum = clWaitForEvents(1, (cl_event *)last_event->marker); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Waiting for Events!\n"); - } - - pb_Timestamp total_async_time = record_async_times(timers); - - /* Async operations completed before previous CPU operations: - * overlapped time is the total async time */ - if(async_done == CL_COMPLETE) { - //fprintf(stderr, "Async_done: total_async_type = %lld\n", total_async_time); - timers->timers[pb_TimerID_OVERLAP].elapsed += total_async_time; - } - - } else - /* implies (!is_async(timers->current) && asyncs_outstanding(timers)) */ - // i.e. Current Not Async (not KERNEL/COPY_ASYNC) but there are outstanding - // so something is deeper in stack - if(async_done == CL_COMPLETE ) { - /* Async operations completed before previous CPU operations: - * overlapped time is the total async time */ - timers->timers[pb_TimerID_OVERLAP].elapsed += record_async_times(timers); - } - } - - /* Start the new timer */ - if (timer != pb_TimerID_NONE) { - if(!is_async(timer)) { - pb_StartTimer(&timers->timers[timer]); - } else { - // toSwitchTo Is Async (KERNEL/COPY_ASYNC) - if (!asyncs_outstanding(timers)) { - /* No asyncs outstanding, insert a fresh async marker */ - - insert_marker(timers, timer); - timers->async_begin = currentTime; - } else if(!is_async(timers->current)) { - /* Previous asyncs still in flight, but a previous SwitchTo - * already marked the end of the most recent async operation, - * so we can rename that marker as the beginning of this async - * operation */ - - struct pb_async_time_marker_list * last_event = get_last_async(timers); - last_event->label = NULL; - last_event->timerID = timer; - } - if (!is_async(timers->current)) { - pb_StartTimer(&timers->timers[pb_TimerID_DRIVER]); - } - } - } - timers->current = timer; - -#endif -#endif -} - -void -pb_SwitchToSubTimer(struct pb_TimerSet *timers, char *label, enum pb_TimerID category) -{ -#if 0 -#ifndef DISABLE_PARBOIL_TIMER - struct pb_SubTimerList *subtimerlist = timers->sub_timer_list[timers->current]; - struct pb_SubTimer *curr = (subtimerlist != NULL) ? subtimerlist->current : NULL; - - if (timers->current != pb_TimerID_NONE) { - if (!is_async(timers->current) ) { - if (timers->current != category) { - if (curr != NULL) { - pb_StopTimerAndSubTimer(&timers->timers[timers->current], &curr->timer); - } else { - pb_StopTimer(&timers->timers[timers->current]); - } - } else { - if (curr != NULL) { - pb_StopTimer(&curr->timer); - } - } - } else { - insert_submarker(timers, label, category); - if (!is_async(category)) { // if switching to async too, keep driver going - pb_StopTimer(&timers->timers[pb_TimerID_DRIVER]); - } - } - } - - pb_Timestamp currentTime = 0; //get_time(); - - /* The only cases we check for asynchronous task completion is - * when an overlapping CPU operation completes, or the next - * segment blocks on completion of previous async operations */ - if( asyncs_outstanding(timers) && - (!is_async(timers->current) || is_blocking(category) ) ) { - - struct pb_async_time_marker_list * last_event = get_last_async(timers); - /* CL_COMPLETE if completed */ - - cl_int ciErrNum = CL_SUCCESS; - cl_int async_done = CL_COMPLETE; - - ciErrNum = clGetEventInfo(*((cl_event *)last_event->marker), CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(cl_int), &async_done, NULL); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Querying EventInfo!\n"); - } - - if(is_blocking(category)) { - /* Async operations completed after previous CPU operations: - * overlapped time is the total CPU time since this set of async - * operations were first issued */ - - // timer to switch to is COPY or NONE - // if it hasn't already finished, then just take now and use that as the elapsed time in OVERLAP - // anything happening after now isn't OVERLAP because everything is being stopped to wait for synchronization - // it seems that the extra sync wall time isn't being recorded anywhere - if(async_done != CL_COMPLETE) - accumulate_time(&(timers->timers[pb_TimerID_OVERLAP].elapsed), - timers->async_begin,currentTime); - - /* Wait on async operation completion */ - ciErrNum = clWaitForEvents(1, (cl_event *)last_event->marker); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Waiting for Events!\n"); - } - pb_Timestamp total_async_time = record_async_times(timers); - - /* Async operations completed before previous CPU operations: - * overlapped time is the total async time */ - // If it did finish, then accumulate all the async time that did happen into OVERLAP - // the immediately preceding EventSynchronize theoretically didn't have any effect since it was already completed. - if(async_done == CL_COMPLETE /*cudaSuccess*/) - timers->timers[pb_TimerID_OVERLAP].elapsed += total_async_time; - - } else - /* implies (!is_async(timers->current) && asyncs_outstanding(timers)) */ - // i.e. Current Not Async (not KERNEL/COPY_ASYNC) but there are outstanding - // so something is deeper in stack - if(async_done == CL_COMPLETE /*cudaSuccess*/) { - /* Async operations completed before previous CPU operations: - * overlapped time is the total async time */ - timers->timers[pb_TimerID_OVERLAP].elapsed += record_async_times(timers); - } - // else, this isn't blocking, so just check the next time around - } - - subtimerlist = timers->sub_timer_list[category]; - struct pb_SubTimer *subtimer = NULL; - - if (label != NULL) { - subtimer = subtimerlist->subtimer_list; - while (subtimer != NULL) { - if (strcmp(subtimer->label, label) == 0) { - break; - } else { - subtimer = subtimer->next; - } - } - } - - /* Start the new timer */ - if (category != pb_TimerID_NONE) { - if(!is_async(category)) { - if (subtimerlist != NULL) { - subtimerlist->current = subtimer; - } - - if (category != timers->current && subtimer != NULL) { - pb_StartTimerAndSubTimer(&timers->timers[category], &subtimer->timer); - } else if (subtimer != NULL) { - pb_StartTimer(&subtimer->timer); - } else { - pb_StartTimer(&timers->timers[category]); - } - } else { - if (subtimerlist != NULL) { - subtimerlist->current = subtimer; - } - - // toSwitchTo Is Async (KERNEL/COPY_ASYNC) - if (!asyncs_outstanding(timers)) { - /* No asyncs outstanding, insert a fresh async marker */ - insert_submarker(timers, label, category); - timers->async_begin = currentTime; - } else if(!is_async(timers->current)) { - /* Previous asyncs still in flight, but a previous SwitchTo - * already marked the end of the most recent async operation, - * so we can rename that marker as the beginning of this async - * operation */ - - struct pb_async_time_marker_list * last_event = get_last_async(timers); - last_event->timerID = category; - last_event->label = label; - } // else, marker for switchToThis was already inserted - - //toSwitchto is already asynchronous, but if current/prev state is async too, then DRIVER is already running - if (!is_async(timers->current)) { - pb_StartTimer(&timers->timers[pb_TimerID_DRIVER]); - } - } - } - - timers->current = category; -#endif -#endif -} - -void -pb_PrintTimerSet(struct pb_TimerSet *timers) -{ -#if 0 -#ifndef DISABLE_PARBOIL_TIMER - pb_Timestamp wall_end = 0; //get_time(); - - struct pb_Timer *t = timers->timers; - struct pb_SubTimer* sub = NULL; - - int maxSubLength; - - const char *categories[] = { - "IO", "Kernel", "Copy", "Driver", "Copy Async", "Compute" - }; - - const int maxCategoryLength = 10; - - int i; - for(i = 1; i < pb_TimerID_LAST-1; ++i) { // exclude NONE and OVRELAP from this format - if(pb_GetElapsedTime(&t[i]) != 0) { - - // Print Category Timer - printf("%-*s: %f\n", maxCategoryLength, categories[i-1], pb_GetElapsedTime(&t[i])); - - if (timers->sub_timer_list[i] != NULL) { - sub = timers->sub_timer_list[i]->subtimer_list; - maxSubLength = 0; - while (sub != NULL) { - // Find longest SubTimer label - if (strlen(sub->label) > maxSubLength) { - maxSubLength = strlen(sub->label); - } - sub = sub->next; - } - - // Fit to Categories - if (maxSubLength <= maxCategoryLength) { - maxSubLength = maxCategoryLength; - } - - sub = timers->sub_timer_list[i]->subtimer_list; - - // Print SubTimers - while (sub != NULL) { - printf(" -%-*s: %f\n", maxSubLength, sub->label, pb_GetElapsedTime(&sub->timer)); - sub = sub->next; - } - } - } - } - - if(pb_GetElapsedTime(&t[pb_TimerID_OVERLAP]) != 0) - printf("CPU/Kernel Overlap: %f\n", pb_GetElapsedTime(&t[pb_TimerID_OVERLAP])); - - float walltime = (wall_end - timers->wall_begin)/ 1e6; - printf("Timer Wall Time: %f\n", walltime); - -#endif -#endif -} - -void pb_DestroyTimerSet(struct pb_TimerSet * timers) -{ -#ifndef DISABLE_PARBOIL_TIMER - /* clean up all of the async event markers */ - struct pb_async_time_marker_list* event = timers->async_markers; - while(event != NULL) { - - cl_int ciErrNum = CL_SUCCESS; - ciErrNum = clWaitForEvents(1, (cl_event *)(event)->marker); - if (ciErrNum != CL_SUCCESS) { - //fprintf(stderr, "Error Waiting for Events!\n"); - } - - ciErrNum = clReleaseEvent( *((cl_event *)(event)->marker) ); - if (ciErrNum != CL_SUCCESS) { - fprintf(stderr, "Error Release Events!\n"); - } - - free((event)->marker); - struct pb_async_time_marker_list* next = ((event)->next); - - free(event); - - // (*event) = NULL; - event = next; - } - - int i = 0; - for(i = 0; i < pb_TimerID_LAST; ++i) { - if (timers->sub_timer_list[i] != NULL) { - struct pb_SubTimer *subtimer = timers->sub_timer_list[i]->subtimer_list; - struct pb_SubTimer *prev = NULL; - while (subtimer != NULL) { - free(subtimer->label); - prev = subtimer; - subtimer = subtimer->next; - free(prev); - } - free(timers->sub_timer_list[i]); - } - } -#endif -} - -static pb_Platform** ptr = NULL; - -// verbosely print out list of platforms and their devices to the console. -pb_Platform** -pb_GetPlatforms() { - if (ptr == NULL) { - cl_uint num_platforms; - clGetPlatformIDs(0, NULL, &num_platforms); - if (num_platforms == 0) return NULL; - - ptr = (pb_Platform **) malloc(sizeof(pb_Platform *) * (num_platforms + 1)); - cl_platform_id* ids = (cl_platform_id *) malloc(num_platforms * sizeof(cl_platform_id)); - clGetPlatformIDs(num_platforms, ids, NULL); - - unsigned int i; - for (i = 0; i < num_platforms; i++) { - ptr[i] = (pb_Platform *) malloc(sizeof(pb_Platform)); - ptr[i]->clPlatform = ids[i]; - ptr[i]->contexts = NULL; - ptr[i]->in_use = 0; - ptr[i]->devices = NULL; - - size_t sz; - clGetPlatformInfo(ids[i], CL_PLATFORM_NAME, 0, NULL, &sz); - char* name = (char *) malloc(sz + 1); - clGetPlatformInfo(ids[i], CL_PLATFORM_NAME, sz, name, NULL); - name[sz] = '\0'; - ptr[i]->name = name; - - clGetPlatformInfo(ids[i], CL_PLATFORM_VERSION, 0, NULL, &sz); - char* version = (char *) malloc(sz + 1); - clGetPlatformInfo(ids[i], CL_PLATFORM_VERSION, sz, version, NULL); - version[sz] = '\0'; - ptr[i]->version = version; - } - ptr[i] = NULL; - - free(ids); - } - - return (pb_Platform**) ptr; -} - -pb_Context* -createContext(pb_Platform* pb_platform, pb_Device* pb_device) { - pb_Context* c = (pb_Context*) malloc(sizeof(pb_Context)); - cl_int clStatus; - cl_context_properties clCps[3] = { - CL_CONTEXT_PLATFORM, (cl_context_properties)(pb_platform->clPlatform), 0 - }; - c->clContext = - clCreateContext(clCps, 1, (cl_device_id*)&pb_device->clDevice, NULL, NULL, &clStatus); - c->clPlatformId = pb_platform->clPlatform; - c->clDeviceId = pb_device->clDevice; - c->pb_platform = pb_platform; - c->pb_device = pb_device; - pb_platform->in_use = 1; - pb_device->in_use = 1; - unsigned int i = 0; - if (pb_platform->contexts == NULL) { - pb_platform->contexts = (pb_Context**) malloc(2*sizeof(pb_Context*)); - } else { - for (i = 0; pb_platform->contexts[i] != NULL; i++) {}; - pb_platform->contexts = (pb_Context**) realloc(pb_platform->contexts, - (i+1)*sizeof(pb_Context*)); - } - pb_platform->contexts[i+1] = NULL; - pb_platform->contexts[i] = c; - return c; -} - -// choose a platform by name. -pb_Platform* -pb_GetPlatformByName(const char* name) { - pb_Platform** ps = (pb_Platform **) pb_GetPlatforms(); - if (ps == NULL) return NULL; - if (name == NULL) { - return *ps; - } - - while (*ps) { - if (strstr((*ps)->name, name)) break; - ps++; - } - return (pb_Platform*) *ps; -} - -pb_Device** -pb_GetDevices(pb_Platform* pb_platform) { - if (pb_platform->devices == NULL) { - cl_uint num_devs; - cl_device_id* dev_ids; - clGetDeviceIDs((cl_platform_id) pb_platform->clPlatform, - CL_DEVICE_TYPE_ALL, 0, NULL, &num_devs); - if (num_devs == 0) return NULL; - - pb_platform->devices = - (pb_Device **) malloc((num_devs + 1) * sizeof(pb_Device *)); - dev_ids = (cl_device_id *) malloc(sizeof(cl_device_id) * num_devs); - clGetDeviceIDs((cl_platform_id) pb_platform->clPlatform, - CL_DEVICE_TYPE_ALL, num_devs, dev_ids, NULL); - - unsigned int i; - for (i = 0; i < num_devs; i++) { - pb_platform->devices[i] = (pb_Device *) malloc(sizeof(pb_Device)); - - pb_platform->devices[i]->clDevice = dev_ids[i]; - pb_platform->devices[i]->id = i; - - size_t sz; - clGetDeviceInfo(dev_ids[i], CL_DEVICE_NAME, 0, NULL, &sz); - char* name = (char *) malloc(sz + 1); - clGetDeviceInfo(dev_ids[i], CL_DEVICE_NAME, sz, name, NULL); - name[sz] = '\0'; - pb_platform->devices[i]->name = (char *) name; - - cl_bool available; - clGetDeviceInfo(dev_ids[i], CL_DEVICE_AVAILABLE, sizeof(cl_bool), &available, NULL); - pb_platform->devices[i]->available = (int) available; - - pb_platform->devices[i]->in_use = 0; - } - pb_platform->devices[i] = NULL; - } - return (pb_Device **) pb_platform->devices; -} - -// choose a device by name. -static pb_Device* -pb_SelectDeviceByName(pb_Device **ds, const char* name) { - if (ds == NULL) return NULL; - if (name == NULL) return *ds; - while (*ds) { - if (strstr((*ds)->name, name)) break; - ds++; - } - - return *ds; -} - -// choose a device by name and set the device's 'in_use' flag. -pb_Device* -pb_GetDeviceByName(pb_Platform* pb_platform, const char* name) { - pb_Device** ds = (pb_Device **) pb_GetDevices(pb_platform); - pb_Device *d = pb_SelectDeviceByName(ds, name); - - if (d) d->in_use = 1; - - return d; -} - -void -pb_ReleasePlatforms() { - if (!ptr) return; - pb_Platform** cur_ptr = ptr; - while (*cur_ptr) { - pb_Platform* pfptr = *cur_ptr++; - if (pfptr->devices) { - pb_Device** dvptr = pfptr->devices; - while (*dvptr) { - pb_Device* d = *dvptr++; - free(d->name); - free(d); - } - free(pfptr->devices); - } - if (pfptr->contexts) { - pb_Context** cptr = pfptr->contexts; - while (*cptr) { - free(*cptr++); - } - free(pfptr->contexts); - } - free(pfptr->name); - free(pfptr); - } - free(ptr); - ptr = NULL; -} - -pb_Platform* -pb_GetPlatformByNameAndVersion(const char* name, const char* version) { - pb_Platform** ps = (pb_Platform **) pb_GetPlatforms(); - if (ps == NULL) return NULL; - if (name == NULL) return *ps; - while (*ps) { - if (strstr((*ps)->name, name) && strstr((*ps)->version, version)) break; - ps++; - } - return (pb_Platform*) *ps; -} - -/* Return a pointer to the device at the specified index, or NULL. - * Used by pb_GetDevice. */ -static pb_Device * -select_device_by_index(pb_Device** ds, int id) -{ - int i = 0; - pb_Device** p = ds; - while (*p && (i < id)) { p++; i++; } - return *p; -} - -/* Return a pointer to the device with the specified type, or NULL. - * Used by pb_GetDevice. */ -static pb_Device * -select_device_by_type(pb_Device** ds, - enum pb_DeviceSelectionCriterion criterion) -{ - cl_device_type sought_type; - - /* Determine the OpenCL device type to search for */ - switch(criterion) { - case pb_Device_CPU: - sought_type = CL_DEVICE_TYPE_CPU; - break; - case pb_Device_GPU: - sought_type = CL_DEVICE_TYPE_GPU; - break; - case pb_Device_ACCELERATOR: - sought_type = CL_DEVICE_TYPE_ACCELERATOR; - break; - default: - fprintf(stderr, "pb_GetDevice: Invalid device type"); - exit(-1); - } - - /* Find the device */ - { - pb_Device** p = ds; - cl_device_type type; - while (*p) { - clGetDeviceInfo(((cl_device_id) ((*p)->clDevice)), CL_DEVICE_TYPE, - sizeof(cl_device_type), &type, NULL); - if (type == sought_type) break; - } - - return *p; - } -} - -pb_Device* -pb_GetDevice(pb_Platform* pb_platform, struct pb_DeviceParam *device) -{ - pb_Device** ds = (pb_Device **) pb_GetDevices(pb_platform); - - // The list of devices must be nonempty - if (ds == NULL || *ds == NULL) { - fprintf(stderr, "Error: No device is found in platform: name = %s, version = %s\n.", pb_platform->name, pb_platform->version); - exit(-1); - } - - pb_Device *selected_device = NULL; - - if (device != NULL) { - /* Use 'device' to select and return a device. - * If unable to select a device, fall - * back on the default selection mechanism. */ - switch(device->criterion) { - case pb_Device_INDEX: - selected_device = select_device_by_index(ds, device->index); - break; - case pb_Device_GPU: - case pb_Device_CPU: - case pb_Device_ACCELERATOR: - selected_device = select_device_by_type(ds, device->criterion); - break; - case pb_Device_NAME: - selected_device = pb_SelectDeviceByName(ds, device->name); - break; - default: - fprintf(stderr, "pb_GetDevice: Invalid argument"); - exit(-1); - } - } - - /* By default or if user-specified selection failed, - * select the first device */ - if (selected_device == NULL) - selected_device = *ds; - - /* Set the in_use flag */ - selected_device->in_use = 1; - - return selected_device; -} - -pb_Device* -pb_GetDeviceByEnvVars(pb_Platform* pb_platform) { - - /* Convert environment variables to a 'pb_DeviceParam' */ - struct pb_DeviceParam *param = NULL; - - char* device_num = getenv("PARBOIL_DEVICE_NUMBER"); - if (device_num && strcmp(device_num, "")) { - int id = atoi(device_num); - param = pb_DeviceParam_index(id); - } - else { - char* device_name = getenv("PARBOIL_DEVICE_NAME"); - if (device_name && strcmp(device_name, "")) { - param = pb_DeviceParam_name(strdup(device_name)); - } - else { - char* device_type = getenv("PARBOIL_DEVICE_TYPE"); - if (device_type && strcmp(device_type, "")) { - if (strcmp(device_type, "CPU") == 0) - param = pb_DeviceParam_cpu(); - else if (strcmp(device_type, "GPU") == 0) - param = pb_DeviceParam_gpu(); - else if (strcmp(device_type, "ACCELERATOR") == 0) - param = pb_DeviceParam_accelerator(); - } - } - } - - /* Get a device */ - pb_Device *d = pb_GetDevice(pb_platform, param); - pb_FreeDeviceParam(param); - - return d; -} - -pb_Platform* -pb_GetPlatformByEnvVars() { - char* name = getenv("PARBOIL_PLATFORM_NAME"); - char* version = getenv("PARBOIL_PLATFORM_VERSION"); - - /* Create a pb_PlatformParam object (or NULL) representing the data from the - * environment variables */ - struct pb_PlatformParam *platform; - - if (name) { - if (version) { - platform = pb_PlatformParam(strdup(name), strdup(version)); - } - else { - platform = pb_PlatformParam(strdup(name), NULL); - } - } - else { - platform = NULL; - } - - /* Convert to a platform */ - pb_Platform *p = pb_GetPlatform(platform); - pb_FreePlatformParam(platform); - - return p; -} - -/* Choose an OpenCL platform based on the given command-line parameters. - * If NULL, use the default OpenCL platform. */ -pb_Platform* -pb_GetPlatform(struct pb_PlatformParam *platform) { - if (platform != NULL) { - /* Try to use command-line parameters to choose platform */ - char *name = platform->name; - char *version = platform->version; - - if (!name) { - fprintf(stderr, "Internal error: NULL pointer"); - exit(-1); - } - - if (version) { - pb_Platform* p = pb_GetPlatformByNameAndVersion(name, version); - if (p) return p; - } - - pb_Platform* p = pb_GetPlatformByName(name); - if (p) return p; - } - - pb_Platform* p = pb_GetPlatformByName(NULL); - if (p == NULL) { - fprintf(stderr, "Error: No OpenCL platform in this system. Exiting."); - exit(-1); - } - return p; -} - -//extern void perf_init(); -//extern void mxpa_scheduler_init(); - -pb_Context* -pb_InitOpenCLContext(struct pb_Parameters* parameters) { -#if 0 - pb_Platform* ps = pb_GetPlatform(parameters->platform); - if (!ps) return NULL; - pb_Device* ds = pb_GetDevice(ps, parameters->device); - if (!ds) return NULL; - - /* HERE INITIALIZE TIMER */ - //perf_init(); - //mxpa_scheduler_init(); - - pb_Context* c = createContext(ps, ds); - pb_PrintPlatformInfo(c); - return c; -#endif - cl_int _err; - cl_platform_id platform_id; - cl_device_id device_id; - cl_context context; - clGetPlatformIDs(1, &platform_id, NULL); - clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL); - context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &_err); - - pb_Context* c = (pb_Context*)malloc(sizeof(pb_Context)); - c->clContext = context; - c->clDeviceId = device_id; - c->clPlatformId = platform_id; - c->pb_platform = (pb_Platform*)malloc(sizeof(pb_Platform)); - c->pb_device = (pb_Device*)malloc(sizeof(pb_Device)); - c->pb_platform->devices = (pb_Device**)malloc(sizeof(pb_Device*) * 2); - c->pb_platform->devices[0] = c->pb_device; - c->pb_platform->devices[1] = NULL; - c->pb_platform->contexts = (pb_Context**)malloc(sizeof(pb_Context*) * 2); - c->pb_platform->contexts[0] = c; - c->pb_platform->contexts[1] = NULL; - c->pb_platform->in_use = 1; - c->pb_device->in_use = 1; - return c; -} - -void -pb_ReleaseOpenCLContext(pb_Context* c) { - pb_ReleasePlatforms(); -} - -void -pb_PrintPlatformInfo(pb_Context* c) { - /*pb_Platform** ps = pb_GetPlatforms(); - if (!ps) { - fprintf (stderr, "No platform found"); - return; - } - - printf ("********************************************************\n"); - printf ("DETECTED OPENCL PLATFORMS AND DEVICES:\n"); - printf ("--------------------------------------------------------\n"); - - while (*ps) { - printf ("PLATFORM = %s, %s", (*ps)->name, (*ps)->version); - if (c->pb_platform == *ps) printf (" (SELECTED)"); - printf ("\n"); - - pb_Device** ds = (pb_Device **) pb_GetDevices((*ps)); - if (ds == NULL) { - printf (" + (No devices)\n"); - } else { - while (*ds) { - printf (" + %d: %s", (*ds)->id, (*ds)->name); - if (c->pb_device == *ds) printf (" (SELECTED)"); - printf ("\n"); - ds++; - } - } - - ps++; - } - printf ("********************************************************\n");*/ -} - -#ifdef MEASURE_KERNEL_TIME - -#undef clEnqueueNDRangeKernel - -//extern void pin_trace_enable(char*); -//extern void pin_trace_disable(char*); - -cl_int -pb_clEnqueueNDRangeKernel(cl_command_queue q/* command_queue */, - cl_kernel k/* kernel */, - cl_uint d/* work_dim */, - const size_t * o/* global_work_offset */, - const size_t * gws/* global_work_size */, - const size_t * lws/* local_work_size */, - cl_uint n/* num_events_in_wait_list */, - const cl_event * w/* event_wait_list */, - cl_event * e/* event */) { - - char buf[128]; - struct timeval begin, end; - clGetKernelInfo(k, CL_KERNEL_FUNCTION_NAME, 128, buf, NULL); - -#if 0 - int i; - for (i = 0; i < d; i++) { - printf ("%s: %d: %d / %d\n", buf, i, gws[i], (lws == NULL ? 0 : lws[i])); - } -#endif - - clFinish(q); clFlush(q); - //pin_trace_enable(buf); - //gettimeofday(&begin, NULL); - cl_int result = clEnqueueNDRangeKernel(q, k, d, o, gws, lws, n, w, e); - clFinish(q); clFlush(q); - //gettimeofday(&end, NULL); - //pin_trace_disable(buf); - //float t = (float)(end.tv_sec - begin.tv_sec) + (end.tv_usec - begin.tv_usec) / 1000000.0f; - fflush(stdout); - fflush(stderr); - //printf ("PBTIMER: %s: %f\n", buf, t); - return result; -} - -#endif - -void -pb_sig_float(char* c, float* p, int sz) { - int i; - double s = 0.0; - for (i = 0; i < sz; i++) s += p[i] * (float)(i+1); - printf ("[Signature] %s = %lf\n", c, s); -} - -void -pb_sig_double(char* c, double* p, int sz) { - int i; - double s = 0.0; - for (i = 0; i < sz; i++) s += p[i]; - printf ("[Signature] %s = %lf\n", c, s); -} - -void -pb_sig_short(char* c, short* p, int sz) { - int i; - long long int s = 0; - for (i = 0; i < sz; i++) s += p[i]; - printf ("[Signature] %s = %lld\n", c, s); -} - -void -pb_sig_int(char* c, int* p, int sz) { - int i; - long long int s = 0; - for (i = 0; i < sz; i++) s += p[i]; - printf ("[Signature] %s = %lld\n", c, s); -} - -void -pb_sig_uchar(char* c, unsigned char* p, unsigned int sz) { - int i; - unsigned long long int s = 0; - for (i = 0; i < sz; i++) s += p[i]; - printf ("[Signature] %s = %lld\n", c, s); -} - -void pb_sig_clmem(char* s, cl_command_queue command_queue, cl_mem memobj, int ty) { - size_t sz; - if (clGetMemObjectInfo(memobj, CL_MEM_SIZE, sizeof(size_t), &sz, NULL) != CL_SUCCESS) { - printf ("Something wrong.\n"); - assert(0); - } else { - printf ("size = %d\n", sz); - } - char* hp; // = (char*) malloc(sz); - //posix_memalign((void**)&hp, 64, sz); - hp = (char*)malloc(sz); - - clEnqueueReadBuffer (command_queue, - memobj, - CL_TRUE, - 0, - sz, - hp, - 0, - NULL, - NULL); - - if (ty == T_FLOAT) pb_sig_float(s, (float*)hp, sz/sizeof(float)); - if (ty == T_DOUBLE) pb_sig_double(s, (double*)hp, sz/sizeof(double)); - if (ty == T_INT) pb_sig_int(s, (int*)hp, sz/sizeof(int)); - if (ty == T_SHORT) pb_sig_short(s, (short*)hp, sz/sizeof(short)); - if (ty == T_UCHAR) pb_sig_uchar(s, (unsigned char*)hp, sz/sizeof(char)); - - free(hp); -} - diff --git a/tests/opencl/sgemm2/kernel.cl b/tests/opencl/sgemm2/kernel.cl deleted file mode 100644 index 6a764820..00000000 --- a/tests/opencl/sgemm2/kernel.cl +++ /dev/null @@ -1,73 +0,0 @@ -__kernel void sgemm2(__global float *A, - __global float *B, - __global float *C, - const unsigned int N, - __local float *localA, - __local float *localB) -{ - int globalRow = get_global_id(1); - int globalCol = get_global_id(0); - int localRow = get_local_id(1); - int localCol = get_local_id(0); - int localSize = get_local_size(0); // assuming square local size - - float sum = 0.0f; - - // Loop over all blocks of both matrices - for (int k = 0; k < N; k += localSize) { - // Load block of matrix A to local memory - localA[localRow * localSize + localCol] = A[globalRow * N + k + localCol]; - - // Load block of matrix B to local memory, adjusting for column-major access - localB[localRow * localSize + localCol] = B[(k + localRow) * N + globalCol]; - - // Synchronize to make sure the tiles are loaded - barrier(CLK_LOCAL_MEM_FENCE); - - // Multiply the two matrix blocks and accumulate result - for (int j = 0; j < localSize; j++) { - sum += localA[localRow * localSize + j] * localB[j * localSize + localCol]; - } - - // Ensure computation is done before loading next block - barrier(CLK_LOCAL_MEM_FENCE); - } - - C[globalRow * N + globalCol] = sum; -} - -/*__kernel void sgemm2(__global float *A, - __global float *B, - __global float *C, - const unsigned int N) -{ - int globalRow = get_global_id(1); - int globalCol = get_global_id(0); - int localRow = get_local_id(1); - int localCol = get_local_id(0); - - // Static local memory declaration - __local float localA[16][16]; - __local float localB[16][16]; - - float sum = 0.0f; - - // Iterate over blocks - for (int k = 0; k < N; k += 16) { - // Load a block of matrix A into local memory - localA[localRow][localCol] = A[globalRow * N + k + localCol]; - - // Load a block of matrix B into local memory - localB[localRow][localCol] = B[(k + localRow) * N + globalCol]; - - // Ensure the entire block is loaded - barrier(CLK_LOCAL_MEM_FENCE); - - // Compute multiplication for this block - for (int j = 0; j < 16; j++) { - sum += localA[localRow][j] * localB[j][localCol]; - } - } - - C[globalRow * N + globalCol] = sum; -}*/ \ No newline at end of file diff --git a/tests/opencl/vectorhypot/Makefile b/tests/opencl/vectorhypot/Makefile deleted file mode 100644 index 5763dfb5..00000000 --- a/tests/opencl/vectorhypot/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -PROJECT = vectorhypot - -SRCS = main.cc oclUtils.cpp shrUtils.cpp cmd_arg_reader.cpp - -CXXFLAGS += -I. - -OPTS ?= - -include ../common.mk - diff --git a/tests/opencl/vectorhypot/cmd_arg_reader.cpp b/tests/opencl/vectorhypot/cmd_arg_reader.cpp deleted file mode 100644 index 9b7f91ef..00000000 --- a/tests/opencl/vectorhypot/cmd_arg_reader.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -/* CUda UTility Library */ - -// includes, file -#include "cmd_arg_reader.h" - -// includes, system -#include - -// internal unnamed namespace - -namespace -{ - // types, internal (class, enum, struct, union, typedef) - - // variables, internal - -} // namespace { - -// variables, exported - -/*static*/ CmdArgReader* CmdArgReader::self; -/*static*/ char** CmdArgReader::rargv; -/*static*/ int CmdArgReader::rargc; - -// functions, exported - -//////////////////////////////////////////////////////////////////////////////// -//! Public construction interface -//! @return a handle to the class instance -//! @param argc number of command line arguments (as given to main()) -//! @param argv command line argument string (as given to main()) -//////////////////////////////////////////////////////////////////////////////// -/*static*/ void -CmdArgReader::init( const int argc, const char** argv) -{ - if ( NULL != self) - { - return; - } - - // command line arguments - if (( 0 == argc) || ( 0 == argv)) - { - LOGIC_EXCEPTION( "No command line arguments given."); - } - - self = new CmdArgReader(); - - self->createArgsMaps( argc, argv); - - rargc = argc; - rargv = const_cast( argv); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Constructor, default -//////////////////////////////////////////////////////////////////////////////// -CmdArgReader::CmdArgReader() : - args(), - unprocessed(), - iter(), - iter_unprocessed() -{ } - -//////////////////////////////////////////////////////////////////////////////// -//! Destructor -//////////////////////////////////////////////////////////////////////////////// -CmdArgReader::~CmdArgReader() -{ - for( iter = args.begin(); iter != args.end(); ++iter) - { - if( *(iter->second.first) == typeid( int)) - { - delete static_cast( iter->second.second); - break; - } - else if( *(iter->second.first) == typeid( bool)) - { - delete static_cast( iter->second.second); - break; - } - else if( *(iter->second.first) == typeid( std::string)) - { - delete static_cast( iter->second.second); - break; - } - else if( *(iter->second.first) == typeid( std::vector< std::string>) ) - { - delete static_cast< std::vector< std::string>* >( iter->second.second); - break; - } - else if( *(iter->second.first) == typeid( std::vector) ) - { - delete static_cast< std::vector* >( iter->second.second); - break; - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read args as token value pair into map for better processing (Even the -//! values remain strings until the parameter values is requested by the -//! program.) -//! @param argc the argument count (as given to 'main') -//! @param argv the char* array containing the command line arguments -//////////////////////////////////////////////////////////////////////////////// -void -CmdArgReader::createArgsMaps( const int argc, const char** argv) { - - std::string token; - std::string val_str; - - std::map< std::string, std::string> args; - - std::string::size_type pos; - std::string arg; - for( int i=1; i - inline const T* getArgHelper( const std::string& name); - - //! Check if a command line argument with name \a name exists - //! @return true if a command line argument of name \a name exists, - //! otherwise false - //! @param name the name of the requested argument - inline bool existArgHelper( const std::string& name) const; - - //! Read args as token value pair into map for better processing - //! (Even the values remain strings until the parameter values is - //! requested by the program.) - //! @param argc the argument count (as given to 'main') - //! @param argv the char* array containing the command line arguments - void createArgsMaps( const int argc, const char** argv); - - //! Helper for "casting" the strings from the map with the unprocessed - //! values to the correct - //! data type. - //! @return true if conversion succeeded, otherwise false - //! @param element the value as string - //! @param val the value as type T - template - static inline bool convertToT( const std::string& element, T& val); - -public: - - // typedefs internal - - //! container for a processed command line argument - //! typeid is used to easily be able to decide if a re-requested token-value - //! pair match the type of the first conversion - typedef std::pair< const std::type_info*, void*> ValType; - //! map of already converted values - typedef std::map< std::string, ValType > ArgsMap; - //! iterator for the map of already converted values - typedef ArgsMap::iterator ArgsMapIter; - typedef ArgsMap::const_iterator ConstArgsMapIter; - - //! map of unprocessed (means unconverted) token-value pairs - typedef std::map< std::string, std::string> UnpMap; - //! iterator for the map of unprocessed (means unconverted) token-value pairs - typedef std::map< std::string, std::string>::iterator UnpMapIter; - -private: - -#ifdef _WIN32 -# pragma warning( disable: 4251) -#endif - - //! rargc original value of argc - static int rargc; - - //! rargv contains command line arguments in raw format - static char** rargv; - - //! args Map containing the already converted token-value pairs - ArgsMap args; - - //! args Map containing the unprocessed / unconverted token-value pairs - UnpMap unprocessed; - - //! iter Iterator for the map with the already converted token-value - //! pairs (to avoid frequent reallocation) - ArgsMapIter iter; - - //! iter Iterator for the map with the unconverted token-value - //! pairs (to avoid frequent reallocation) - UnpMapIter iter_unprocessed; - -#ifdef _WIN32 -# pragma warning( default: 4251) -#endif - -private: - - //! Constructor, copy (not implemented) - CmdArgReader( const CmdArgReader&); - - //! Assignment operator (not implemented) - CmdArgReader& operator=( const CmdArgReader&); -}; - -// variables, exported (extern) - -// functions, inlined (inline) - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line argument arrays -//! @note This function is used each type for which no template specialization -//! exist (which will cause errors if the type does not fulfill the std::vector -//! interface). -//////////////////////////////////////////////////////////////////////////////// -template -/*static*/ inline bool -CmdArgReader::convertToT( const std::string& element, T& val) -{ - // preallocate storage - val.resize( std::count( element.begin(), element.end(), ',') + 1); - - unsigned int i = 0; - std::string::size_type pos_start = 1; // leave array prefix '[' - std::string::size_type pos_end = 0; - - // do for all elements of the comma seperated list - while( std::string::npos != ( pos_end = element.find(',', pos_end+1)) ) - { - // convert each element by the appropriate function - if ( ! convertToT< typename T::value_type >( - std::string( element, pos_start, pos_end - pos_start), val[i])) - { - return false; - } - - pos_start = pos_end + 1; - ++i; - } - - std::string tmp1( element, pos_start, element.length() - pos_start - 1); - - // process last element (leave array postfix ']') - if ( ! convertToT< typename T::value_type >( std::string( element, - pos_start, - element.length() - pos_start - 1), - val[i])) - { - return false; - } - - // possible to process all elements? - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type int -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, int& val) -{ - std::istringstream ios( element); - ios >> val; - - bool ret_val = false; - if ( ios.eof()) - { - ret_val = true; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type float -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, float& val) -{ - std::istringstream ios( element); - ios >> val; - - bool ret_val = false; - if ( ios.eof()) - { - ret_val = true; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type double -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, double& val) -{ - std::istringstream ios( element); - ios >> val; - - bool ret_val = false; - if ( ios.eof()) - { - ret_val = true; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type string -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, - std::string& val) -{ - val = element; - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Conversion function for command line arguments of type bool -//////////////////////////////////////////////////////////////////////////////// -template<> -inline bool -CmdArgReader::convertToT( const std::string& element, bool& val) -{ - // check if value is given as string-type { true | false } - if ( "true" == element) - { - val = true; - return true; - } - else if ( "false" == element) - { - val = false; - return true; - } - // check if argument is given as integer { 0 | 1 } - else - { - int tmp; - if ( convertToT( element, tmp)) - { - if ( 1 == tmp) - { - val = true; - return true; - } - else if ( 0 == tmp) - { - val = false; - return true; - } - } - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the value of the command line argument with given name -//! @return A const handle to the requested argument. If the argument does -//! not exist or if it is not from type T NULL is returned -//! @param T the type of the argument requested -//! @param name the name of the requested argument -//////////////////////////////////////////////////////////////////////////////// -template -/*static*/ const T* -CmdArgReader::getArg( const std::string& name) -{ - if( ! self) - { - RUNTIME_EXCEPTION("CmdArgReader::getArg(): CmdArgReader not initialized."); - return NULL; - } - - return self->getArgHelper( name); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Check if a command line argument with the given name exists -//! @return true if a command line argument with name \a name exists, -//! otherwise false -//! @param name name of the command line argument in question -//////////////////////////////////////////////////////////////////////////////// -/*static*/ inline bool -CmdArgReader::existArg( const std::string& name) -{ - if( ! self) - { - RUNTIME_EXCEPTION("CmdArgReader::getArg(): CmdArgReader not initialized."); - return false; - } - - return self->existArgHelper( name); -} - -//////////////////////////////////////////////////////////////////////////////// -//! @brief Get the value of the command line argument with given name -//! @return A const handle to the requested argument. If the argument does -//! not exist or if it is not from type T NULL is returned -//! @param T the type of the argument requested -//! @param name the name of the requested argument -//////////////////////////////////////////////////////////////////////////////// -template -const T* -CmdArgReader::getArgHelper( const std::string& name) -{ - // check if argument already processed and stored in correct type - if ( args.end() != (iter = args.find( name))) - { - if ( (*(iter->second.first)) == typeid( T) ) - { - return (T*) iter->second.second; - } - } - else - { - T* tmp = new T; - - // check the array with unprocessed values - if ( unprocessed.end() != (iter_unprocessed = unprocessed.find( name))) - { - // try to "cast" the string to the type requested - if ( convertToT< T >( iter_unprocessed->second, *tmp)) - { - // add the token element pair to map of already converted values - args[name] = std::make_pair( &(typeid( T)), (void*) tmp); - - return tmp; - } - } - - // not used while not inserted into the map -> cleanup - delete tmp; - } - - // failed, argument not available - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Check if a command line argument with name \a name exists -//! @return true if a command line argument of name \a name exists, -//! otherwise false -//! @param name the name of the requested argument -//////////////////////////////////////////////////////////////////////////////// -inline bool -CmdArgReader::existArgHelper( const std::string& name) const -{ - bool ret_val = false; - - // check if argument already processed and stored in correct type - if( args.end() != args.find( name)) - { - ret_val = true; - } - else - { - - // check the array with unprocessed values - if ( unprocessed.end() != unprocessed.find( name)) - { - ret_val = true; - } - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the original / raw argc program argument -//////////////////////////////////////////////////////////////////////////////// -/*static*/ inline int& -CmdArgReader::getRArgc() -{ - if( ! self) - { - RUNTIME_EXCEPTION("CmdArgReader::getRArgc(): CmdArgReader not initialized."); - } - - return rargc; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the original / raw argv program argument -//////////////////////////////////////////////////////////////////////////////// -/*static*/ inline char**& -CmdArgReader::getRArgv() -{ - if( ! self) - { - RUNTIME_EXCEPTION("CmdArgReader::getRArgc(): CmdArgReader not initialized."); - } - - return rargv; -} - -// functions, exported (extern) - -#endif // #ifndef _CMDARGREADER_H_ diff --git a/tests/opencl/vectorhypot/exception.h b/tests/opencl/vectorhypot/exception.h deleted file mode 100644 index e4650d99..00000000 --- a/tests/opencl/vectorhypot/exception.h +++ /dev/null @@ -1,151 +0,0 @@ -/* -* Copyright 1993-2010 NVIDIA Corporation. All rights reserved. -* -* Please refer to the NVIDIA end user license agreement (EULA) associated -* with this source code for terms and conditions that govern your use of -* this software. Any use, reproduction, disclosure, or distribution of -* this software and related documentation outside the terms of the EULA -* is strictly prohibited. -* -*/ - -/* CUda UTility Library */ -#ifndef _EXCEPTION_H_ -#define _EXCEPTION_H_ - -// includes, system -#include -#include -#include -#include - -//! Exception wrapper. -//! @param Std_Exception Exception out of namespace std for easy typing. -template -class Exception : public Std_Exception -{ -public: - - //! @brief Static construction interface - //! @return Alwayss throws ( Located_Exception) - //! @param file file in which the Exception occurs - //! @param line line in which the Exception occurs - //! @param detailed details on the code fragment causing the Exception - static void throw_it( const char* file, - const int line, - const char* detailed = "-" ); - - //! Static construction interface - //! @return Alwayss throws ( Located_Exception) - //! @param file file in which the Exception occurs - //! @param line line in which the Exception occurs - //! @param detailed details on the code fragment causing the Exception - static void throw_it( const char* file, - const int line, - const std::string& detailed); - - //! Destructor - virtual ~Exception() throw(); - -private: - - //! Constructor, default (private) - Exception(); - - //! Constructor, standard - //! @param str string returned by what() - Exception( const std::string& str); - -}; - -//////////////////////////////////////////////////////////////////////////////// -//! Exception handler function for arbitrary exceptions -//! @param ex exception to handle -//////////////////////////////////////////////////////////////////////////////// -template -inline void -handleException( const Exception_Typ& ex) -{ - std::cerr << ex.what() << std::endl; - - exit( EXIT_FAILURE); -} - -//! Convenience macros - -//! Exception caused by dynamic program behavior, e.g. file does not exist -#define RUNTIME_EXCEPTION( msg) \ - Exception::throw_it( __FILE__, __LINE__, msg) - -//! Logic exception in program, e.g. an assert failed -#define LOGIC_EXCEPTION( msg) \ - Exception::throw_it( __FILE__, __LINE__, msg) - -//! Out of range exception -#define RANGE_EXCEPTION( msg) \ - Exception::throw_it( __FILE__, __LINE__, msg) - -//////////////////////////////////////////////////////////////////////////////// -//! Implementation - -// includes, system -#include - -//////////////////////////////////////////////////////////////////////////////// -//! Static construction interface. -//! @param Exception causing code fragment (file and line) and detailed infos. -//////////////////////////////////////////////////////////////////////////////// -/*static*/ template -void -Exception:: -throw_it( const char* file, const int line, const char* detailed) -{ - std::stringstream s; - - // Quiet heavy-weight but exceptions are not for - // performance / release versions - s << "Exception in file '" << file << "' in line " << line << "\n" - << "Detailed description: " << detailed << "\n"; - - throw Exception( s.str()); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Static construction interface. -//! @param Exception causing code fragment (file and line) and detailed infos. -//////////////////////////////////////////////////////////////////////////////// -/*static*/ template -void -Exception:: -throw_it( const char* file, const int line, const std::string& msg) -{ - throw_it( file, line, msg.c_str()); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Constructor, default (private). -//////////////////////////////////////////////////////////////////////////////// -template -Exception::Exception() : - Exception("Unknown Exception.\n") -{ } - -//////////////////////////////////////////////////////////////////////////////// -//! Constructor, standard (private). -//! String returned by what(). -//////////////////////////////////////////////////////////////////////////////// -template -Exception::Exception( const std::string& s) : - Std_Exception( s) -{ } - -//////////////////////////////////////////////////////////////////////////////// -//! Destructor -//////////////////////////////////////////////////////////////////////////////// -template -Exception::~Exception() throw() { } - -// functions, exported - -#endif // #ifndef _EXCEPTION_H_ - diff --git a/tests/opencl/vectorhypot/kernel.cl b/tests/opencl/vectorhypot/kernel.cl deleted file mode 100644 index 1983a862..00000000 --- a/tests/opencl/vectorhypot/kernel.cl +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -// OpenCL Kernel Function Naive Implementation for hyptenuse -__kernel void VectorHypot(__global float4* fg4A, __global float4* fg4B, __global float4* fg4Hypot, unsigned int uiOffset, int iInnerLoopCount, unsigned int uiNumElements) -{ - // get index into global data array - size_t szGlobalOffset = get_global_id(0) + uiOffset; - - // bound check - if (szGlobalOffset >= uiNumElements) - { - return; - } - - // Processing 4 elements per work item, so read fgA and fgB source values from GMEM - float4 f4A = fg4A[szGlobalOffset]; - float4 f4B = fg4B[szGlobalOffset]; - float4 f4H = (float4)0.0f; - - // Get the hypotenuses the vectors of 'legs', but exaggerate the time needed with loop - for (int i = 0; i < iInnerLoopCount; i++) - { - // compute the 4 hypotenuses using built-in function - f4H.x = hypot (f4A.x, f4B.x); - f4H.y = hypot (f4A.y, f4B.y); - f4H.z = hypot (f4A.z, f4B.z); - f4H.w = hypot (f4A.w, f4B.w); - } - - // Write 4 result values back out to GMEM - fg4Hypot[szGlobalOffset] = f4H; -} \ No newline at end of file diff --git a/tests/opencl/vectorhypot/main.cc b/tests/opencl/vectorhypot/main.cc deleted file mode 100644 index ec25bbf2..00000000 --- a/tests/opencl/vectorhypot/main.cc +++ /dev/null @@ -1,702 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -// ********************************************************************* -// oclCopyComputeOverlap Notes: -// -// OpenCL API demo application for NVIDIA CUDA GPU's that implements a -// element by element vector hyptenuse computation using 2 input float arrays -// and 1 output float array. -// -// Demonstrates host->GPU and GPU->host copies that are asynchronous/overlapped -// with respect to GPU computation (and with respect to host thread). -// -// Because the overlap acheivable for this computation and data set on a given system depends upon the GPU being used and the -// GPU/Host bandwidth, the sample adjust the computation duration to test the most ideal case and test against a consistent standard. -// This sample should be able to achieve up to 30% overlap on GPU's arch 1.2 and 1.3, and up to 50% on arch 2.0+ (Fermi) GPU's. -// -// After setup, warmup and calibration to the system, the sample runs 4 scenarios: -// A) Computations with 2 command queues on GPU -// A multiple-cycle sequence is executed, timed and compared against the host -// B) Computations with 1 command queue on GPU -// A multiple-cycle sequence is executed, timed and compared against the host -// -// The 2-command queue approach ought to be substantially faster -// -// For developmental purposes, the "iInnerLoopCount" variable passes into kernel and independently -// increases compute time without increasing data size (via a loop inside the kernel) -// -// At some value of iInnerLoopCount, # of elements, workgroup size, etc the Overlap percentage should reach 30%: -// (This ~naively assumes time H2D bandwidth is the same as D2H bandwidth, but this is close on most systems) -// -// If we name the time to copy single input vector H2D (or outpute vector D2H) as "T", then the optimum comparison case is: -// -// Single Queue with all the data and all the work -// Ttot (serial) = 4T + 4T + 2T = 10T -// -// Dual Queue, where each queue has 1/2 the data and 1/2 the work -// Tq0 (overlap) = 2T + 2T + T .... -// Tq1 (overlap) = .... 2T + 2T + T -// -// Ttot (elapsed, wall) = 2T + 2T + 2T + T = 7T -// -// Best Overlap % = 100.0 * (10T - 7T)/10T = 30.0 % (Tesla arch 1.2 or 1.3, single copy engine) -// -// For multiple independent cycles using arch >= 2.0 with 2 copy engines, input and output copies can also be overlapped. -// This doesn't help for the first cycle, but theoretically can lead to 50% overlap over many independent cycles. -// ********************************************************************* - -// common SDK header for standard utilities and system libs -#include -#include -#include - -// Best possible and Min ratio of compute/copy overlap timing benefit to pass the test -// values greater than 0.0f represent a speed-up relative to non-overlapped -#define EXPECTED_OVERLAP 30.0f -#define EXPECTED_OVERLAP_FERMI 45.0f -#define PASS_FACTOR 0.60f -#define RETRIES_ON_FAILURE 1 - -// Base sizes for parameters manipulated dynamically or on the command line -#define BASE_WORK_ITEMS 64 -#define BASE_ARRAY_LENGTH 40000 -#define BASE_LOOP_COUNT 32 - -static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { - if (nullptr == filename || nullptr == data || 0 == size) - return CL_INVALID_VALUE; - - FILE* fp = fopen(filename, "r"); - if (NULL == fp) { - fprintf(stderr, "Failed to load kernel."); - return CL_INVALID_VALUE; - } - fseek(fp , 0 , SEEK_END); - long fsize = ftell(fp); - rewind(fp); - - *data = (uint8_t*)malloc(fsize); - *size = fread(*data, 1, fsize, fp); - - fclose(fp); - - return CL_SUCCESS; -} - -// Vars -// ********************************************************************* -cl_platform_id cpPlatform; // OpenCL platform -cl_context cxGPUContext; // OpenCL context -cl_command_queue cqCommandQueue[2]; // OpenCL command queues -cl_device_id* cdDevices; // OpenCL device list -cl_program cpProgram; // OpenCL program -cl_kernel ckKernel[2]; // OpenCL kernel, 1 per queue -cl_mem cmPinnedSrcA; // OpenCL pinned host source buffer A -cl_mem cmPinnedSrcB; // OpenCL pinned host source buffer B -cl_mem cmPinnedResult; // OpenCL pinned host result buffer -float* fSourceA = NULL; // Mapped pointer for pinned Host source A buffer -float* fSourceB = NULL; // Mapped pointer for pinned Host source B buffer -float* fResult = NULL; // Mapped pointer for pinned Host result buffer -cl_mem cmDevSrcA; // OpenCL device source buffer A -cl_mem cmDevSrcB; // OpenCL device source buffer B -cl_mem cmDevResult; // OpenCL device result buffer -size_t szBuffBytes; // Size of main buffers -size_t szGlobalWorkSize; // 1D var for Total # of work items in the launched ND range -size_t szLocalWorkSize = BASE_WORK_ITEMS; // initial # of work items in the work group -cl_int ciErrNum; // Error code var -char* cPathAndName = NULL; // Var for full paths to data, src, etc. -char* cSourceCL = NULL; // Buffer to hold source for compilation -const char* cExecutableName = NULL; - -// demo config vars -const char* cSourceFile = "kernel.cl"; // OpenCL computation kernel source code -float* Golden = NULL; // temp buffer to hold golden results for cross check -bool bNoPrompt = false; // Command line switch to skip exit prompt -bool bQATest = false; // Command line switch to test - -// Forward Declarations -// ********************************************************************* -double DualQueueSequence(int iCycles, unsigned int uiNumElements, bool bShowConfig); -double OneQueueSequence(int iCycles, unsigned int uiNumElements, bool bShowConfig); -int AdjustCompute(cl_device_id cdTargetDevice, unsigned int uiNumElements, int iInitialLoopCount, int iCycles); -void VectorHypotHost(const float* pfData1, const float* pfData2, float* pfResult, unsigned int uiNumElements, int iInnerLoopCount); -void Cleanup (int iExitCode); -void (*pCleanup)(int) = &Cleanup; - -int *gp_argc = 0; -const char *** gp_argv = NULL; - -// Main function -// ********************************************************************* -int main(int argc, const char **argv) -{ - //Locals - size_t szKernelLength; // Byte size of kernel code - double dBuildTime; // Compile time - cl_uint uiTargetDevice = 0; // Default Device to compute on - cl_uint uiNumDevsUsed = 1; // Number of devices used in this sample - cl_uint uiNumDevices; // Number of devices available - int iDevCap = -1; // Capability of device - int iInnerLoopCount = BASE_LOOP_COUNT; // Varies "compute intensity" per data within the kernel - const int iTestCycles = 10; // How many times to run the external test loop - const int iWarmupCycles = 8; // How many times to run the warmup sequence - cl_uint uiWorkGroupMultiple = 4; // Command line var (using "workgroupmult=") to optionally increase workgroup size - cl_uint uiNumElements = BASE_ARRAY_LENGTH; // initial # of elements per array to process (note: procesing 4 per work item) - cl_uint uiSizeMultiple = 4; // Command line var (using "sizemult=") to optionally increase vector sizes - bool bPassFlag = false; // Var to accumulate test pass/fail - shrBOOL bMatch = shrFALSE; // Cross check result - shrBOOL bTestOverlap = shrFALSE; - double dAvgGPUTime[2] = {0.0, 0.0}; // Average time of iTestCycles calls for 2-Queue and 1-Queue test - double dHostTime[2] = {0.0, 0.0}; // Host computation time (2nd test is redundant but a good stability indicator) - float fMinPassCriteria[2] = {0.0f, 0.0f}; // Test pass cireria, adjusted dependant on GPU arch - - gp_argc = &argc; - gp_argv = &argv; - - shrQAStart(argc, (char **)argv); - - // start logs - cExecutableName = argv[0]; - shrSetLogFileName ("oclCopyComputeOverlap.txt"); - shrLog("%s Starting...\n\n", argv[0]); - - // get basic command line args - bNoPrompt = (shrTRUE == shrCheckCmdLineFlag(argc, argv, "noprompt")); - bQATest = (shrTRUE == shrCheckCmdLineFlag(argc, argv, "qatest")); - shrGetCmdLineArgumentu(argc, argv, "device", &uiTargetDevice); - - // Optional Command-line multiplier for vector size - // Default val of 4 gives 10.24 million float elements per vector - // Range of 3 - 16 (7.68 to 40.96 million floats) is reasonable range (if system and GPU have enough memory) - shrGetCmdLineArgumentu(argc, argv, "sizemult", &uiSizeMultiple); - uiSizeMultiple = CLAMP(uiSizeMultiple, 1, 50); - uiNumElements = uiSizeMultiple * BASE_ARRAY_LENGTH * BASE_WORK_ITEMS; - shrLog("Array sizes = %u float elements\n", uiNumElements); - - // Optional Command-line multiplier for workgroup size (x 64 work items) - // Default val of 4 gives szLocalWorkSize of 256. - // Range of 1 - 8 (resulting in workgroup sizes of 64 to 512) is reasonable range - shrGetCmdLineArgumentu(argc, argv, "workgroupmult", &uiWorkGroupMultiple); - uiWorkGroupMultiple = CLAMP(uiWorkGroupMultiple, 1, 10); - szLocalWorkSize = uiWorkGroupMultiple * BASE_WORK_ITEMS; - shrLog("Workgroup Size = %u\n\n", szLocalWorkSize); - - // Get the NVIDIA platform if available, otherwise use default - shrLog("Get the Platform ID...\n\n"); - ciErrNum = oclGetPlatformID(&cpPlatform); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Get OpenCL platform name and version - char cBuffer[256]; - ciErrNum = clGetPlatformInfo (cpPlatform, CL_PLATFORM_NAME, sizeof(cBuffer), cBuffer, NULL); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - shrLog("Platform Name = %s\n\n", cBuffer); - - // Get all the devices - shrLog("Get the Device info and select Device...\n"); - uiNumDevices = 1; - cdDevices = (cl_device_id*)malloc(uiNumDevices * sizeof(cl_device_id)); - ciErrNum = clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_DEFAULT, 1, cdDevices, NULL); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Set target device and check capabilities - shrLog(" # of Devices Available = %u\n", uiNumDevices); - uiTargetDevice = CLAMP(uiTargetDevice, 0, (uiNumDevices - 1)); - shrLog(" Using Device %u, ", uiTargetDevice); - oclPrintDevName(LOGBOTH, cdDevices[uiTargetDevice]); - /*iDevCap = oclGetDevCap(cdDevices[uiTargetDevice]); - if (iDevCap > 0) { - shrLog(", Capability = %d.%d\n\n", iDevCap/10, iDevCap%10); - } else { - shrLog("\n\n", iDevCap); - } - if (strstr(cBuffer, "NVIDIA") != NULL) - { - if (iDevCap < 12) - { - shrLog("Device doesn't have overlap capability. Skipping test...\n"); - Cleanup (EXIT_SUCCESS); - } - - // Device and Platform eligible for overlap testing - bTestOverlap = shrTRUE; - - // If device has overlap capability, proceed - fMinPassCriteria[0] = PASS_FACTOR * EXPECTED_OVERLAP; // 1st cycle overlap is same for 1 or 2 copy engines - if (iDevCap != 20) - { - // Single copy engine - fMinPassCriteria[1] = PASS_FACTOR * EXPECTED_OVERLAP; // avg of many cycles - } - else - { - char cDevName[1024]; - clGetDeviceInfo(cdDevices[uiTargetDevice], CL_DEVICE_NAME, sizeof(cDevName), &cDevName, NULL); - if(strstr(cDevName, "Quadro")!=0 || strstr(cDevName, "Tesla")!=0) - { - // Tesla or Quadro (arch = 2.0) ... Dual copy engine - fMinPassCriteria[1] = PASS_FACTOR * EXPECTED_OVERLAP_FERMI; // average of many cycles - } - else - { - // Geforce ... Single copy engine - fMinPassCriteria[1] = PASS_FACTOR * EXPECTED_OVERLAP; // average of many cycles - } - } - }*/ - - // Create the context - shrLog("clCreateContext...\n"); - cxGPUContext = clCreateContext(0, uiNumDevsUsed, &cdDevices[uiTargetDevice], NULL, NULL, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Create 2 command-queues - cqCommandQueue[0] = clCreateCommandQueue(cxGPUContext, cdDevices[uiTargetDevice], 0, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - shrLog("clCreateCommandQueue [0]...\n"); - cqCommandQueue[1] = clCreateCommandQueue(cxGPUContext, cdDevices[uiTargetDevice], 0, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - shrLog("clCreateCommandQueue [1]...\n"); - - // Allocate the OpenCL source and result buffer memory objects on GPU device GMEM - szBuffBytes = sizeof(cl_float) * uiNumElements; - cmDevSrcA = clCreateBuffer(cxGPUContext, CL_MEM_READ_ONLY, szBuffBytes, NULL, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - cmDevSrcB = clCreateBuffer(cxGPUContext, CL_MEM_READ_ONLY, szBuffBytes, NULL, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - cmDevResult = clCreateBuffer(cxGPUContext, CL_MEM_WRITE_ONLY, szBuffBytes, NULL, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - shrLog("clCreateBuffer (Src A, Src B and Result GPU Device GMEM, 3 x %u floats) ...\n", uiNumElements); - - // Allocate pinned source and result host buffers: - // Note: Pinned (Page Locked) memory is needed for async host<->GPU memory copy operations *** - cmPinnedSrcA = clCreateBuffer(cxGPUContext, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, szBuffBytes, NULL, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - cmPinnedSrcB = clCreateBuffer(cxGPUContext, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, szBuffBytes, NULL, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - cmPinnedResult = clCreateBuffer(cxGPUContext, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, szBuffBytes, NULL, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - shrLog("clCreateBuffer (Src A, Src B and Result Pinned Host buffers, 3 x %u floats)...\n\n", uiNumElements); - - // Get mapped pointers to pinned input host buffers - // Note: This allows general (non-OpenCL) host functions to access pinned buffers using standard pointers - fSourceA = (cl_float*)clEnqueueMapBuffer(cqCommandQueue[0], cmPinnedSrcA, CL_TRUE, CL_MAP_WRITE, 0, szBuffBytes, 0, NULL, NULL, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - fSourceB = (cl_float*)clEnqueueMapBuffer(cqCommandQueue[0], cmPinnedSrcB, CL_TRUE, CL_MAP_WRITE, 0, szBuffBytes, 0, NULL, NULL, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - fResult = (cl_float*)clEnqueueMapBuffer(cqCommandQueue[0], cmPinnedResult, CL_TRUE, CL_MAP_READ, 0, szBuffBytes, 0, NULL, NULL, &ciErrNum); - oclCheckErrorEX (ciErrNum, CL_SUCCESS, pCleanup); - shrLog("clEnqueueMapBuffer (Pointers to 3 pinned host buffers)...\n"); - - // Alloc temp golden buffer for cross checks - Golden = (float*)malloc(szBuffBytes); - oclCheckErrorEX(Golden != NULL, shrTRUE, pCleanup); - -#ifdef HOSTGPU - // Read the OpenCL kernel in from source file - cPathAndName = shrFindFilePath(cSourceFile, argv[0]); - oclCheckError(cPathAndName != NULL, shrTRUE); - shrLog("oclLoadProgSource (%s)...\n", cSourceFile); - cSourceCL = oclLoadProgSource(cPathAndName, "", &szKernelLength); - // Create the program object - shrLog("clCreateProgramWithSource...\n"); - cpProgram = clCreateProgramWithSource(cxGPUContext, 1, (const char **)&cSourceCL, &szKernelLength, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); -#else - uint8_t *kernel_bin = NULL; - size_t kernel_size; - cl_int binary_status = 0; - ciErrNum = read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - cpProgram = clCreateProgramWithBinary( - cxGPUContext, 1, &cdDevices[uiTargetDevice], &kernel_size, (const uint8_t**)&kernel_bin, &binary_status, &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); -#endif - // Build the program for the target device - clFinish(cqCommandQueue[0]); - shrDeltaT(0); - ciErrNum = clBuildProgram(cpProgram, uiNumDevsUsed, &cdDevices[uiTargetDevice], "-cl-fast-relaxed-math", NULL, NULL); - shrLog("clBuildProgram..."); - if (ciErrNum != CL_SUCCESS) - { - // write out standard error, Build Log and PTX, then cleanup and exit - shrLogEx(LOGBOTH | ERRORMSG, (double)ciErrNum, STDERROR); - oclLogBuildInfo(cpProgram, oclGetFirstDev(cxGPUContext)); - oclLogPtx(cpProgram, oclGetFirstDev(cxGPUContext), "VectorHypot.ptx"); - Cleanup(EXIT_FAILURE); - } - dBuildTime = shrDeltaT(0); - - // Create the kernel - ckKernel[0] = clCreateKernel(cpProgram, "VectorHypot", &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - ckKernel[1] = clCreateKernel(cpProgram, "VectorHypot", &ciErrNum); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - shrLog("clCreateKernel (ckKernel[2])...\n"); - - // Offsets for 2 queues - cl_uint uiOffset[2] = {0, uiNumElements / (2 * 4)}; - - // Set the Argument values for the 1st kernel instance (queue 0) - ciErrNum = clSetKernelArg(ckKernel[0], 0, sizeof(cl_mem), (void*)&cmDevSrcA); - ciErrNum |= clSetKernelArg(ckKernel[0], 1, sizeof(cl_mem), (void*)&cmDevSrcB); - ciErrNum |= clSetKernelArg(ckKernel[0], 2, sizeof(cl_mem), (void*)&cmDevResult); - ciErrNum |= clSetKernelArg(ckKernel[0], 3, sizeof(cl_uint), (void*)&uiOffset[0]); - ciErrNum |= clSetKernelArg(ckKernel[0], 4, sizeof(cl_int), (void*)&iInnerLoopCount); - ciErrNum |= clSetKernelArg(ckKernel[0], 5, sizeof(cl_uint), (void*)&uiNumElements); - shrLog("clSetKernelArg ckKernel[0] args 0 - 5...\n"); - - // Set the Argument values for the 2d kernel instance (queue 1) - ciErrNum |= clSetKernelArg(ckKernel[1], 0, sizeof(cl_mem), (void*)&cmDevSrcA); - ciErrNum |= clSetKernelArg(ckKernel[1], 1, sizeof(cl_mem), (void*)&cmDevSrcB); - ciErrNum |= clSetKernelArg(ckKernel[1], 2, sizeof(cl_mem), (void*)&cmDevResult); - ciErrNum |= clSetKernelArg(ckKernel[1], 3, sizeof(cl_uint), (void*)&uiOffset[1]); - ciErrNum |= clSetKernelArg(ckKernel[1], 4, sizeof(cl_int), (void*)&iInnerLoopCount); - ciErrNum |= clSetKernelArg(ckKernel[1], 5, sizeof(cl_uint), (void*)&uiNumElements); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - shrLog("clSetKernelArg ckKernel[1] args 0 - 5...\n\n"); - - //******************************************* - // Warmup the driver with dual queue sequence - //******************************************* - - // Warmup with dual queue sequence for iTestCycles - shrLog("Warmup with 2-Queue sequence, %d cycles...\n", iWarmupCycles); - DualQueueSequence(iWarmupCycles, uiNumElements, false); - - // Use single queue config to adjust compute intensity - shrLog("Adjust compute for GPU / system...\n"); - iInnerLoopCount = AdjustCompute(cdDevices[uiTargetDevice], uiNumElements, iInnerLoopCount, iTestCycles); - shrLog(" Kernel inner loop count = %d\n", iInnerLoopCount); - - //******************************************* - // Run and time with 2 command-queues - //******************************************* - for( int iRun =0; iRun <= RETRIES_ON_FAILURE; ++iRun ) { - - // Run the sequence iTestCycles times - dAvgGPUTime[0] = DualQueueSequence(iTestCycles, uiNumElements, false); - - // Warmup then Compute on host iTestCycles times (using mapped standard pointer to pinned host cl_mem buffer) - shrLog(" Device vs Host Result Comparison\t: "); - VectorHypotHost(fSourceA, fSourceB, Golden, uiNumElements, iInnerLoopCount); - shrDeltaT(0); - for (int i = 0; i < iTestCycles; i++) - { - VectorHypotHost (fSourceA, fSourceB, Golden, uiNumElements, iInnerLoopCount); - } - dHostTime[0] = shrDeltaT(0)/iTestCycles; - - // Compare host and GPU results (using mapped standard pointer to pinned host cl_mem buffer) - bMatch = shrComparefet(Golden, fResult, uiNumElements, 0.0f, 0); - shrLog("gpu %s cpu\n", (bMatch == shrTRUE) ? "MATCHES" : "DOESN'T MATCH"); - bPassFlag = (bMatch == shrTRUE); - - //******************************************* - // Run and time with 1 command queue - //******************************************* - // Run the sequence iTestCycles times - dAvgGPUTime[1] = OneQueueSequence(iTestCycles, uiNumElements, false); - - // Compute on host iTestCycles times (using mapped standard pointer to pinned host cl_mem buffer) - shrLog(" Device vs Host Result Comparison\t: "); - shrDeltaT(0); - for (int i = 0; i < iTestCycles; i++) - { - VectorHypotHost(fSourceA, fSourceB, Golden, (int)uiNumElements, iInnerLoopCount); - } - dHostTime[1] = shrDeltaT(0)/iTestCycles; - - // Compare host and GPU results (using mapped standard pointer to pinned host cl_mem buffer) - bMatch = shrComparefet(Golden, fResult, uiNumElements, 0.0f, 0); - shrLog("gpu %s cpu\n", (bMatch == shrTRUE) ? "MATCHES" : "DOESN'T MATCH"); - bPassFlag &= (bMatch == shrTRUE); - - //******************************************* - - // Compare Single and Dual queue timing - shrLog("\nResult Summary:\n"); - - // Log GPU and CPU Time for 2-queue scenario - shrLog(" Avg GPU Elapsed Time for 2-Queues\t= %.5f s\n", dAvgGPUTime[0]); - shrLog(" Avg Host Elapsed Time\t\t\t= %.5f s\n\n", dHostTime[0]); - - // Log GPU and CPU Time for 1-queue scenario - shrLog(" Avg GPU Elapsed Time for 1-Queue\t= %.5f s\n", dAvgGPUTime[1]); - shrLog(" Avg Host Elapsed Time\t\t\t= %.5f s\n\n", dHostTime[1]); - - // Log overlap % for GPU (comparison of 2-queue and 1 queue scenarios) and status - double dAvgOverlap = 100.0 * (1.0 - dAvgGPUTime[0]/dAvgGPUTime[1]); - - if( bTestOverlap ) { - bool bAvgOverlapOK = (dAvgOverlap >= fMinPassCriteria[1]); - if( iRun == RETRIES_ON_FAILURE || bAvgOverlapOK ) { - shrLog(" Measured and (Acceptable) Avg Overlap\t= %.1f %% (%.1f %%) -> Measured Overlap is %s\n\n", dAvgOverlap, fMinPassCriteria[1], bAvgOverlapOK ? "Acceptable" : "NOT Acceptable"); - - // Log info to master log in standard format - shrLogEx(LOGBOTH | MASTER, 0, "oclCopyComputeOverlap-Avg, Throughput = %.4f OverlapPercent, Time = %.5f s, Size = %u Elements, NumDevsUsed = %u, Workgroup = %u\n", - dAvgOverlap, dAvgGPUTime[0], uiNumElements, uiNumDevsUsed, szLocalWorkSize); - - bPassFlag &= bAvgOverlapOK; - break; - } - } - - shrLog(" Measured and (Acceptable) Avg Overlap\t= %.1f %% (%.1f %%) -> Retry %d more time(s)...\n\n", dAvgOverlap, fMinPassCriteria[1], RETRIES_ON_FAILURE - iRun); - } - - - //******************************************* - // Report pass/fail, cleanup and exit - Cleanup (bPassFlag ? EXIT_SUCCESS : EXIT_FAILURE); - - return 0; -} - -// Run 1 queue sequence for n cycles -// ********************************************************************* -double OneQueueSequence(int iCycles, unsigned int uiNumElements, bool bShowConfig) -{ - // Use fresh source Data: (re)initialize pinned host array buffers (using mapped standard pointer to pinned host cl_mem buffer) - shrFillArray(fSourceA, (int)uiNumElements); - shrFillArray(fSourceB, (int)uiNumElements); - - // Reset Global work size for 1 command-queue, and log work sizes & dimensions - szGlobalWorkSize = shrRoundUp((int)szLocalWorkSize, (int)(uiNumElements/4)); - - // *** Make sure queues are empty and then start timer - double dAvgTime = 0.0; - clFinish(cqCommandQueue[0]); - clFinish(cqCommandQueue[1]); - shrDeltaT(0); - - // Run the sequence iCycles times - for (int i = 0; i < iCycles; i++) - { - // Nonblocking Write of all of input data from host to device in command-queue 0 - ciErrNum = clEnqueueWriteBuffer(cqCommandQueue[0], cmDevSrcA, CL_FALSE, 0, szBuffBytes, (void*)&fSourceA[0], 0, NULL, NULL); - ciErrNum |= clEnqueueWriteBuffer(cqCommandQueue[0], cmDevSrcB, CL_FALSE, 0, szBuffBytes, (void*)&fSourceB[0], 0, NULL, NULL); - shrCheckError(ciErrNum, CL_SUCCESS); - - // Launch kernel computation, command-queue 0 - ciErrNum = clEnqueueNDRangeKernel(cqCommandQueue[0], ckKernel[0], 1, NULL, &szGlobalWorkSize, &szLocalWorkSize, 0, NULL, NULL); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Non Blocking Read of output data from device to host, command-queue 0 - ciErrNum = clEnqueueReadBuffer(cqCommandQueue[0], cmDevResult, CL_FALSE, 0, szBuffBytes, (void*)&fResult[0], 0, NULL, NULL); - shrCheckError(ciErrNum, CL_SUCCESS); - - // Flush sequence to device (may not be necessary on Linux or WinXP or when using the NVIDIA Tesla Computing Cluster driver) - clFlush(cqCommandQueue[0]); - } - - // *** Assure sync to host and return average sequence time - clFinish(cqCommandQueue[0]); - dAvgTime = shrDeltaT(0)/(double)iCycles; - - // Log config if asked for - if (bShowConfig) - { - shrLog("\n1-Queue sequence Configuration:\n"); - shrLog(" Global Work Size (per command-queue)\t= %u\n Local Work Size \t\t\t= %u\n # of Work Groups (per command-queue)\t= %u\n # of command-queues\t\t\t= 1\n", - szGlobalWorkSize, szLocalWorkSize, szGlobalWorkSize/szLocalWorkSize); - } - return dAvgTime; -} - -// Run 2 queue sequence for n cycles -// ********************************************************************* -double DualQueueSequence(int iCycles, unsigned int uiNumElements, bool bShowConfig) -{ - // Locals - size_t szHalfBuffer = szBuffBytes / 2; - size_t szHalfOffset = szHalfBuffer / sizeof(float); - double dAvgTime = 0.0; - - // Use fresh source Data: (re)initialize pinned host array buffers (using mapped standard pointer to pinned host cl_mem buffer) - shrFillArray(fSourceA, (int)uiNumElements); - shrFillArray(fSourceB, (int)uiNumElements); - - // Set Global work size for 2 command-queues, and log work sizes & dimensions - szGlobalWorkSize = shrRoundUp((int)szLocalWorkSize, (int)(uiNumElements/(2 * 4))); - - // Make sure queues are empty and then start timer - clFinish(cqCommandQueue[0]); - clFinish(cqCommandQueue[1]); - shrDeltaT(0); - - for (int i = 0; i < iCycles; i++) - { - // Mid Phase 0 - // Nonblocking Write of 1st half of input data from host to device in command-queue 0 - ciErrNum = clEnqueueWriteBuffer(cqCommandQueue[0], cmDevSrcA, CL_FALSE, 0, szHalfBuffer, (void*)&fSourceA[0], 0, NULL, NULL); - ciErrNum |= clEnqueueWriteBuffer(cqCommandQueue[0], cmDevSrcB, CL_FALSE, 0, szHalfBuffer, (void*)&fSourceB[0], 0, NULL, NULL); - shrCheckError(ciErrNum, CL_SUCCESS); - - // Push out the write for queue 0 (and prior read from queue 1 at end of loop) to the driver - // (not necessary on Linux, Mac OSX or WinXP) - clFlush(cqCommandQueue[0]); - clFlush(cqCommandQueue[1]); - - // Start Phase 1 *********************************** - - // Launch kernel computation, command-queue 0 - // (Note: The order MATTERS here on Fermi ! THE KERNEL IN THIS PHASE SHOULD BE LAUNCHED BEFORE THE WRITE) - ciErrNum = clEnqueueNDRangeKernel(cqCommandQueue[0], ckKernel[0], 1, NULL, &szGlobalWorkSize, &szLocalWorkSize, 0, NULL, NULL); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Nonblocking Write of 2nd half of input data from host to device in command-queue 1 - // (Note: The order MATTERS here on Fermi ! THE KERNEL IN THIS PHASE SHOULD BE LAUNCHED BEFORE THE WRITE) - ciErrNum = clEnqueueWriteBuffer(cqCommandQueue[1], cmDevSrcA, CL_FALSE, szHalfBuffer, szHalfBuffer, (void*)&fSourceA[szHalfOffset], 0, NULL, NULL); - ciErrNum |= clEnqueueWriteBuffer(cqCommandQueue[1], cmDevSrcB, CL_FALSE, szHalfBuffer, szHalfBuffer, (void*)&fSourceB[szHalfOffset], 0, NULL, NULL); - shrCheckError(ciErrNum, CL_SUCCESS); - - // Push out the compute for queue 0 and write for queue 1 to the driver - // (not necessary on Linux, Mac OSX or WinXP) - clFlush(cqCommandQueue[0]); - clFlush(cqCommandQueue[1]); - - // Start Phase 2 *********************************** - - // Launch kernel computation, command-queue 1 - ciErrNum = clEnqueueNDRangeKernel(cqCommandQueue[1], ckKernel[1], 1, NULL, &szGlobalWorkSize, &szLocalWorkSize, 0, NULL, NULL); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - - // Non Blocking Read of 1st half of output data from device to host, command-queue 0 - ciErrNum = clEnqueueReadBuffer(cqCommandQueue[0], cmDevResult, CL_FALSE, 0, szHalfBuffer, (void*)&fResult[0], 0, NULL, NULL); - shrCheckError(ciErrNum, CL_SUCCESS); - - // Push out the compute for queue 1 and the read for queue 0 to the driver - // (not necessary on Linux, Mac OSX or WinXP) - clFlush(cqCommandQueue[0]); - clFlush(cqCommandQueue[1]); - - // Start Phase 0 (Rolls over) *********************************** - - // Non Blocking Read of 2nd half of output data from device to host, command-queue 1 - ciErrNum = clEnqueueReadBuffer(cqCommandQueue[1], cmDevResult, CL_FALSE, szHalfBuffer, szHalfBuffer, (void*)&fResult[szHalfOffset], 0, NULL, NULL); - shrCheckError(ciErrNum, CL_SUCCESS); - } - - // *** Sync to host and get average sequence time - clFinish(cqCommandQueue[0]); - clFinish(cqCommandQueue[1]); - dAvgTime = shrDeltaT(0)/(double)iCycles; - - // Log config if asked for - if (bShowConfig) - { - shrLog("\n2-Queue sequence Configuration:\n"); - shrLog(" Global Work Size (per command-queue)\t= %u\n Local Work Size \t\t\t= %u\n # of Work Groups (per command-queue)\t= %u\n # of command-queues\t\t\t= 2\n", - szGlobalWorkSize, szLocalWorkSize, szGlobalWorkSize/szLocalWorkSize); - } - - return dAvgTime; -} - -// Function to adjust compute task according to device capability -// This allows a consistent overlap % across a wide variety of GPU's for test purposes -// It also implitly illustrates the relationship between compute capability and overlap at fixed work size -// ********************************************************************* -int AdjustCompute(cl_device_id cdTargetDevice, unsigned int uiNumElements, int iInitLoopCount, int iCycles) -{ - // Locals - double dCopyTime, dComputeTime; - int iComputedLoopCount; - - // Change Source Data - shrFillArray(fSourceA, (int)uiNumElements); - shrFillArray(fSourceB, (int)uiNumElements); - - // Reset Global work size for 1 command-queue, and log work sizes & dimensions - szGlobalWorkSize = shrRoundUp((int)szLocalWorkSize, (int)(uiNumElements/4)); - - // *** Make sure queues are empty and then start timer - clFinish(cqCommandQueue[0]); - clFinish(cqCommandQueue[1]); - shrDeltaT(0); - - // Run the copy iCycles times and measure copy time on this system - for (int i = 0; i < iCycles; i++) - { - // Nonblocking Write of all of input data from host to device in command-queue 0 - ciErrNum = clEnqueueWriteBuffer(cqCommandQueue[0], cmDevSrcA, CL_FALSE, 0, szBuffBytes, (void*)&fSourceA[0], 0, NULL, NULL); - ciErrNum |= clEnqueueWriteBuffer(cqCommandQueue[0], cmDevSrcB, CL_FALSE, 0, szBuffBytes, (void*)&fSourceB[0], 0, NULL, NULL); - ciErrNum |= clFlush(cqCommandQueue[0]); - shrCheckError(ciErrNum, CL_SUCCESS); - } - clFinish(cqCommandQueue[0]); - dCopyTime = shrDeltaT(0); - - // Run the compute iCycles times and measure compute time on this system - for (int i = 0; i < iCycles; i++) - { - // Launch kernel computation, command-queue 0 - ciErrNum = clEnqueueNDRangeKernel(cqCommandQueue[0], ckKernel[0], 1, NULL, &szGlobalWorkSize, &szLocalWorkSize, 0, NULL, NULL); - ciErrNum |= clFlush(cqCommandQueue[0]); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - } - clFinish(cqCommandQueue[0]); - dComputeTime = shrDeltaT(0); - - // Determine number of core loop cycles proportional to copy/compute time ratio - dComputeTime = MAX(dComputeTime, 1.0e-6); - iComputedLoopCount = CLAMP(2, (int)((dCopyTime/dComputeTime) * (double)iInitLoopCount), (iInitLoopCount * 4)); - ciErrNum |= clSetKernelArg(ckKernel[0], 4, sizeof(cl_int), (void*)&iComputedLoopCount); - ciErrNum |= clSetKernelArg(ckKernel[1], 4, sizeof(cl_int), (void*)&iComputedLoopCount); - oclCheckErrorEX(ciErrNum, CL_SUCCESS, pCleanup); - return (iComputedLoopCount); -} - -// Cleanup/Exit function -// ********************************************************************* -void Cleanup (int iExitCode) -{ - // Cleanup allocated objects - shrLog("Starting Cleanup...\n\n"); - if(cPathAndName)free(cPathAndName); - if(cSourceCL)free(cSourceCL); - if(Golden)free(Golden); - if(ckKernel[0])clReleaseKernel(ckKernel[0]); - if(ckKernel[1])clReleaseKernel(ckKernel[1]); - if(cpProgram)clReleaseProgram(cpProgram); - if(fSourceA)clEnqueueUnmapMemObject(cqCommandQueue[0], cmPinnedSrcA, (void*)fSourceA, 0, NULL, NULL); - if(fSourceB)clEnqueueUnmapMemObject(cqCommandQueue[0], cmPinnedSrcB, (void*)fSourceB, 0, NULL, NULL); - if(fResult)clEnqueueUnmapMemObject(cqCommandQueue[0], cmPinnedResult, (void*)fResult, 0, NULL, NULL); - if(cmDevSrcA)clReleaseMemObject(cmDevSrcA); - if(cmDevSrcB)clReleaseMemObject(cmDevSrcB); - if(cmDevResult)clReleaseMemObject(cmDevResult); - if(cmPinnedSrcA)clReleaseMemObject(cmPinnedSrcA); - if(cmPinnedSrcB)clReleaseMemObject(cmPinnedSrcB); - if(cmPinnedResult)clReleaseMemObject(cmPinnedResult); - if(cqCommandQueue[0])clReleaseCommandQueue(cqCommandQueue[0]); - if(cqCommandQueue[1])clReleaseCommandQueue(cqCommandQueue[1]); - if(cxGPUContext)clReleaseContext(cxGPUContext); - if(cdDevices)free(cdDevices); - - // Master status Pass/Fail (all tests) - shrQAFinishExit( *gp_argc, (const char **)*gp_argv, (iExitCode == EXIT_SUCCESS) ? QA_PASSED : QA_FAILED ); -} - -// "Golden" Host processing vector hyptenuse function for comparison purposes -// ********************************************************************* -void VectorHypotHost(const float* pfData1, const float* pfData2, float* pfResult, unsigned int uiNumElements, int iInnerLoopCount) -{ - for (unsigned int i = 0; i < uiNumElements; i++) - { - float fA = pfData1[i]; - float fB = pfData2[i]; - float fC = sqrtf(fA * fA + fB * fB); - - pfResult[i] = fC; - } -} diff --git a/tests/opencl/vectorhypot/oclUtils.cpp b/tests/opencl/vectorhypot/oclUtils.cpp deleted file mode 100644 index 6d920858..00000000 --- a/tests/opencl/vectorhypot/oclUtils.cpp +++ /dev/null @@ -1,806 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -// ********************************************************************* -// Utilities specific to OpenCL samples in NVIDIA GPU Computing SDK -// ********************************************************************* - -#include -#include -#include -#include -#include -#include "oclUtils.h" - -////////////////////////////////////////////////////////////////////////////// -//! Gets the platform ID for NVIDIA if available, otherwise default -//! -//! @return the id -//! @param clSelectedPlatformID OpenCL platoform ID -////////////////////////////////////////////////////////////////////////////// -cl_int oclGetPlatformID(cl_platform_id* clSelectedPlatformID) -{ - char chBuffer[1024]; - cl_uint num_platforms; - cl_platform_id* clPlatformIDs; - cl_int ciErrNum; - *clSelectedPlatformID = NULL; - - // Get OpenCL platform count - ciErrNum = clGetPlatformIDs (0, NULL, &num_platforms); - if (ciErrNum != CL_SUCCESS) - { - shrLog(" Error %i in clGetPlatformIDs Call !!!\n\n", ciErrNum); - return -1000; - } - else - { - if(num_platforms == 0) - { - shrLog("No OpenCL platform found!\n\n"); - return -2000; - } - else - { - // if there's a platform or more, make space for ID's - if ((clPlatformIDs = (cl_platform_id*)malloc(num_platforms * sizeof(cl_platform_id))) == NULL) - { - shrLog("Failed to allocate memory for cl_platform ID's!\n\n"); - return -3000; - } - - // get platform info for each platform and trap the NVIDIA platform if found - ciErrNum = clGetPlatformIDs (num_platforms, clPlatformIDs, NULL); - for(cl_uint i = 0; i < num_platforms; ++i) - { - ciErrNum = clGetPlatformInfo (clPlatformIDs[i], CL_PLATFORM_NAME, 1024, &chBuffer, NULL); - if(ciErrNum == CL_SUCCESS) - { - if(strstr(chBuffer, "NVIDIA") != NULL) - { - *clSelectedPlatformID = clPlatformIDs[i]; - break; - } - } - } - - // default to zeroeth platform if NVIDIA not found - if(*clSelectedPlatformID == NULL) - { - shrLog("WARNING: NVIDIA OpenCL platform not found - defaulting to first platform!\n\n"); - *clSelectedPlatformID = clPlatformIDs[0]; - } - - free(clPlatformIDs); - } - } - - return CL_SUCCESS; -} - -////////////////////////////////////////////////////////////////////////////// -//! Print the device name -//! -//! @param iLogMode enum LOGBOTH, LOGCONSOLE, LOGFILE -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -void oclPrintDevName(int iLogMode, cl_device_id device) -{ - char device_string[1024]; - clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, "%s\n", device_string); -} - -////////////////////////////////////////////////////////////////////////////// -//! Print info about the device -//! -//! @param iLogMode enum LOGBOTH, LOGCONSOLE, LOGFILE -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -void oclPrintDevInfo(int iLogMode, cl_device_id device) -{ - char device_string[1024]; - bool nv_device_attibute_query = false; - - // CL_DEVICE_NAME - clGetDeviceInfo(device, CL_DEVICE_NAME, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_NAME: \t\t\t%s\n", device_string); - - // CL_DEVICE_VENDOR - clGetDeviceInfo(device, CL_DEVICE_VENDOR, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_VENDOR: \t\t\t%s\n", device_string); - - // CL_DRIVER_VERSION - clGetDeviceInfo(device, CL_DRIVER_VERSION, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DRIVER_VERSION: \t\t\t%s\n", device_string); - - // CL_DEVICE_VERSION - clGetDeviceInfo(device, CL_DEVICE_VERSION, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_VERSION: \t\t\t%s\n", device_string); - - // CL_DEVICE_OPENCL_C_VERSION (if CL_DEVICE_VERSION version > 1.0) - if(strncmp("OpenCL 1.0", device_string, 10) != 0) - { - // This code is unused for devices reporting OpenCL 1.0, but a def is needed anyway to allow compilation using v 1.0 headers - // This constant isn't #defined in 1.0 - #ifndef CL_DEVICE_OPENCL_C_VERSION - #define CL_DEVICE_OPENCL_C_VERSION 0x103D - #endif - - clGetDeviceInfo(device, CL_DEVICE_OPENCL_C_VERSION, sizeof(device_string), &device_string, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_OPENCL_C_VERSION: \t\t%s\n", device_string); - } - - // CL_DEVICE_TYPE - cl_device_type type; - clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(type), &type, NULL); - if( type & CL_DEVICE_TYPE_CPU ) - shrLogEx(iLogMode, 0, " CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_CPU"); - if( type & CL_DEVICE_TYPE_GPU ) - shrLogEx(iLogMode, 0, " CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_GPU"); - if( type & CL_DEVICE_TYPE_ACCELERATOR ) - shrLogEx(iLogMode, 0, " CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_ACCELERATOR"); - if( type & CL_DEVICE_TYPE_DEFAULT ) - shrLogEx(iLogMode, 0, " CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_DEFAULT"); - - // CL_DEVICE_MAX_COMPUTE_UNITS - cl_uint compute_units; - clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(compute_units), &compute_units, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_COMPUTE_UNITS:\t\t%u\n", compute_units); - - // CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS - size_t workitem_dims; - clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof(workitem_dims), &workitem_dims, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS:\t%u\n", workitem_dims); - - // CL_DEVICE_MAX_WORK_ITEM_SIZES - size_t workitem_size[3]; - clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(workitem_size), &workitem_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_WORK_ITEM_SIZES:\t%u / %u / %u \n", workitem_size[0], workitem_size[1], workitem_size[2]); - - // CL_DEVICE_MAX_WORK_GROUP_SIZE - size_t workgroup_size; - clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(workgroup_size), &workgroup_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_WORK_GROUP_SIZE:\t%u\n", workgroup_size); - - // CL_DEVICE_MAX_CLOCK_FREQUENCY - cl_uint clock_frequency; - clGetDeviceInfo(device, CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(clock_frequency), &clock_frequency, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_CLOCK_FREQUENCY:\t%u MHz\n", clock_frequency); - - // CL_DEVICE_ADDRESS_BITS - cl_uint addr_bits; - clGetDeviceInfo(device, CL_DEVICE_ADDRESS_BITS, sizeof(addr_bits), &addr_bits, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_ADDRESS_BITS:\t\t%u\n", addr_bits); - - // CL_DEVICE_MAX_MEM_ALLOC_SIZE - cl_ulong max_mem_alloc_size; - clGetDeviceInfo(device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(max_mem_alloc_size), &max_mem_alloc_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_MEM_ALLOC_SIZE:\t\t%u MByte\n", (unsigned int)(max_mem_alloc_size / (1024 * 1024))); - - // CL_DEVICE_GLOBAL_MEM_SIZE - cl_ulong mem_size; - clGetDeviceInfo(device, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(mem_size), &mem_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_GLOBAL_MEM_SIZE:\t\t%u MByte\n", (unsigned int)(mem_size / (1024 * 1024))); - - // CL_DEVICE_ERROR_CORRECTION_SUPPORT - cl_bool error_correction_support; - clGetDeviceInfo(device, CL_DEVICE_ERROR_CORRECTION_SUPPORT, sizeof(error_correction_support), &error_correction_support, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_ERROR_CORRECTION_SUPPORT:\t%s\n", error_correction_support == CL_TRUE ? "yes" : "no"); - - // CL_DEVICE_LOCAL_MEM_TYPE - cl_device_local_mem_type local_mem_type; - clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_TYPE, sizeof(local_mem_type), &local_mem_type, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_LOCAL_MEM_TYPE:\t\t%s\n", local_mem_type == 1 ? "local" : "global"); - - // CL_DEVICE_LOCAL_MEM_SIZE - clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(mem_size), &mem_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_LOCAL_MEM_SIZE:\t\t%u KByte\n", (unsigned int)(mem_size / 1024)); - - // CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE - clGetDeviceInfo(device, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, sizeof(mem_size), &mem_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE:\t%u KByte\n", (unsigned int)(mem_size / 1024)); - - // CL_DEVICE_QUEUE_PROPERTIES - cl_command_queue_properties queue_properties; - clGetDeviceInfo(device, CL_DEVICE_QUEUE_PROPERTIES, sizeof(queue_properties), &queue_properties, NULL); - if( queue_properties & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE ) - shrLogEx(iLogMode, 0, " CL_DEVICE_QUEUE_PROPERTIES:\t\t%s\n", "CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE"); - if( queue_properties & CL_QUEUE_PROFILING_ENABLE ) - shrLogEx(iLogMode, 0, " CL_DEVICE_QUEUE_PROPERTIES:\t\t%s\n", "CL_QUEUE_PROFILING_ENABLE"); - - // CL_DEVICE_IMAGE_SUPPORT - cl_bool image_support; - clGetDeviceInfo(device, CL_DEVICE_IMAGE_SUPPORT, sizeof(image_support), &image_support, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_IMAGE_SUPPORT:\t\t%u\n", image_support); - - // CL_DEVICE_MAX_READ_IMAGE_ARGS - cl_uint max_read_image_args; - clGetDeviceInfo(device, CL_DEVICE_MAX_READ_IMAGE_ARGS, sizeof(max_read_image_args), &max_read_image_args, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_READ_IMAGE_ARGS:\t%u\n", max_read_image_args); - - // CL_DEVICE_MAX_WRITE_IMAGE_ARGS - cl_uint max_write_image_args; - clGetDeviceInfo(device, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, sizeof(max_write_image_args), &max_write_image_args, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_MAX_WRITE_IMAGE_ARGS:\t%u\n", max_write_image_args); - - // CL_DEVICE_SINGLE_FP_CONFIG - cl_device_fp_config fp_config; - clGetDeviceInfo(device, CL_DEVICE_SINGLE_FP_CONFIG, sizeof(cl_device_fp_config), &fp_config, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_SINGLE_FP_CONFIG:\t\t%s%s%s%s%s%s\n", - fp_config & CL_FP_DENORM ? "denorms " : "", - fp_config & CL_FP_INF_NAN ? "INF-quietNaNs " : "", - fp_config & CL_FP_ROUND_TO_NEAREST ? "round-to-nearest " : "", - fp_config & CL_FP_ROUND_TO_ZERO ? "round-to-zero " : "", - fp_config & CL_FP_ROUND_TO_INF ? "round-to-inf " : "", - fp_config & CL_FP_FMA ? "fma " : ""); - - // CL_DEVICE_IMAGE2D_MAX_WIDTH, CL_DEVICE_IMAGE2D_MAX_HEIGHT, CL_DEVICE_IMAGE3D_MAX_WIDTH, CL_DEVICE_IMAGE3D_MAX_HEIGHT, CL_DEVICE_IMAGE3D_MAX_DEPTH - size_t szMaxDims[5]; - shrLogEx(iLogMode, 0, "\n CL_DEVICE_IMAGE "); - clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof(size_t), &szMaxDims[0], NULL); - shrLogEx(iLogMode, 0, "\t\t\t2D_MAX_WIDTH\t %u\n", szMaxDims[0]); - clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof(size_t), &szMaxDims[1], NULL); - shrLogEx(iLogMode, 0, "\t\t\t\t\t2D_MAX_HEIGHT\t %u\n", szMaxDims[1]); - clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_WIDTH, sizeof(size_t), &szMaxDims[2], NULL); - shrLogEx(iLogMode, 0, "\t\t\t\t\t3D_MAX_WIDTH\t %u\n", szMaxDims[2]); - clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_HEIGHT, sizeof(size_t), &szMaxDims[3], NULL); - shrLogEx(iLogMode, 0, "\t\t\t\t\t3D_MAX_HEIGHT\t %u\n", szMaxDims[3]); - clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_DEPTH, sizeof(size_t), &szMaxDims[4], NULL); - shrLogEx(iLogMode, 0, "\t\t\t\t\t3D_MAX_DEPTH\t %u\n", szMaxDims[4]); - - // CL_DEVICE_EXTENSIONS: get device extensions, and if any then parse & log the string onto separate lines - clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, sizeof(device_string), &device_string, NULL); - if (device_string != 0) - { - shrLogEx(iLogMode, 0, "\n CL_DEVICE_EXTENSIONS:"); - std::string stdDevString; - stdDevString = std::string(device_string); - size_t szOldPos = 0; - size_t szSpacePos = stdDevString.find(' ', szOldPos); // extensions string is space delimited - while (szSpacePos != stdDevString.npos) - { - if( strcmp("cl_nv_device_attribute_query", stdDevString.substr(szOldPos, szSpacePos - szOldPos).c_str()) == 0 ) - nv_device_attibute_query = true; - - if (szOldPos > 0) - { - shrLogEx(iLogMode, 0, "\t\t"); - } - shrLogEx(iLogMode, 0, "\t\t\t%s\n", stdDevString.substr(szOldPos, szSpacePos - szOldPos).c_str()); - - do { - szOldPos = szSpacePos + 1; - szSpacePos = stdDevString.find(' ', szOldPos); - } while (szSpacePos == szOldPos); - } - shrLogEx(iLogMode, 0, "\n"); - } - else - { - shrLogEx(iLogMode, 0, " CL_DEVICE_EXTENSIONS: None\n"); - } - - if(nv_device_attibute_query) - { - cl_uint compute_capability_major, compute_capability_minor; - clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, sizeof(cl_uint), &compute_capability_major, NULL); - clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, sizeof(cl_uint), &compute_capability_minor, NULL); - shrLogEx(iLogMode, 0, "\n CL_DEVICE_COMPUTE_CAPABILITY_NV:\t%u.%u\n", compute_capability_major, compute_capability_minor); - - shrLogEx(iLogMode, 0, " NUMBER OF MULTIPROCESSORS:\t\t%u\n", compute_units); // this is the same value reported by CL_DEVICE_MAX_COMPUTE_UNITS - shrLogEx(iLogMode, 0, " NUMBER OF CUDA CORES:\t\t\t%u\n", ConvertSMVer2Cores(compute_capability_major, compute_capability_minor) * compute_units); - - cl_uint regs_per_block; - clGetDeviceInfo(device, CL_DEVICE_REGISTERS_PER_BLOCK_NV, sizeof(cl_uint), ®s_per_block, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_REGISTERS_PER_BLOCK_NV:\t%u\n", regs_per_block); - - cl_uint warp_size; - clGetDeviceInfo(device, CL_DEVICE_WARP_SIZE_NV, sizeof(cl_uint), &warp_size, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_WARP_SIZE_NV:\t\t%u\n", warp_size); - - cl_bool gpu_overlap; - clGetDeviceInfo(device, CL_DEVICE_GPU_OVERLAP_NV, sizeof(cl_bool), &gpu_overlap, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_GPU_OVERLAP_NV:\t\t%s\n", gpu_overlap == CL_TRUE ? "CL_TRUE" : "CL_FALSE"); - - cl_bool exec_timeout; - clGetDeviceInfo(device, CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, sizeof(cl_bool), &exec_timeout, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV:\t%s\n", exec_timeout == CL_TRUE ? "CL_TRUE" : "CL_FALSE"); - - cl_bool integrated_memory; - clGetDeviceInfo(device, CL_DEVICE_INTEGRATED_MEMORY_NV, sizeof(cl_bool), &integrated_memory, NULL); - shrLogEx(iLogMode, 0, " CL_DEVICE_INTEGRATED_MEMORY_NV:\t%s\n", integrated_memory == CL_TRUE ? "CL_TRUE" : "CL_FALSE"); - } - - // CL_DEVICE_PREFERRED_VECTOR_WIDTH_ - shrLogEx(iLogMode, 0, " CL_DEVICE_PREFERRED_VECTOR_WIDTH_\t"); - cl_uint vec_width [6]; - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, sizeof(cl_uint), &vec_width[0], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, sizeof(cl_uint), &vec_width[1], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, sizeof(cl_uint), &vec_width[2], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, sizeof(cl_uint), &vec_width[3], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, sizeof(cl_uint), &vec_width[4], NULL); - clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, sizeof(cl_uint), &vec_width[5], NULL); - shrLogEx(iLogMode, 0, "CHAR %u, SHORT %u, INT %u, LONG %u, FLOAT %u, DOUBLE %u\n\n\n", - vec_width[0], vec_width[1], vec_width[2], vec_width[3], vec_width[4], vec_width[5]); -} - -////////////////////////////////////////////////////////////////////////////// -//! Get and return device capability -//! -//! @return the 2 digit integer representation of device Cap (major minor). return -1 if NA -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -int oclGetDevCap(cl_device_id device) -{ - char cDevString[1024]; - bool bDevAttributeQuery = false; - int iDevArch = -1; - - // Get device extensions, and if any then search for cl_nv_device_attribute_query - clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, sizeof(cDevString), &cDevString, NULL); - if (cDevString != 0) - { - std::string stdDevString; - stdDevString = std::string(cDevString); - size_t szOldPos = 0; - size_t szSpacePos = stdDevString.find(' ', szOldPos); // extensions string is space delimited - while (szSpacePos != stdDevString.npos) - { - if( strcmp("cl_nv_device_attribute_query", stdDevString.substr(szOldPos, szSpacePos - szOldPos).c_str()) == 0 ) - { - bDevAttributeQuery = true; - } - - do { - szOldPos = szSpacePos + 1; - szSpacePos = stdDevString.find(' ', szOldPos); - } while (szSpacePos == szOldPos); - } - } - - // if search succeeded, get device caps - if(bDevAttributeQuery) - { - cl_int iComputeCapMajor, iComputeCapMinor; - clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, sizeof(cl_uint), (void*)&iComputeCapMajor, NULL); - clGetDeviceInfo(device, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, sizeof(cl_uint), (void*)&iComputeCapMinor, NULL); - iDevArch = (10 * iComputeCapMajor) + iComputeCapMinor; - } - - return iDevArch; -} - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of the first device from the context -//! -//! @return the id -//! @param cxGPUContext OpenCL context -////////////////////////////////////////////////////////////////////////////// -cl_device_id oclGetFirstDev(cl_context cxGPUContext) -{ - size_t szParmDataBytes; - cl_device_id* cdDevices; - - // get the list of GPU devices associated with context - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, 0, NULL, &szParmDataBytes); - cdDevices = (cl_device_id*) malloc(szParmDataBytes); - - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, szParmDataBytes, cdDevices, NULL); - - cl_device_id first = cdDevices[0]; - free(cdDevices); - - return first; -} - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of device with maximal FLOPS from the context -//! -//! @return the id -//! @param cxGPUContext OpenCL context -////////////////////////////////////////////////////////////////////////////// -cl_device_id oclGetMaxFlopsDev(cl_context cxGPUContext) -{ - size_t szParmDataBytes; - cl_device_id* cdDevices; - - // get the list of GPU devices associated with context - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, 0, NULL, &szParmDataBytes); - cdDevices = (cl_device_id*) malloc(szParmDataBytes); - size_t device_count = szParmDataBytes / sizeof(cl_device_id); - - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, szParmDataBytes, cdDevices, NULL); - - cl_device_id max_flops_device = cdDevices[0]; - int max_flops = 0; - - size_t current_device = 0; - - // CL_DEVICE_MAX_COMPUTE_UNITS - cl_uint compute_units; - clGetDeviceInfo(cdDevices[current_device], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(compute_units), &compute_units, NULL); - - // CL_DEVICE_MAX_CLOCK_FREQUENCY - cl_uint clock_frequency; - clGetDeviceInfo(cdDevices[current_device], CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(clock_frequency), &clock_frequency, NULL); - - max_flops = compute_units * clock_frequency; - ++current_device; - - while( current_device < device_count ) - { - // CL_DEVICE_MAX_COMPUTE_UNITS - cl_uint compute_units; - clGetDeviceInfo(cdDevices[current_device], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(compute_units), &compute_units, NULL); - - // CL_DEVICE_MAX_CLOCK_FREQUENCY - cl_uint clock_frequency; - clGetDeviceInfo(cdDevices[current_device], CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(clock_frequency), &clock_frequency, NULL); - - int flops = compute_units * clock_frequency; - if( flops > max_flops ) - { - max_flops = flops; - max_flops_device = cdDevices[current_device]; - } - ++current_device; - } - - free(cdDevices); - - return max_flops_device; -} - -////////////////////////////////////////////////////////////////////////////// -//! Loads a Program file and prepends the cPreamble to the code. -//! -//! @return the source string if succeeded, 0 otherwise -//! @param cFilename program filename -//! @param cPreamble code that is prepended to the loaded file, typically a set of #defines or a header -//! @param szFinalLength returned length of the code string -////////////////////////////////////////////////////////////////////////////// -char* oclLoadProgSource(const char* cFilename, const char* cPreamble, size_t* szFinalLength) -{ - // locals - FILE* pFileStream = NULL; - size_t szSourceLength; - - // open the OpenCL source code file - #ifdef _WIN32 // Windows version - if(fopen_s(&pFileStream, cFilename, "rb") != 0) - { - return NULL; - } - #else // Linux version - pFileStream = fopen(cFilename, "rb"); - if(pFileStream == 0) - { - return NULL; - } - #endif - - size_t szPreambleLength = strlen(cPreamble); - - // get the length of the source code - fseek(pFileStream, 0, SEEK_END); - szSourceLength = ftell(pFileStream); - fseek(pFileStream, 0, SEEK_SET); - - // allocate a buffer for the source code string and read it in - char* cSourceString = (char *)malloc(szSourceLength + szPreambleLength + 1); - memcpy(cSourceString, cPreamble, szPreambleLength); - if (fread((cSourceString) + szPreambleLength, szSourceLength, 1, pFileStream) != 1) - { - fclose(pFileStream); - free(cSourceString); - return 0; - } - - // close the file and return the total length of the combined (preamble + source) string - fclose(pFileStream); - if(szFinalLength != 0) - { - *szFinalLength = szSourceLength + szPreambleLength; - } - cSourceString[szSourceLength + szPreambleLength] = '\0'; - - return cSourceString; -} - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of the nth device from the context -//! -//! @return the id or -1 when out of range -//! @param cxGPUContext OpenCL context -//! @param device_idx index of the device of interest -////////////////////////////////////////////////////////////////////////////// -cl_device_id oclGetDev(cl_context cxGPUContext, unsigned int nr) -{ - size_t szParmDataBytes; - cl_device_id* cdDevices; - - // get the list of GPU devices associated with context - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, 0, NULL, &szParmDataBytes); - - if( szParmDataBytes / sizeof(cl_device_id) <= nr ) { - return (cl_device_id)-1; - } - - cdDevices = (cl_device_id*) malloc(szParmDataBytes); - - clGetContextInfo(cxGPUContext, CL_CONTEXT_DEVICES, szParmDataBytes, cdDevices, NULL); - - cl_device_id device = cdDevices[nr]; - free(cdDevices); - - return device; -} - -////////////////////////////////////////////////////////////////////////////// -//! Get the binary (PTX) of the program associated with the device -//! -//! @param cpProgram OpenCL program -//! @param cdDevice device of interest -//! @param binary returned code -//! @param length length of returned code -////////////////////////////////////////////////////////////////////////////// -void oclGetProgBinary( cl_program cpProgram, cl_device_id cdDevice, char** binary, size_t* length) -{ - // Grab the number of devices associated witht the program - cl_uint num_devices; - clGetProgramInfo(cpProgram, CL_PROGRAM_NUM_DEVICES, sizeof(cl_uint), &num_devices, NULL); - - // Grab the device ids - cl_device_id* devices = (cl_device_id*) malloc(num_devices * sizeof(cl_device_id)); - clGetProgramInfo(cpProgram, CL_PROGRAM_DEVICES, num_devices * sizeof(cl_device_id), devices, 0); - - // Grab the sizes of the binaries - size_t* binary_sizes = (size_t*)malloc(num_devices * sizeof(size_t)); - clGetProgramInfo(cpProgram, CL_PROGRAM_BINARY_SIZES, num_devices * sizeof(size_t), binary_sizes, NULL); - - // Now get the binaries - char** ptx_code = (char**) malloc(num_devices * sizeof(char*)); - for( unsigned int i=0; i= 0 && index < errorCount) ? errorString[index] : "Unspecified Error"; -} - -// Helper function to get OpenCL image format string (channel order and type) from constant -// ********************************************************************* -const char* oclImageFormatString(cl_uint uiImageFormat) -{ - // cl_channel_order - if (uiImageFormat == CL_R)return "CL_R"; - if (uiImageFormat == CL_A)return "CL_A"; - if (uiImageFormat == CL_RG)return "CL_RG"; - if (uiImageFormat == CL_RA)return "CL_RA"; - if (uiImageFormat == CL_RGB)return "CL_RGB"; - if (uiImageFormat == CL_RGBA)return "CL_RGBA"; - if (uiImageFormat == CL_BGRA)return "CL_BGRA"; - if (uiImageFormat == CL_ARGB)return "CL_ARGB"; - if (uiImageFormat == CL_INTENSITY)return "CL_INTENSITY"; - if (uiImageFormat == CL_LUMINANCE)return "CL_LUMINANCE"; - - // cl_channel_type - if (uiImageFormat == CL_SNORM_INT8)return "CL_SNORM_INT8"; - if (uiImageFormat == CL_SNORM_INT16)return "CL_SNORM_INT16"; - if (uiImageFormat == CL_UNORM_INT8)return "CL_UNORM_INT8"; - if (uiImageFormat == CL_UNORM_INT16)return "CL_UNORM_INT16"; - if (uiImageFormat == CL_UNORM_SHORT_565)return "CL_UNORM_SHORT_565"; - if (uiImageFormat == CL_UNORM_SHORT_555)return "CL_UNORM_SHORT_555"; - if (uiImageFormat == CL_UNORM_INT_101010)return "CL_UNORM_INT_101010"; - if (uiImageFormat == CL_SIGNED_INT8)return "CL_SIGNED_INT8"; - if (uiImageFormat == CL_SIGNED_INT16)return "CL_SIGNED_INT16"; - if (uiImageFormat == CL_SIGNED_INT32)return "CL_SIGNED_INT32"; - if (uiImageFormat == CL_UNSIGNED_INT8)return "CL_UNSIGNED_INT8"; - if (uiImageFormat == CL_UNSIGNED_INT16)return "CL_UNSIGNED_INT16"; - if (uiImageFormat == CL_UNSIGNED_INT32)return "CL_UNSIGNED_INT32"; - if (uiImageFormat == CL_HALF_FLOAT)return "CL_HALF_FLOAT"; - if (uiImageFormat == CL_FLOAT)return "CL_FLOAT"; - - // unknown constant - return "Unknown"; -} diff --git a/tests/opencl/vectorhypot/oclUtils.h b/tests/opencl/vectorhypot/oclUtils.h deleted file mode 100644 index 2b109e18..00000000 --- a/tests/opencl/vectorhypot/oclUtils.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -#ifndef OCL_UTILS_H -#define OCL_UTILS_H - -// ********************************************************************* -// Utilities specific to OpenCL samples in NVIDIA GPU Computing SDK -// ********************************************************************* - -// Common headers: Cross-API utililties and OpenCL header -#include - -// All OpenCL headers -#if defined (__APPLE__) || defined(MACOSX) - #include -#else - #include -#endif - -// Includes -#include -#include -#include - -// For systems with CL_EXT that are not updated with these extensions, we copied these -// extensions from -#ifndef CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV - /* cl_nv_device_attribute_query extension - no extension #define since it has no functions */ - #define CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV 0x4000 - #define CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV 0x4001 - #define CL_DEVICE_REGISTERS_PER_BLOCK_NV 0x4002 - #define CL_DEVICE_WARP_SIZE_NV 0x4003 - #define CL_DEVICE_GPU_OVERLAP_NV 0x4004 - #define CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV 0x4005 - #define CL_DEVICE_INTEGRATED_MEMORY_NV 0x4006 -#endif - -// reminders for build output window and log -#ifdef _WIN32 - #pragma message ("Note: including shrUtils.h") - #pragma message ("Note: including opencl.h") -#endif - -// SDK Revision # -#define OCL_SDKREVISION "7027912" - -// Error and Exit Handling Macros... -// ********************************************************************* -// Full error handling macro with Cleanup() callback (if supplied)... -// (Companion Inline Function lower on page) -#define oclCheckErrorEX(a, b, c) __oclCheckErrorEX(a, b, c, __FILE__ , __LINE__) - -// Short version without Cleanup() callback pointer -// Both Input (a) and Reference (b) are specified as args -#define oclCheckError(a, b) oclCheckErrorEX(a, b, 0) - -////////////////////////////////////////////////////////////////////////////// -//! Gets the platform ID for NVIDIA if available, otherwise default to platform 0 -//! -//! @return the id -//! @param clSelectedPlatformID OpenCL platform ID -////////////////////////////////////////////////////////////////////////////// -extern "C" cl_int oclGetPlatformID(cl_platform_id* clSelectedPlatformID); - -////////////////////////////////////////////////////////////////////////////// -//! Print info about the device -//! -//! @param iLogMode enum LOGBOTH, LOGCONSOLE, LOGFILE -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclPrintDevInfo(int iLogMode, cl_device_id device); - -////////////////////////////////////////////////////////////////////////////// -//! Get and return device capability -//! -//! @return the 2 digit integer representation of device Cap (major minor). return -1 if NA -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -extern "C" int oclGetDevCap(cl_device_id device); - -////////////////////////////////////////////////////////////////////////////// -//! Print the device name -//! -//! @param iLogMode enum LOGBOTH, LOGCONSOLE, LOGFILE -//! @param device OpenCL id of the device -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclPrintDevName(int iLogMode, cl_device_id device); - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of the first device from the context -//! -//! @return the id -//! @param cxGPUContext OpenCL context -////////////////////////////////////////////////////////////////////////////// -extern "C" cl_device_id oclGetFirstDev(cl_context cxGPUContext); - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of the nth device from the context -//! -//! @return the id or -1 when out of range -//! @param cxGPUContext OpenCL context -//! @param device_idx index of the device of interest -////////////////////////////////////////////////////////////////////////////// -extern "C" cl_device_id oclGetDev(cl_context cxGPUContext, unsigned int device_idx); - -////////////////////////////////////////////////////////////////////////////// -//! Gets the id of device with maximal FLOPS from the context -//! -//! @return the id -//! @param cxGPUContext OpenCL context -////////////////////////////////////////////////////////////////////////////// -extern "C" cl_device_id oclGetMaxFlopsDev(cl_context cxGPUContext); - -////////////////////////////////////////////////////////////////////////////// -//! Loads a Program file and prepends the cPreamble to the code. -//! -//! @return the source string if succeeded, 0 otherwise -//! @param cFilename program filename -//! @param cPreamble code that is prepended to the loaded file, typically a set of #defines or a header -//! @param szFinalLength returned length of the code string -////////////////////////////////////////////////////////////////////////////// -extern "C" char* oclLoadProgSource(const char* cFilename, const char* cPreamble, size_t* szFinalLength); - -////////////////////////////////////////////////////////////////////////////// -//! Get the binary (PTX) of the program associated with the device -//! -//! @param cpProgram OpenCL program -//! @param cdDevice device of interest -//! @param binary returned code -//! @param length length of returned code -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclGetProgBinary( cl_program cpProgram, cl_device_id cdDevice, char** binary, size_t* length); - -////////////////////////////////////////////////////////////////////////////// -//! Get and log the binary (PTX) from the OpenCL compiler for the requested program & device -//! -//! @param cpProgram OpenCL program -//! @param cdDevice device of interest -//! @param const char* cPtxFileName optional PTX file name -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclLogPtx(cl_program cpProgram, cl_device_id cdDevice, const char* cPtxFileName); - -////////////////////////////////////////////////////////////////////////////// -//! Get and log the Build Log from the OpenCL compiler for the requested program & device -//! -//! @param cpProgram OpenCL program -//! @param cdDevice device of interest -////////////////////////////////////////////////////////////////////////////// -extern "C" void oclLogBuildInfo(cl_program cpProgram, cl_device_id cdDevice); - -// Helper function for De-allocating cl objects -// ********************************************************************* -extern "C" void oclDeleteMemObjs(cl_mem* cmMemObjs, int iNumObjs); - -// Helper function to get OpenCL error string from constant -// ********************************************************************* -extern "C" const char* oclErrorString(cl_int error); - -// Helper function to get OpenCL image format string (channel order and type) from constant -// ********************************************************************* -extern "C" const char* oclImageFormatString(cl_uint uiImageFormat); - -// companion inline function for error checking and exit on error WITH Cleanup Callback (if supplied) -// ********************************************************************* -inline void __oclCheckErrorEX(cl_int iSample, cl_int iReference, void (*pCleanup)(int), const char* cFile, const int iLine) -{ - // An error condition is defined by the sample/test value not equal to the reference - if (iReference != iSample) - { - // If the sample/test value isn't equal to the ref, it's an error by defnition, so override 0 sample/test value - iSample = (iSample == 0) ? -9999 : iSample; - - // Log the error info - shrLog("\n !!! Error # %i (%s) at line %i , in file %s !!!\n\n", iSample, oclErrorString(iSample), iLine, cFile); - - // Cleanup and exit, or just exit if no cleanup function pointer provided. Use iSample (error code in this case) as process exit code. - if (pCleanup != NULL) - { - pCleanup(iSample); - } - else - { - shrLogEx(LOGBOTH | CLOSELOG, 0, "Exiting...\n"); - exit(iSample); - } - } -} - -#endif \ No newline at end of file diff --git a/tests/opencl/vectorhypot/shrQATest.h b/tests/opencl/vectorhypot/shrQATest.h deleted file mode 100644 index 245cf8dc..00000000 --- a/tests/opencl/vectorhypot/shrQATest.h +++ /dev/null @@ -1,238 +0,0 @@ -/* -* Copyright 1993-2010 NVIDIA Corporation. All rights reserved. -* -* Please refer to the NVIDIA end user license agreement (EULA) associated -* with this source code for terms and conditions that govern your use of -* this software. Any use, reproduction, disclosure, or distribution of -* this software and related documentation outside the terms of the EULA -* is strictly prohibited. -* -*/ - -#ifndef SHR_QATEST_H -#define SHR_QATEST_H - -// ********************************************************************* -// Generic utilities for NVIDIA GPU Computing SDK -// ********************************************************************* - -// OS dependent includes -#ifdef _WIN32 - #pragma message ("Note: including windows.h") - #pragma message ("Note: including math.h") - #pragma message ("Note: including assert.h") - #pragma message ("Note: including time.h") - -// Headers needed for Windows - #include - #include -#else - // Headers needed for Linux - #include - #include - #include - #include - #include - #include - #include - #include - #include -#endif - -#ifndef STRCASECMP -#ifdef _WIN32 -#define STRCASECMP _stricmp -#else -#define STRCASECMP strcasecmp -#endif -#endif - -#ifndef STRNCASECMP -#ifdef _WIN32 -#define STRNCASECMP _strnicmp -#else -#define STRNCASECMP strncasecmp -#endif -#endif - - -// Standardized QA Start/Finish for CUDA SDK tests -#define shrQAStart(a, b) __shrQAStart(a, b) -#define shrQAFinish(a, b, c) __shrQAFinish(a, b, c) -#define shrQAFinish2(a, b, c, d) __shrQAFinish2(a, b, c, d) - -inline int findExeNameStart(const char *exec_name) -{ - int exename_start = (int)strlen(exec_name); - - while( (exename_start > 0) && - (exec_name[exename_start] != '\\') && - (exec_name[exename_start] != '/') ) - { - exename_start--; - } - if (exec_name[exename_start] == '\\' || - exec_name[exename_start] == '/') - { - return exename_start+1; - } else { - return exename_start; - } -} - -inline int __shrQAStart(int argc, char **argv) -{ - bool bQATest = false; - // First clear the output buffer - fflush(stdout); - fflush(stdout); - - for (int i=1; i < argc; i++) { - int string_start = 0; - while (argv[i][string_start] == '-') - string_start++; - char *string_argv = &argv[i][string_start]; - - if (!STRCASECMP(string_argv, "qatest")) { - bQATest = true; - } - } - - // We don't want to print the entire path, so we search for the first - int exename_start = findExeNameStart(argv[0]); - if (bQATest) { - fprintf(stdout, "&&&& RUNNING %s", &(argv[0][exename_start])); - for (int i=1; i < argc; i++) fprintf(stdout, " %s", argv[i]); - fprintf(stdout, "\n"); - } else { - fprintf(stdout, "[%s] starting...\n", &(argv[0][exename_start])); - } - fflush(stdout); - printf("\n"); fflush(stdout); - return exename_start; -} - -enum eQAstatus { - QA_FAILED = 0, - QA_PASSED = 1, - QA_WAIVED = 2 -}; - -inline void __ExitInTime(int seconds) -{ - fprintf(stdout, "> exiting in %d seconds: ", seconds); - fflush(stdout); - time_t t; - int count; - for (t=time(0)+seconds, count=seconds; time(0) < t; count--) { - fprintf(stdout, "%d...", count); -#ifdef WIN32 - Sleep(1000); -#else - sleep(1); -#endif - } - fprintf(stdout,"done!\n\n"); - fflush(stdout); -} - - -inline void __shrQAFinish(int argc, const char **argv, int iStatus) -{ - // By default QATest is disabled and NoPrompt is Enabled (times out at seconds passed into __ExitInTime() ) - bool bQATest = false, bNoPrompt = true, bQuitInTime = true; - const char *sStatus[] = { "FAILED", "PASSED", "WAIVED", NULL }; - - for (int i=1; i < argc; i++) { - int string_start = 0; - while (argv[i][string_start] == '-') - string_start++; - - const char *string_argv = &argv[i][string_start]; - if (!STRCASECMP(string_argv, "qatest")) { - bQATest = true; - } - // For SDK individual samples that don't specify -noprompt or -prompt, - // a 3 second delay will happen before exiting, giving a user time to view results - if (!STRCASECMP(string_argv, "noprompt") || !STRCASECMP(string_argv, "help")) { - bNoPrompt = true; - bQuitInTime = false; - } - if (!STRCASECMP(string_argv, "prompt")) { - bNoPrompt = false; - bQuitInTime = false; - } - } - - int exename_start = findExeNameStart(argv[0]); - if (bQATest) { - fprintf(stdout, "&&&& %s %s", sStatus[iStatus], &(argv[0][exename_start])); - for (int i=1; i < argc; i++) fprintf(stdout, " %s", argv[i]); - fprintf(stdout, "\n"); - } else { - fprintf(stdout, "[%s] test results...\n%s\n", &(argv[0][exename_start]), sStatus[iStatus]); - } - fflush(stdout); - printf("\n"); fflush(stdout); - if (bQuitInTime) { - __ExitInTime(3); - } else { - if (!bNoPrompt) { - fprintf(stdout, "\nPress to exit...\n"); - fflush(stdout); - getchar(); - } - } -} - -inline void __shrQAFinish2(bool bQATest, int argc, const char **argv, int iStatus) -{ - bool bQuitInTime = true; - const char *sStatus[] = { "FAILED", "PASSED", "WAIVED", NULL }; - - for (int i=1; i < argc; i++) { - int string_start = 0; - while (argv[i][string_start] == '-') - string_start++; - - const char *string_argv = &argv[i][string_start]; - // For SDK individual samples that don't specify -noprompt or -prompt, - // a 3 second delay will happen before exiting, giving a user time to view results - if (!STRCASECMP(string_argv, "noprompt") || !STRCASECMP(string_argv, "help")) { - bQuitInTime = false; - } - if (!STRCASECMP(string_argv, "prompt")) { - bQuitInTime = false; - } - } - - int exename_start = findExeNameStart(argv[0]); - if (bQATest) { - fprintf(stdout, "&&&& %s %s", sStatus[iStatus], &(argv[0][exename_start])); - for (int i=1; i < argc; i++) fprintf(stdout, " %s", argv[i]); - fprintf(stdout, "\n"); - } else { - fprintf(stdout, "[%s] test results...\n%s\n", &(argv[0][exename_start]), sStatus[iStatus]); - } - fflush(stdout); - - if (bQuitInTime) { - __ExitInTime(3); - } -} - -inline void shrQAFinishExit(int argc, const char **argv, int iStatus) -{ - __shrQAFinish(argc, argv, iStatus); - - exit(iStatus ? EXIT_SUCCESS : EXIT_FAILURE); -} - -inline void shrQAFinishExit2(bool bQAtest, int argc, const char **argv, int iStatus) -{ - __shrQAFinish2(bQAtest, argc, argv, iStatus); - - exit(iStatus ? EXIT_SUCCESS : EXIT_FAILURE); -} - -#endif \ No newline at end of file diff --git a/tests/opencl/vectorhypot/shrUtils.cpp b/tests/opencl/vectorhypot/shrUtils.cpp deleted file mode 100644 index cf0d2c3e..00000000 --- a/tests/opencl/vectorhypot/shrUtils.cpp +++ /dev/null @@ -1,1954 +0,0 @@ -/* - * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. - * - * Please refer to the NVIDIA end user license agreement (EULA) associated - * with this source code for terms and conditions that govern your use of - * this software. Any use, reproduction, disclosure, or distribution of - * this software and related documentation outside the terms of the EULA - * is strictly prohibited. - * - */ - -// ********************************************************************* -// Generic Utilities for NVIDIA GPU Computing SDK -// ********************************************************************* - -// includes -#include -#include -#include -#include -#include "shrUtils.h" -#include "cmd_arg_reader.h" - -// size of PGM file header -const unsigned int PGMHeaderSize = 0x40; -#define MIN_EPSILON_ERROR 1e-3f - -// Deallocate memory allocated within shrUtils -// ********************************************************************* -void shrFree(void* ptr) -{ - if( NULL != ptr) free( ptr); -} - -// Helper function to init data arrays -// ********************************************************************* -void shrFillArray(float* pfData, int iSize) -{ - int i; - const float fScale = 1.0f / (float)RAND_MAX; - for (i = 0; i < iSize; ++i) - { - pfData[i] = fScale * rand(); - } -} - -// Helper function to print data arrays -// ********************************************************************* -void shrPrintArray(float* pfData, int iSize) -{ - int i; - for (i = 0; i < iSize; ++i) - { - shrLog("%d: %.3f\n", i, pfData[i]); - } -} - -// Helper function to return precision delta time for 3 counters since last call based upon host high performance counter -// ********************************************************************* -double shrDeltaT(int iCounterID = 0) -{ - // local var for computation of microseconds since last call - double DeltaT; - - #ifdef _WIN32 // Windows version of precision host timer - - // Variables that need to retain state between calls - static LARGE_INTEGER liOldCount0 = {0, 0}; - static LARGE_INTEGER liOldCount1 = {0, 0}; - static LARGE_INTEGER liOldCount2 = {0, 0}; - - // locals for new count, new freq and new time delta - LARGE_INTEGER liNewCount, liFreq; - if (QueryPerformanceFrequency(&liFreq)) - { - // Get new counter reading - QueryPerformanceCounter(&liNewCount); - - // Update the requested timer - switch (iCounterID) - { - case 0: - { - // Calculate time difference for timer 0. (zero when called the first time) - DeltaT = liOldCount0.LowPart ? (((double)liNewCount.QuadPart - (double)liOldCount0.QuadPart) / (double)liFreq.QuadPart) : 0.0; - - // Reset old count to new - liOldCount0 = liNewCount; - - break; - } - case 1: - { - // Calculate time difference for timer 1. (zero when called the first time) - DeltaT = liOldCount1.LowPart ? (((double)liNewCount.QuadPart - (double)liOldCount1.QuadPart) / (double)liFreq.QuadPart) : 0.0; - - // Reset old count to new - liOldCount1 = liNewCount; - - break; - } - case 2: - { - // Calculate time difference for timer 2. (zero when called the first time) - DeltaT = liOldCount2.LowPart ? (((double)liNewCount.QuadPart - (double)liOldCount2.QuadPart) / (double)liFreq.QuadPart) : 0.0; - - // Reset old count to new - liOldCount2 = liNewCount; - - break; - } - default: - { - // Requested counter ID out of range - return -9999.0; - } - } - - // Returns time difference in seconds sunce the last call - return DeltaT; - } - else - { - // No high resolution performance counter - return -9999.0; - } - #else // Linux version of precision host timer. See http://www.informit.com/articles/article.aspx?p=23618&seqNum=8 - static struct timeval _NewTime; // new wall clock time (struct representation in seconds and microseconds) - static struct timeval _OldTime0; // old wall clock time 0(struct representation in seconds and microseconds) - static struct timeval _OldTime1; // old wall clock time 1(struct representation in seconds and microseconds) - static struct timeval _OldTime2; // old wall clock time 2(struct representation in seconds and microseconds) - - // Get new counter reading - gettimeofday(&_NewTime, NULL); - - switch (iCounterID) - { - case 0: - { - // Calculate time difference for timer 0. (zero when called the first time) - DeltaT = ((double)_NewTime.tv_sec + 1.0e-6 * (double)_NewTime.tv_usec) - ((double)_OldTime0.tv_sec + 1.0e-6 * (double)_OldTime0.tv_usec); - - // Reset old time 0 to new - _OldTime0.tv_sec = _NewTime.tv_sec; - _OldTime0.tv_usec = _NewTime.tv_usec; - - break; - } - case 1: - { - // Calculate time difference for timer 1. (zero when called the first time) - DeltaT = ((double)_NewTime.tv_sec + 1.0e-6 * (double)_NewTime.tv_usec) - ((double)_OldTime1.tv_sec + 1.0e-6 * (double)_OldTime1.tv_usec); - - // Reset old time 1 to new - _OldTime1.tv_sec = _NewTime.tv_sec; - _OldTime1.tv_usec = _NewTime.tv_usec; - - break; - } - case 2: - { - // Calculate time difference for timer 2. (zero when called the first time) - DeltaT = ((double)_NewTime.tv_sec + 1.0e-6 * (double)_NewTime.tv_usec) - ((double)_OldTime2.tv_sec + 1.0e-6 * (double)_OldTime2.tv_usec); - - // Reset old time 2 to new - _OldTime2.tv_sec = _NewTime.tv_sec; - _OldTime2.tv_usec = _NewTime.tv_usec; - - break; - } - default: - { - // Requested counter ID out of range - return -9999.0; - } - } - - // Returns time difference in seconds sunce the last call - return DeltaT; - #endif -} - -// Optional LogFileName Override function -// ********************************************************************* -char* cLogFilePathAndName = NULL; -void shrSetLogFileName (const char* cOverRideName) -{ - if( cLogFilePathAndName != NULL ) { - free(cLogFilePathAndName); - } - cLogFilePathAndName = (char*) malloc(strlen(cOverRideName) + 1); - #ifdef WIN32 - strcpy_s(cLogFilePathAndName, strlen(cOverRideName) + 1, cOverRideName); - #else - strcpy(cLogFilePathAndName, cOverRideName); - #endif - return; -} - -// Function to log standardized information to console, file or both -// ********************************************************************* -static int shrLogV(int iLogMode, int iErrNum, const char* cFormatString, va_list vaArgList) -{ - static FILE* pFileStream0 = NULL; - static FILE* pFileStream1 = NULL; - size_t szNumWritten = 0; - char cFileMode [3]; - - // if the sample log file is closed and the call incudes a "write-to-file", open file for writing - if ((pFileStream0 == NULL) && (iLogMode & LOGFILE)) - { - // if the default filename has not been overriden, set to default - if (cLogFilePathAndName == NULL) - { - shrSetLogFileName(DEFAULTLOGFILE); - } - - #ifdef _WIN32 // Windows version - // set the file mode - if (iLogMode & APPENDMODE) // append to prexisting file contents - { - sprintf_s (cFileMode, 3, "a+"); - } - else // replace prexisting file contents - { - sprintf_s (cFileMode, 3, "w"); - } - - // open the individual sample log file in the requested mode - errno_t err = fopen_s(&pFileStream0, cLogFilePathAndName, cFileMode); - - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (err != 0) - { - if (pFileStream0) - { - fclose (pFileStream0); - } - return -err; - } - #else // Linux & Mac version - // set the file mode - if (iLogMode & APPENDMODE) // append to prexisting file contents - { - sprintf (cFileMode, "a+"); - } - else // replace prexisting file contents - { - sprintf (cFileMode, "w"); - } - - // open the file in the requested mode - if ((pFileStream0 = fopen(cLogFilePathAndName, cFileMode)) == 0) - { - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (pFileStream0) - { - fclose (pFileStream0); - } - return -1; - } - #endif - } - - // if the master log file is closed and the call incudes a "write-to-file" and MASTER, open master logfile file for writing - if ((pFileStream1 == NULL) && (iLogMode & LOGFILE) && (iLogMode & MASTER)) - { - #ifdef _WIN32 // Windows version - // open the master log file in append mode - errno_t err = fopen_s(&pFileStream1, MASTERLOGFILE, "a+"); - - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (err != 0) - { - if (pFileStream1) - { - fclose (pFileStream1); - pFileStream1 = NULL; - } - iLogMode = LOGCONSOLE; // Force to LOGCONSOLE only since the file stream is invalid -// return -err; - } - #else // Linux & Mac version - - // open the file in the requested mode - if ((pFileStream1 = fopen(MASTERLOGFILE, "a+")) == 0) - { - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (pFileStream1) - { - fclose (pFileStream1); - pFileStream1 = NULL; - } - iLogMode = LOGCONSOLE; // Force to LOGCONSOLE only since the file stream is invalid -// return -1; - } - #endif - - // If master log file length has become excessive, empty/reopen - if (iLogMode != LOGCONSOLE) - { - fseek(pFileStream1, 0L, SEEK_END); - if (ftell(pFileStream1) > 50000L) - { - fclose (pFileStream1); - #ifdef _WIN32 // Windows version - fopen_s(&pFileStream1, MASTERLOGFILE, "w"); - #else - pFileStream1 = fopen(MASTERLOGFILE, "w"); - #endif - } - } - } - - // Handle special Error Message code - if (iLogMode & ERRORMSG) - { - // print string to console if flagged - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf ("\n !!! Error # %i at ", iErrNum); // console - } - // print string to file if flagged - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, "\n !!! Error # %i at ", iErrNum); // sample log file - } - } - - // Vars used for variable argument processing - const char* pStr; - const char* cArg; - int iArg; - double dArg; - unsigned int uiArg; - std::string sFormatSpec; - const std::string sFormatChars = " -+#0123456789.dioufnpcsXxEeGgAa"; - const std::string sTypeChars = "dioufnpcsXxEeGgAa"; - char cType = 'c'; - - // Start at the head of the string and scan to the null at the end - for (pStr = cFormatString; *pStr; ++pStr) - { - // Check if the current character is not a formatting specifier ('%') - if (*pStr != '%') - { - // character is not '%', so print it verbatim to console and/or files as flagged - if (iLogMode & LOGCONSOLE) - { - szNumWritten = putc(*pStr, stdout); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = putc(*pStr, pFileStream0); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = putc(*pStr, pFileStream1); // master log file - } - } - } - else - { - // character is '%', so skip over it and read the full format specifier for the argument - ++pStr; - sFormatSpec = '%'; - - // special handling for string of %%%% - bool bRepeater = (*pStr == '%'); - if (bRepeater) - { - cType = '%'; - } - - // chars after the '%' are part of format if on list of constants... scan until that isn't true or NULL is found - while (pStr && ((sFormatChars.find(*pStr) != std::string::npos) || bRepeater)) - { - sFormatSpec += *pStr; - - // If the char is a type specifier, trap it and stop scanning - // (a type specifier char is always the last in the format except for string of %%%) - if (sTypeChars.find(*pStr) != std::string::npos) - { - cType = *pStr; - break; - } - - // Special handling for string of %%% - // If a string of %%% was started and then it ends, break (There won't be a typical type specifier) - if (bRepeater && (*pStr != '%')) - { - break; - } - - pStr++; - } - - // Now handle the arg according to type - switch (cType) - { - case '%': // special handling for string of %%%% - { - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str()); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str()); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str()); // master log file - } - } - continue; - } - case 'c': // single byte char - case 's': // string of single byte chars - { - // Set cArg as the next value in list and print to console and/or files if flagged - cArg = va_arg(vaArgList, char*); - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str(), cArg); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), cArg); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), cArg); // master log file - } - } - continue; - } - case 'd': // signed decimal integer - case 'i': // signed decimal integer - { - // set iArg as the next value in list and print to console and/or files if flagged - iArg = va_arg(vaArgList, int); - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str(), iArg); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), iArg); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), iArg); // master log file - } - } - continue; - } - case 'u': // unsigned decimal integer - case 'o': // unsigned octal integer - case 'x': // unsigned hexadecimal integer using "abcdef" - case 'X': // unsigned hexadecimal integer using "ABCDEF" - { - // set uiArg as the next value in list and print to console and/or files if flagged - uiArg = va_arg(vaArgList, unsigned int); - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str(), uiArg); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), uiArg); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), uiArg); // master log file - } - } - continue; - } - case 'f': // float/double - case 'e': // scientific double/float - case 'E': // scientific double/float - case 'g': // scientific double/float - case 'G': // scientific double/float - case 'a': // signed hexadecimal double precision float - case 'A': // signed hexadecimal double precision float - { - // set dArg as the next value in list and print to console and/or files if flagged - dArg = va_arg(vaArgList, double); - if (iLogMode & LOGCONSOLE) - { - szNumWritten = printf(sFormatSpec.c_str(), dArg); // console - } - if (iLogMode & LOGFILE) - { - szNumWritten = fprintf (pFileStream0, sFormatSpec.c_str(), dArg); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = fprintf(pFileStream1, sFormatSpec.c_str(), dArg); // master log file - } - } - continue; - } - default: - { - // print arg of unknown/unsupported type to console and/or file if flagged - if (iLogMode & LOGCONSOLE) // console - { - szNumWritten = putc(*pStr, stdout); - } - if (iLogMode & LOGFILE) - { - szNumWritten = putc(*pStr, pFileStream0); // sample log file - if (iLogMode & MASTER) - { - szNumWritten = putc(*pStr, pFileStream1); // master log file - } - } - } - } - } - } - - // end the sample log with a horizontal line if closing - if (iLogMode & CLOSELOG) - { - if (iLogMode & LOGCONSOLE) - { - printf(HDASHLINE); - } - if (iLogMode & LOGFILE) - { - fprintf(pFileStream0, HDASHLINE); - } - } - - // flush console and/or file buffers if updated - if (iLogMode & LOGCONSOLE) - { - fflush(stdout); - } - if (iLogMode & LOGFILE) - { - fflush (pFileStream0); - - // if the master log file has been updated, flush it too - if (iLogMode & MASTER) - { - fflush (pFileStream1); - } - } - - // If the log file is open and the caller requests "close file", then close and NULL file handle - if ((pFileStream0) && (iLogMode & CLOSELOG)) - { - fclose (pFileStream0); - pFileStream0 = NULL; - } - if ((pFileStream1) && (iLogMode & CLOSELOG)) - { - fclose (pFileStream1); - pFileStream1 = NULL; - } - - // return error code or OK - if (iLogMode & ERRORMSG) - { - return iErrNum; - } - else - { - return 0; - } -} - -// Function to log standardized information to console, file or both -// ********************************************************************* -int shrLogEx(int iLogMode = LOGCONSOLE, int iErrNum = 0, const char* cFormatString = "", ...) -{ - va_list vaArgList; - - // Prepare variable agument list - va_start(vaArgList, cFormatString); - int ret = shrLogV(iLogMode, iErrNum, cFormatString, vaArgList); - - // end variable argument handler - va_end(vaArgList); - - return ret; -} - -// Function to log standardized information to console, file or both -// ********************************************************************* -int shrLog(const char* cFormatString = "", ...) -{ - va_list vaArgList; - - // Prepare variable agument list - va_start(vaArgList, cFormatString); - int ret = shrLogV(LOGBOTH, 0, cFormatString, vaArgList); - - // end variable argument handler - va_end(vaArgList); - - return ret; -} - -////////////////////////////////////////////////////////////////////////////// -//! Find the path for a file assuming that -//! files are found in the searchPath. -//! -//! @return the path if succeeded, otherwise 0 -//! @param filename name of the file -//! @param executable_path optional absolute path of the executable -////////////////////////////////////////////////////////////////////////////// -char* shrFindFilePath(const char* filename, const char* executable_path) -{ - // defines a variable that is replaced with the name of the executable - - // Typical relative search paths to locate needed companion files (e.g. sample input data, or JIT source files) - // The origin for the relative search may be the .exe file, a .bat file launching an .exe, a browser .exe launching the .exe or .bat, etc - const char* searchPath[] = - { - "./", // same dir - "./data/", // "/data/" subdir - "./src/", // "/src/" subdir - "./src//data/", // "/src//data/" subdir - "./inc/", // "/inc/" subdir - "../", // up 1 in tree - "../data/", // up 1 in tree, "/data/" subdir - "../src/", // up 1 in tree, "/src/" subdir - "../inc/", // up 1 in tree, "/inc/" subdir - "../OpenCL/src//", // up 1 in tree, "/OpenCL/src//" subdir - "../OpenCL/src//data/", // up 1 in tree, "/OpenCL/src//data/" subdir - "../OpenCL/src//src/", // up 1 in tree, "/OpenCL/src//src/" subdir - "../OpenCL/src//inc/", // up 1 in tree, "/OpenCL/src//inc/" subdir - "../C/src//", // up 1 in tree, "/C/src//" subdir - "../C/src//data/", // up 1 in tree, "/C/src//data/" subdir - "../C/src//src/", // up 1 in tree, "/C/src//src/" subdir - "../C/src//inc/", // up 1 in tree, "/C/src//inc/" subdir - "../DirectCompute/src//", // up 1 in tree, "/DirectCompute/src//" subdir - "../DirectCompute/src//data/", // up 1 in tree, "/DirectCompute/src//data/" subdir - "../DirectCompute/src//src/", // up 1 in tree, "/DirectCompute/src//src/" subdir - "../DirectCompute/src//inc/", // up 1 in tree, "/DirectCompute/src//inc/" subdir - "../../", // up 2 in tree - "../../data/", // up 2 in tree, "/data/" subdir - "../../src/", // up 2 in tree, "/src/" subdir - "../../inc/", // up 2 in tree, "/inc/" subdir - "../../../", // up 3 in tree - "../../../src//", // up 3 in tree, "/src//" subdir - "../../../src//data/", // up 3 in tree, "/src//data/" subdir - "../../../src//src/", // up 3 in tree, "/src//src/" subdir - "../../../src//inc/", // up 3 in tree, "/src//inc/" subdir - "../../../sandbox//", // up 3 in tree, "/sandbox//" subdir - "../../../sandbox//data/", // up 3 in tree, "/sandbox//data/" subdir - "../../../sandbox//src/", // up 3 in tree, "/sandbox//src/" subdir - "../../../sandbox//inc/" // up 3 in tree, "/sandbox//inc/" subdir - }; - - // Extract the executable name - std::string executable_name; - if (executable_path != 0) - { - executable_name = std::string(executable_path); - - #ifdef _WIN32 - // Windows path delimiter - size_t delimiter_pos = executable_name.find_last_of('\\'); - executable_name.erase(0, delimiter_pos + 1); - - if (executable_name.rfind(".exe") != string::npos) - { - // we strip .exe, only if the .exe is found - executable_name.resize(executable_name.size() - 4); - } - #else - // Linux & OSX path delimiter - size_t delimiter_pos = executable_name.find_last_of('/'); - executable_name.erase(0,delimiter_pos+1); - #endif - - } - - // Loop over all search paths and return the first hit - for( unsigned int i = 0; i < sizeof(searchPath)/sizeof(char*); ++i ) - { - std::string path(searchPath[i]); - size_t executable_name_pos = path.find(""); - - // If there is executable_name variable in the searchPath - // replace it with the value - if(executable_name_pos != std::string::npos) - { - if(executable_path != 0) - { - path.replace(executable_name_pos, strlen(""), executable_name); - - } - else - { - // Skip this path entry if no executable argument is given - continue; - } - } - - // Test if the file exists - path.append(filename); - std::fstream fh(path.c_str(), std::fstream::in); - if (fh.good()) - { - // File found - // returning an allocated array here for backwards compatibility reasons - char* file_path = (char*) malloc(path.length() + 1); - #ifdef _WIN32 - strcpy_s(file_path, path.length() + 1, path.c_str()); - #else - strcpy(file_path, path.c_str()); - #endif - return file_path; - } - } - - // File not found - return 0; -} - -////////////////////////////////////////////////////////////////////////////// -//! Read file \filename and return the data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -shrReadFile( const char* filename, T** data, unsigned int* len, bool verbose) -{ - // check input arguments - ARGCHECK(NULL != filename); - ARGCHECK(NULL != len); - - // intermediate storage for the data read - std::vector data_read; - - // open file for reading - std::fstream fh( filename, std::fstream::in); - // check if filestream is valid - if(!fh.good()) - { - if (verbose) - std::cerr << "shrReadFile() : Opening file failed." << std::endl; - return shrFALSE; - } - - // read all data elements - T token; - while( fh.good()) - { - fh >> token; - data_read.push_back( token); - } - - // the last element is read twice - data_read.pop_back(); - - // check if reading result is consistent - if( ! fh.eof()) - { - if (verbose) - std::cerr << "WARNING : readData() : reading file might have failed." - << std::endl; - } - - fh.close(); - - // check if the given handle is already initialized - if( NULL != *data) - { - if( *len != data_read.size()) - { - std::cerr << "shrReadFile() : Initialized memory given but " - << "size mismatch with signal read " - << "(data read / data init = " << (unsigned int)data_read.size() - << " / " << *len << ")" << std::endl; - - return shrFALSE; - } - } - else - { - // allocate storage for the data read - *data = (T*) malloc( sizeof(T) * data_read.size()); - // store signal size - *len = static_cast( data_read.size()); - } - - // copy data - memcpy( *data, &data_read.front(), sizeof(T) * data_read.size()); - - return shrTRUE; -} - -////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -shrWriteFile( const char* filename, const T* data, unsigned int len, - const T epsilon, bool verbose) -{ - ARGCHECK(NULL != filename); - ARGCHECK(NULL != data); - - // open file for writing - std::fstream fh( filename, std::fstream::out); - // check if filestream is valid - if(!fh.good()) - { - if (verbose) - std::cerr << "shrWriteFile() : Opening file failed." << std::endl; - return shrFALSE; - } - - // first write epsilon - fh << "# " << epsilon << "\n"; - - // write data - for( unsigned int i = 0; (i < len) && (fh.good()); ++i) - { - fh << data[i] << ' '; - } - - // Check if writing succeeded - if( ! fh.good()) - { - if (verbose) - std::cerr << "shrWriteFile() : Writing file failed." << std::endl; - return shrFALSE; - } - - // file ends with nl - fh << std::endl; - - return shrTRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg single precision floating point data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFilef( const char* filename, float** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg double precision floating point data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFiled( const char* filename, double** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg integer data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFilei( const char* filename, int** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg unsigned integer data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFileui( const char* filename, unsigned int** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg char / byte data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFileb( const char* filename, char** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Read file \filename containg unsigned char / byte data -//! @return shrTRUEif reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrReadFileub( const char* filename, unsigned char** data, unsigned int* len, bool verbose) -{ - return shrReadFile( filename, data, len, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for single precision floating point data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFilef( const char* filename, const float* data, unsigned int len, - const float epsilon, bool verbose) -{ - return shrWriteFile( filename, data, len, epsilon, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for double precision floating point data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFiled( const char* filename, const double* data, unsigned int len, - const double epsilon, bool verbose) -{ - return shrWriteFile( filename, data, len, epsilon, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for integer data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFilei( const char* filename, const int* data, unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, 0, verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for unsigned integer data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFileui( const char* filename,const unsigned int* data,unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, static_cast(0), verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for byte / char data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFileb( const char* filename, const char* data, unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, static_cast(0), verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for byte / char data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFileub( const char* filename, const unsigned char* data, - unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, static_cast(0), verbose); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename for unsigned byte / char data -//! @return shrTRUEif writing the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrWriteFileb( const char* filename,const unsigned char* data,unsigned int len, bool verbose) -{ - return shrWriteFile( filename, data, len, static_cast(0), verbose); -} - -////////////////////////////////////////////////////////////////////////////// -//! Load PGM or PPM file -//! @note if data == NULL then the necessary memory is allocated in the -//! function and w and h are initialized to the size of the image -//! @return shrTRUE if the file loading succeeded, otherwise shrFALSE -//! @param file name of the file to load -//! @param data handle to the memory for the image file data -//! @param w width of the image -//! @param h height of the image -//! @param channels number of channels in image -////////////////////////////////////////////////////////////////////////////// -shrBOOL loadPPM(const char* file, unsigned char** data, - unsigned int *w, unsigned int *h, unsigned int *channels) -{ - FILE* fp = 0; - - #ifdef _WIN32 - // open the file for binary read - errno_t err; - if ((err = fopen_s(&fp, file, "rb")) != 0) - #else - // open the file for binary read - if ((fp = fopen(file, "rb")) == 0) - #endif - { - // if error on attempt to open, be sure the file is null or close it, then return negative error code - if (fp) - { - fclose (fp); - } - std::cerr << "loadPPM() : Failed to open file: " << file << std::endl; - return shrFALSE; - } - - // check header - char header[PGMHeaderSize]; - if ((fgets( header, PGMHeaderSize, fp) == NULL) && ferror(fp)) - { - if (fp) - { - fclose (fp); - } - std::cerr << "loadPPM() : File is not a valid PPM or PGM image" << std::endl; - *channels = 0; - return shrFALSE; - } - - if (strncmp(header, "P5", 2) == 0) - { - *channels = 1; - } - else if (strncmp(header, "P6", 2) == 0) - { - *channels = 3; - } - else - { - std::cerr << "loadPPM() : File is not a PPM or PGM image" << std::endl; - *channels = 0; - return shrFALSE; - } - - // parse header, read maxval, width and height - unsigned int width = 0; - unsigned int height = 0; - unsigned int maxval = 0; - unsigned int i = 0; - while(i < 3) - { - if ((fgets(header, PGMHeaderSize, fp) == NULL) && ferror(fp)) - { - if (fp) - { - fclose (fp); - } - std::cerr << "loadPPM() : File is not a valid PPM or PGM image" << std::endl; - return shrFALSE; - } - if(header[0] == '#') continue; - - #ifdef _WIN32 - if(i == 0) - { - i += sscanf_s(header, "%u %u %u", &width, &height, &maxval); - } - else if (i == 1) - { - i += sscanf_s(header, "%u %u", &height, &maxval); - } - else if (i == 2) - { - i += sscanf_s(header, "%u", &maxval); - } - #else - if(i == 0) - { - i += sscanf(header, "%u %u %u", &width, &height, &maxval); - } - else if (i == 1) - { - i += sscanf(header, "%u %u", &height, &maxval); - } - else if (i == 2) - { - i += sscanf(header, "%u", &maxval); - } - #endif - } - - // check if given handle for the data is initialized - if(NULL != *data) - { - if (*w != width || *h != height) - { - fclose(fp); - std::cerr << "loadPPM() : Invalid image dimensions." << std::endl; - return shrFALSE; - } - } - else - { - *data = (unsigned char*)malloc( sizeof(unsigned char) * width * height * *channels); - *w = width; - *h = height; - } - - // read and close file - if (fread(*data, sizeof(unsigned char), width * height * *channels, fp) != width * height * *channels) - { - fclose(fp); - std::cerr << "loadPPM() : Invalid image." << std::endl; - return shrFALSE; - } - fclose(fp); - - return shrTRUE; -} - -////////////////////////////////////////////////////////////////////////////// -//! Write / Save PPM or PGM file -//! @note Internal usage only -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -////////////////////////////////////////////////////////////////////////////// -shrBOOL savePPM( const char* file, unsigned char *data, - unsigned int w, unsigned int h, unsigned int channels) -{ - ARGCHECK(NULL != data); - ARGCHECK(w > 0); - ARGCHECK(h > 0); - - std::fstream fh( file, std::fstream::out | std::fstream::binary ); - if( fh.bad()) - { - std::cerr << "savePPM() : Opening file failed." << std::endl; - return shrFALSE; - } - - if (channels == 1) - { - fh << "P5\n"; - } - else if (channels == 3) { - fh << "P6\n"; - } - else { - std::cerr << "savePPM() : Invalid number of channels." << std::endl; - return shrFALSE; - } - - fh << w << "\n" << h << "\n" << 0xff << std::endl; - - for( unsigned int i = 0; (i < (w*h*channels)) && fh.good(); ++i) - { - fh << data[i]; - } - fh.flush(); - - if( fh.bad()) - { - std::cerr << "savePPM() : Writing data failed." << std::endl; - return shrFALSE; - } - fh.close(); - - return shrTRUE; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Load PPM image file (with unsigned char as data element type), padding 4th component -//! @return shrTrue if reading the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrLoadPPM4ub( const char* file, unsigned char** OutData, - unsigned int *w, unsigned int *h) -{ - // Load file data into a temporary buffer with automatic allocation - unsigned char* cLocalData = 0; - unsigned int channels; - shrBOOL bLoadOK = loadPPM(file, &cLocalData, w, h, &channels); // this allocates cLocalData, which must be freed later - - // If the data loaded OK from file to temporary buffer, then go ahead with padding and transfer - if (shrTRUE == bLoadOK) - { - // if the receiving buffer is null, allocate it... caller must free this - int size = *w * *h; - if (*OutData == NULL) - { - *OutData = (unsigned char*)malloc(sizeof(unsigned char) * size * 4); - } - - // temp pointers for incrementing - unsigned char* cTemp = cLocalData; - unsigned char* cOutPtr = *OutData; - - // transfer data, padding 4th element - for(int i=0; i( arg_name); - if( NULL != v) - { - // assign value - *val = *v; - ret_val = shrTRUE; - } - else { - // fail safe - val = NULL; - } - } - catch( const std::exception& /*ex*/) - { - std::cerr << "Error when parsing command line argument string." << std::endl; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type unsigned int -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrGetCmdLineArgumentu( const int argc, const char** argv, - const char* arg_name, unsigned int* val) -{ - shrBOOL ret_val = shrFALSE; - - try - { - // initialize - CmdArgReader::init( argc, argv); - - // access argument - const int* v = CmdArgReader::getArg( arg_name); - if( NULL != v) - { - // assign value - *val = *v; - ret_val = shrTRUE; - } - else { - // fail safe - val = NULL; - } - } - catch( const std::exception& /*ex*/) - { - std::cerr << "Error when parsing command line argument string." << std::endl; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type float -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrGetCmdLineArgumentf( const int argc, const char** argv, - const char* arg_name, float* val) -{ - shrBOOL ret_val = shrFALSE; - - try - { - // initialize - CmdArgReader::init( argc, argv); - - // access argument - const float* v = CmdArgReader::getArg( arg_name); - if( NULL != v) - { - // assign value - *val = *v; - ret_val = shrTRUE; - } - else { - // fail safe - val = NULL; - } - } - catch( const std::exception& /*ex*/) - { - std::cerr << "Error when parsing command line argument string." << std::endl; - } - - return ret_val; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type string -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrGetCmdLineArgumentstr( const int argc, const char** argv, - const char* arg_name, char** val) -{ - shrBOOL ret_val = shrFALSE; - - try - { - // initialize - CmdArgReader::init( argc, argv); - - // access argument - const std::string* v = CmdArgReader::getArg( arg_name); - if( NULL != v) - { - - // allocate memory for the string - *val = (char*)malloc(sizeof(char) * (v->length() + 1)); - - // copy from string to c_str - #ifdef WIN32 - strcpy_s(*val, v->length() + 1, v->c_str()); - #else - strcpy(*val, v->c_str()); - #endif - ret_val = shrTRUE; - } - else { - // fail safe - *val = NULL; - } - } - catch( const std::exception& /*ex*/) - { - std::cerr << "Error when parsing command line argument string."<< - std::endl; - } - - return ret_val; - -} - -////////////////////////////////////////////////////////////////////////////// -//! Compare two arrays of arbitrary type -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -compareData( const T* reference, const T* data, const unsigned int len, - const S epsilon, const float threshold) -{ - ARGCHECK( epsilon >= 0); - - bool result = true; - unsigned int error_count = 0; - - for( unsigned int i = 0; i < len; ++i) { - - T diff = reference[i] - data[i]; - bool comp = (diff <= epsilon) && (diff >= -epsilon); - result &= comp; - - error_count += !comp; - -#ifdef _DEBUG - if( ! comp) - { - std::cerr << "ERROR, i = " << i << ",\t " - << reference[i] << " / " - << data[i] - << " (reference / data)\n"; - } -#endif - } - - if (threshold == 0.0f) { - return (result) ? shrTRUE : shrFALSE; - } else { - return (len*threshold > error_count) ? shrTRUE : shrFALSE; - } -} - -////////////////////////////////////////////////////////////////////////////// -//! Compare two arrays of arbitrary type -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -compareDataAsFloat( const T* reference, const T* data, const unsigned int len, - const S epsilon) -{ - ARGCHECK(epsilon >= 0); - - // If we set epsilon to be 0, let's set a minimum threshold - float max_error = MAX( (float)epsilon, MIN_EPSILON_ERROR ); - int error_count = 0; - bool result = true; - - for( unsigned int i = 0; i < len; ++i) { - float diff = fabs((float)reference[i] - (float)data[i]); - bool comp = (diff < max_error); - result &= comp; - - if( ! comp) - { - error_count++; -#ifdef _DEBUG - if (error_count < 50) { - shrLog("\n ERROR(epsilon=%4.3f), i=%d, (ref)0x%02x / (data)0x%02x / (diff)%d\n", max_error, i, reference[i], data[i], (unsigned int)diff); - } -#endif - } - } - if (error_count) { - shrLog("\n Total # of errors = %d\n", error_count); - } - return (error_count == 0) ? shrTRUE : shrFALSE; -} - -////////////////////////////////////////////////////////////////////////////// -//! Compare two arrays of arbitrary type -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//! @param epsilon threshold % of (# of bytes) for pass/fail -////////////////////////////////////////////////////////////////////////////// -template -shrBOOL -compareDataAsFloatThreshold( const T* reference, const T* data, const unsigned int len, - const S epsilon, const float threshold) -{ - ARGCHECK(epsilon >= 0); - - // If we set epsilon to be 0, let's set a minimum threshold - float max_error = MAX( (float)epsilon, MIN_EPSILON_ERROR); - int error_count = 0; - bool result = true; - - for( unsigned int i = 0; i < len; ++i) { - float diff = fabs((float)reference[i] - (float)data[i]); - bool comp = (diff < max_error); - result &= comp; - - if( ! comp) - { - error_count++; -//#ifdef _DEBUG - if (error_count < 50) { - shrLog("\n ERROR(epsilon=%4.3f), i=%d, (ref)%f / (data)%f / (diff)%f\n", max_error, i, reference[i], data[i], diff); - } -//#endif - } - } - - if (threshold == 0.0f) { - if (error_count) { - shrLog("\n Total # of errors = %d\n", error_count); - } - return (error_count == 0) ? shrTRUE : shrFALSE; - } else { - - if (error_count) { - shrLog("\n %.2f(%%) of bytes mismatched (count=%d)\n", (float)error_count*100/(float)len, error_count); - } - - return ((len*threshold > error_count) ? shrTRUE : shrFALSE); - } -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparef( const float* reference, const float* data, - const unsigned int len ) -{ - const float epsilon = 0.0; - return compareData( reference, data, len, epsilon, 0.0f ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparei( const int* reference, const int* data, - const unsigned int len ) -{ - const int epsilon = 0; - return compareData( reference, data, len, epsilon, 0.0f); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two unsigned integer arrays, with epsilon and threshold -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareuit( const unsigned int* reference, const unsigned int* data, - const unsigned int len, const float epsilon, const float threshold ) -{ - return compareDataAsFloatThreshold( reference, data, len, epsilon, threshold ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareub( const unsigned char* reference, const unsigned char* data, - const unsigned int len ) -{ - const int epsilon = 0; - return compareData( reference, data, len, epsilon, 0.0f); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays (inc Threshold for # of pixel we can have errors) -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareubt( const unsigned char* reference, const unsigned char* data, - const unsigned int len, const float epsilon, const float threshold ) -{ - return compareDataAsFloatThreshold( reference, data, len, epsilon, threshold ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays -//! @return shrTRUE if \a reference and \a data are identical, -//! otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareube( const unsigned char* reference, const unsigned char* data, - const unsigned int len, const float epsilon ) -{ - return compareDataAsFloat( reference, data, len, epsilon ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays with an epsilon tolerance for equality -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparefe( const float* reference, const float* data, - const unsigned int len, const float epsilon ) -{ - return compareData( reference, data, len, epsilon, 0.0f); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays with an epsilon tolerance for equality and a -//! threshold for # pixel errors -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparefet( const float* reference, const float* data, - const unsigned int len, const float epsilon, const float threshold ) -{ - return compareDataAsFloatThreshold( reference, data, len, epsilon, threshold ); -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays using L2-norm with an epsilon tolerance for equality -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrCompareL2fe( const float* reference, const float* data, - const unsigned int len, const float epsilon ) -{ - ARGCHECK(epsilon >= 0); - - float error = 0; - float ref = 0; - - for( unsigned int i = 0; i < len; ++i) { - - float diff = reference[i] - data[i]; - error += diff * diff; - ref += reference[i] * reference[i]; - } - - float normRef = sqrtf(ref); - if (fabs(ref) < 1e-7) { -#ifdef _DEBUG - std::cerr << "ERROR, reference l2-norm is 0\n"; -#endif - return shrFALSE; - } - float normError = sqrtf(error); - error = normError / normRef; - bool result = error < epsilon; -#ifdef _DEBUG - if( ! result) - { - std::cerr << "ERROR, l2-norm error " - << error << " is greater than epsilon " << epsilon << "\n"; - } -#endif - - return result ? shrTRUE : shrFALSE; -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two PPM image files with an epsilon tolerance for equality -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param src_file filename for the image to be compared -//! @param data filename for the reference data / gold image -//! @param epsilon epsilon to use for the comparison -//! @param threshold threshold of pixels that can still mismatch to pass (i.e. 0.15f = 15% must pass) -//! @param verboseErrors output details of image mismatch to std::cerr -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparePPM( const char *src_file, const char *ref_file, const float epsilon, const float threshold) -{ - unsigned char* src_data = NULL; - unsigned char* ref_data = NULL; - unsigned long error_count = 0; - unsigned int ref_width, ref_height; - unsigned int src_width, src_height; - - // Check sample and reference file pointers - if (src_file == NULL || ref_file == NULL) { - shrLog("\n> shrComparePGM: src_file or ref_file is NULL\n Aborting comparison !!!\n\n"); - return shrFALSE; - } - shrLog("\n> shrComparePPM:\n (a)rendered: <%s>\n (b)reference: <%s>\n", src_file, ref_file); - - // Load the ref image file - if (shrLoadPPM4ub(ref_file, &ref_data, &ref_width, &ref_height) != shrTRUE) - { - shrLog("\n Unable to load ref image file: %s\n Aborting comparison !!!\n\n", ref_file); - return shrFALSE; - } - - // Load the sample image file - if (shrLoadPPM4ub(src_file, &src_data, &src_width, &src_height) != shrTRUE) - { - shrLog("\n Unable to load src image file: %s\n Aborting comparison !!!\n\n", src_file); - return shrFALSE; - } - - // check to see if image dimensions match - if(src_height != ref_height || src_width != ref_width) - { - shrLog("\n Source and ref size mismatch (%u x %u) vs (%u x %u)\n Aborting Comparison !!!\n\n ", - src_width, src_height, ref_width, ref_height); - return shrFALSE; - } - - // compare the images - if (shrCompareubt(ref_data, src_data, src_width*src_height*4, epsilon, threshold ) == shrFALSE) - { - error_count=1; - } - - shrLog(" Images %s\n\n", (error_count == 0) ? "Match" : "Don't Match !!!"); - return (error_count == 0) ? shrTRUE : shrFALSE; // returns true if all pixels pass -} - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two PGM image files with an epsilon tolerance for equality -//! @return shrTRUE if \a reference and \a data are identical, otherwise shrFALSE -//! @param src_file filename for the image to be compared -//! @param data filename for the reference data / gold image -//! @param epsilon epsilon to use for the comparison -//! @param threshold threshold of pixels that can still mismatch to pass (i.e. 0.15f = 15% must pass) -//////////////////////////////////////////////////////////////////////////////// -shrBOOL shrComparePGM( const char *src_file, const char *ref_file, const float epsilon, const float threshold) -{ - unsigned char* src_data = NULL; - unsigned char* ref_data = NULL; - unsigned long error_count = 0; - unsigned int ref_width, ref_height; - unsigned int src_width, src_height; - - // Check sample and reference file pointers - if (src_file == NULL || ref_file == NULL) { - shrLog("\n> shrComparePGM: src_file or ref_file is NULL\n Aborting comparison !!!\n\n"); - return shrFALSE; - } - shrLog("\n> shrComparePGM:\n (a)rendered: <%s>\n (b)reference: <%s>\n", src_file, ref_file); - - // Load the ref image file - if (shrLoadPPM4ub(ref_file, &ref_data, &ref_width, &ref_height) != shrTRUE) - { - shrLog("\n Unable to load ref image file: %s\n Aborting comparison !!!\n\n", ref_file); - return shrFALSE; - } - - // Load the sample image file - if (shrLoadPPM4ub(src_file, &src_data, &src_width, &src_height) != shrTRUE) - { - shrLog("\n Unable to load src image file: %s\n Aborting comparison !!!\n\n", src_file); - return shrFALSE; - } - - // check to see if image dimensions match - if(src_height != ref_height || src_width != ref_width) - { - shrLog("\n Source and ref size mismatch (%u x %u) vs (%u x %u)\n Aborting Comparison !!!\n\n ", - src_width, src_height, ref_width, ref_height); - return shrFALSE; - } - - // compare the images - if (shrCompareubt(ref_data, src_data, src_width*src_height*4, epsilon, threshold ) == shrFALSE) - { - error_count=1; - } - - shrLog(" Images %s\n\n", (error_count == 0) ? "Match" : "Don't Match !!!"); - return (error_count == 0) ? shrTRUE : shrFALSE; // returns true if all pixels pass -} - -// Load raw data from disk -unsigned char* shrLoadRawFile(const char* filename, size_t size) -{ - FILE *fp = NULL; - #ifdef WIN32 - errno_t err; - if ((err = fopen_s(&fp, filename, "rb")) != 0) - #else - if ((fp = fopen(filename, "rb")) == NULL) - #endif - { - shrLog(" Error opening file '%s' !!!\n", filename); - return 0; - } - - unsigned char* data = (unsigned char*)malloc(size); - size_t read = fread(data, 1, size, fp); - fclose(fp); - - shrLog(" Read '%s', %d bytes\n", filename, read); - - return data; -} - -// Round Up Division function -size_t shrRoundUp(int group_size, int global_size) -{ - int r = global_size % group_size; - if(r == 0) - { - return global_size; - } else - { - return global_size + group_size - r; - } -} \ No newline at end of file diff --git a/tests/opencl/vectorhypot/shrUtils.h b/tests/opencl/vectorhypot/shrUtils.h deleted file mode 100644 index 0f2795d4..00000000 --- a/tests/opencl/vectorhypot/shrUtils.h +++ /dev/null @@ -1,642 +0,0 @@ -/* -* Copyright 1993-2010 NVIDIA Corporation. All rights reserved. -* -* Please refer to the NVIDIA end user license agreement (EULA) associated -* with this source code for terms and conditions that govern your use of -* this software. Any use, reproduction, disclosure, or distribution of -* this software and related documentation outside the terms of the EULA -* is strictly prohibited. -* -*/ - -#ifndef SHR_UTILS_H -#define SHR_UTILS_H - -// ********************************************************************* -// Generic utilities for NVIDIA GPU Computing SDK -// ********************************************************************* - -// reminders for output window and build log -#ifdef _WIN32 - #pragma message ("Note: including windows.h") - #pragma message ("Note: including math.h") - #pragma message ("Note: including assert.h") -#endif - -// OS dependent includes -#ifdef _WIN32 - // Headers needed for Windows - #include -#else - // Headers needed for Linux - #include - #include - #include - #include - #include - #include - #include -#endif - -// Other headers needed for both Windows and Linux -#include -#include -#include -#include -#include - -// Un-comment the following #define to enable profiling code in SDK apps -//#define GPU_PROFILING - -// Beginning of GPU Architecture definitions -inline int ConvertSMVer2Cores(int major, int minor) -{ - // Defines for GPU Architecture types (using the SM version to determine the # of cores per SM - typedef struct { - int SM; // 0xMm (hexidecimal notation), M = SM Major version, and m = SM minor version - int Cores; - } sSMtoCores; - - sSMtoCores nGpuArchCoresPerSM[] = - { { 0x10, 8 }, // Tesla Generation (SM 1.0) G80 class - { 0x11, 8 }, // Tesla Generation (SM 1.1) G8x class - { 0x12, 8 }, // Tesla Generation (SM 1.2) G9x class - { 0x13, 8 }, // Tesla Generation (SM 1.3) GT200 class - { 0x20, 32 }, // Fermi Generation (SM 2.0) GF100 class - { 0x21, 48 }, // Fermi Generation (SM 2.1) GF10x class - { 0x30, 192}, // Fermi Generation (SM 3.0) GK10x class - { -1, -1 } - }; - - int index = 0; - while (nGpuArchCoresPerSM[index].SM != -1) { - if (nGpuArchCoresPerSM[index].SM == ((major << 4) + minor) ) { - return nGpuArchCoresPerSM[index].Cores; - } - index++; - } - printf("MapSMtoCores SM %d.%d is undefined (please update to the latest SDK)!\n", major, minor); - return -1; -} -// end of GPU Architecture definitions - - -// Defines and enum for use with logging functions -// ********************************************************************* -#define DEFAULTLOGFILE "SdkConsoleLog.txt" -#define MASTERLOGFILE "SdkMasterLog.csv" -enum LOGMODES -{ - LOGCONSOLE = 1, // bit to signal "log to console" - LOGFILE = 2, // bit to signal "log to file" - LOGBOTH = 3, // convenience union of first 2 bits to signal "log to both" - APPENDMODE = 4, // bit to set "file append" mode instead of "replace mode" on open - MASTER = 8, // bit to signal master .csv log output - ERRORMSG = 16, // bit to signal "pre-pend Error" - CLOSELOG = 32 // bit to close log file, if open, after any requested file write -}; -#define HDASHLINE "-----------------------------------------------------------\n" - -// Standardized boolean -enum shrBOOL -{ - shrFALSE = 0, - shrTRUE = 1 -}; - -// Standardized MAX, MIN and CLAMP -#define MAX(a, b) ((a > b) ? a : b) -#define MIN(a, b) ((a < b) ? a : b) -#define CLAMP(a, b, c) MIN(MAX(a, b), c) // double sided clip of input a -#define TOPCLAMP(a, b) (a < b ? a:b) // single top side clip of input a - -// Error and Exit Handling Macros... -// ********************************************************************* -// Full error handling macro with Cleanup() callback (if supplied)... -// (Companion Inline Function lower on page) -#define shrCheckErrorEX(a, b, c) __shrCheckErrorEX(a, b, c, __FILE__ , __LINE__) - -// Short version without Cleanup() callback pointer -// Both Input (a) and Reference (b) are specified as args -#define shrCheckError(a, b) shrCheckErrorEX(a, b, 0) - -// Standardized Exit Macro for leaving main()... extended version -// (Companion Inline Function lower on page) -#define shrExitEX(a, b, c) __shrExitEX(a, b, c) - -// Standardized Exit Macro for leaving main()... short version -// (Companion Inline Function lower on page) -#define shrEXIT(a, b) __shrExitEX(a, b, EXIT_SUCCESS) - -// Simple argument checker macro -#define ARGCHECK(a) if((a) != shrTRUE)return shrFALSE - -// Define for user-customized error handling -#define STDERROR "file %s, line %i\n\n" , __FILE__ , __LINE__ - -// Function to deallocate memory allocated within shrUtils -// ********************************************************************* -extern "C" void shrFree(void* ptr); - -// ********************************************************************* -// Helper function to log standardized information to Console, to File or to both -//! Examples: shrLogEx(LOGBOTH, 0, "Function A\n"); -//! : shrLogEx(LOGBOTH | ERRORMSG, ciErrNum, STDERROR); -//! -//! Automatically opens file and stores handle if needed and not done yet -//! Closes file and nulls handle on request -//! -//! @param 0 iLogMode: LOGCONSOLE, LOGFILE, LOGBOTH, APPENDMODE, MASTER, ERRORMSG, CLOSELOG. -//! LOGFILE and LOGBOTH may be | 'd with APPENDMODE to select file append mode instead of overwrite mode -//! LOGFILE and LOGBOTH may be | 'd with CLOSELOG to "write and close" -//! First 3 options may be | 'd with MASTER to enable independent write to master data log file -//! First 3 options may be | 'd with ERRORMSG to start line with standard error message -//! @param 2 dValue: -//! Positive val = double value for time in secs to be formatted to 6 decimals. -//! Negative val is an error code and this give error preformatting. -//! @param 3 cFormatString: String with formatting specifiers like printf or fprintf. -//! ALL printf flags, width, precision and type specifiers are supported with this exception: -//! Wide char type specifiers intended for wprintf (%S and %C) are NOT supported -//! Single byte char type specifiers (%s and %c) ARE supported -//! @param 4... variable args: like printf or fprintf. Must match format specifer type above. -//! @return 0 if OK, negative value on error or if error occurs or was passed in. -// ********************************************************************* -extern "C" int shrLogEx(int iLogMode, int iErrNum, const char* cFormatString, ...); - -// Short version of shrLogEx defaulting to shrLogEx(LOGBOTH, 0, -// ********************************************************************* -extern "C" int shrLog(const char* cFormatString, ...); - -// ********************************************************************* -// Delta timer function for up to 3 independent timers using host high performance counters -// Maintains state for 3 independent counters -//! Example: double dElapsedTime = shrDeltaTime(0); -//! -//! @param 0 iCounterID: Which timer to check/reset. (0, 1, 2) -//! @return delta time of specified counter since last call in seconds. Otherwise -9999.0 if error -// ********************************************************************* -extern "C" double shrDeltaT(int iCounterID); - -// Optional LogFileNameOverride function -// ********************************************************************* -extern "C" void shrSetLogFileName (const char* cOverRideName); - -// Helper function to init data arrays -// ********************************************************************* -extern "C" void shrFillArray(float* pfData, int iSize); - -// Helper function to print data arrays -// ********************************************************************* -extern "C" void shrPrintArray(float* pfData, int iSize); - -//////////////////////////////////////////////////////////////////////////// -//! Find the path for a filename -//! @return the path if succeeded, otherwise 0 -//! @param filename name of the file -//! @param executablePath optional absolute path of the executable -//////////////////////////////////////////////////////////////////////////// -extern "C" char* shrFindFilePath(const char* filename, const char* executablePath); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing single precision floating point data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFilef( const char* filename, float** data, unsigned int* len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing double precision floating point data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFiled( const char* filename, double** data, unsigned int* len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing integer data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFilei( const char* filename, int** data, unsigned int* len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing unsigned integer data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFileui( const char* filename, unsigned int** data, - unsigned int* len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing char / byte data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFileb( const char* filename, char** data, unsigned int* len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Read file \filename containing unsigned char / byte data -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param filename name of the source file -//! @param data uninitialized pointer, returned initialized and pointing to -//! the data read -//! @param len number of data elements in data, -1 on error -//! @note If a NULL pointer is passed to this function and it is -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrReadFileub( const char* filename, unsigned char** data, - unsigned int* len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing single precision floating point -//! data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFilef( const char* filename, const float* data, unsigned int len, - const float epsilon, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing double precision floating point -//! data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//! @param epsilon epsilon for comparison -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFiled( const char* filename, const float* data, unsigned int len, - const double epsilon, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing integer data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFilei( const char* filename, const int* data, unsigned int len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing unsigned integer data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFileui( const char* filename, const unsigned int* data, - unsigned int len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing char / byte data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFileb( const char* filename, const char* data, unsigned int len, - bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Write a data file \filename containing unsigned char / byte data -//! @return shrTRUE if writing the file succeeded, otherwise shrFALSE -//! @param filename name of the file to write -//! @param data pointer to data to write -//! @param len number of data elements in data, -1 on error -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrWriteFileub( const char* filename, const unsigned char* data, - unsigned int len, bool verbose = false); - -//////////////////////////////////////////////////////////////////////////// -//! Load PPM image file (with unsigned char as data element type), padding -//! 4th component -//! @return shrTRUE if reading the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param OutData handle to the data read -//! @param w width of the image -//! @param h height of the image -//! -//! Note: If *OutData is NULL this function allocates buffer that must be freed by caller -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrLoadPPM4ub(const char* file, unsigned char** OutData, - unsigned int *w, unsigned int *h); - -//////////////////////////////////////////////////////////////////////////// -//! Save PPM image file (with unsigned char as data element type, padded to -//! 4 bytes) -//! @return shrTRUE if saving the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrSavePPM4ub( const char* file, unsigned char *data, - unsigned int w, unsigned int h); - -//////////////////////////////////////////////////////////////////////////////// -//! Save PGM image file (with unsigned char as data element type) -//! @return shrTRUE if saving the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrSavePGMub( const char* file, unsigned char *data, - unsigned int w, unsigned int h); - -//////////////////////////////////////////////////////////////////////////// -//! Load PGM image file (with unsigned char as data element type) -//! @return shrTRUE if saving the file succeeded, otherwise shrFALSE -//! @param file name of the image file -//! @param data handle to the data read -//! @param w width of the image -//! @param h height of the image -//! @note If a NULL pointer is passed to this function and it is initialized -//! within shrUtils, then free() has to be used to deallocate the memory -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrLoadPGMub( const char* file, unsigned char** data, - unsigned int *w,unsigned int *h); - -//////////////////////////////////////////////////////////////////////////// -// Command line arguments: General notes -// * All command line arguments begin with '--' followed by the token; -// token and value are seperated by '='; example --samples=50 -// * Arrays have the form --model=[one.obj,two.obj,three.obj] -// (without whitespaces) -//////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////// -//! Check if command line argument \a flag-name is given -//! @return shrTRUE if command line argument \a flag_name has been given, -//! otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param flag_name name of command line flag -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCheckCmdLineFlag( const int argc, const char** argv, - const char* flag_name); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type int -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumenti( const int argc, const char** argv, - const char* arg_name, int* val); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type unsigned int -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumentu( const int argc, const char** argv, - const char* arg_name, unsigned int* val); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type float -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumentf( const int argc, const char** argv, - const char* arg_name, float* val); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument of type string -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val value of the command line argument -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumentstr( const int argc, const char** argv, - const char* arg_name, char** val); - -//////////////////////////////////////////////////////////////////////////// -//! Get the value of a command line argument list those element are strings -//! @return shrTRUE if command line argument \a arg_name has been given and -//! is of the requested type, otherwise shrFALSE -//! @param argc argc as passed to main() -//! @param argv argv as passed to main() -//! @param arg_name name of the command line argument -//! @param val command line argument list -//! @param len length of the list / number of elements -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrGetCmdLineArgumentListstr( const int argc, const char** argv, - const char* arg_name, char** val, - unsigned int* len); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparef( const float* reference, const float* data, - const unsigned int len); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparei( const int* reference, const int* data, - const unsigned int len ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two unsigned integer arrays, with epsilon and threshold -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param threshold tolerance % # of comparison errors (0.15f = 15%) -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareuit( const unsigned int* reference, const unsigned int* data, - const unsigned int len, const float epsilon, const float threshold ); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two unsigned char arrays -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareub( const unsigned char* reference, const unsigned char* data, - const unsigned int len ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integers with a tolernance for # of byte errors -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//! @param threshold tolerance % # of comparison errors (0.15f = 15%) -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareubt( const unsigned char* reference, const unsigned char* data, - const unsigned int len, const float epsilon, const float threshold ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two integer arrays witha n epsilon tolerance for equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareube( const unsigned char* reference, const unsigned char* data, - const unsigned int len, const float epsilon ); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays with an epsilon tolerance for equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparefe( const float* reference, const float* data, - const unsigned int len, const float epsilon ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays with an epsilon tolerance for equality and a -//! threshold for # pixel errors -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparefet( const float* reference, const float* data, - const unsigned int len, const float epsilon, const float threshold ); - -//////////////////////////////////////////////////////////////////////////// -//! Compare two float arrays using L2-norm with an epsilon tolerance for -//! equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param reference handle to the reference data / gold image -//! @param data handle to the computed data -//! @param len number of elements in reference and data -//! @param epsilon epsilon to use for the comparison -//////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrCompareL2fe( const float* reference, const float* data, - const unsigned int len, const float epsilon ); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two PPM image files with an epsilon tolerance for equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param src_file filename for the image to be compared -//! @param data filename for the reference data / gold image -//! @param epsilon epsilon to use for the comparison -//! @param threshold threshold of pixels that can still mismatch to pass (i.e. 0.15f = 15% must pass) -//! $param verboseErrors output details of image mismatch to std::err -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparePPM( const char *src_file, const char *ref_file, const float epsilon, const float threshold); - -//////////////////////////////////////////////////////////////////////////////// -//! Compare two PGM image files with an epsilon tolerance for equality -//! @return shrTRUEif \a reference and \a data are identical, otherwise shrFALSE -//! @param src_file filename for the image to be compared -//! @param data filename for the reference data / gold image -//! @param epsilon epsilon to use for the comparison -//! @param threshold threshold of pixels that can still mismatch to pass (i.e. 0.15f = 15% must pass) -//! $param verboseErrors output details of image mismatch to std::err -//////////////////////////////////////////////////////////////////////////////// -extern "C" shrBOOL shrComparePGM( const char *src_file, const char *ref_file, const float epsilon, const float threshold); - -extern "C" unsigned char* shrLoadRawFile(const char* filename, size_t size); - -extern "C" size_t shrRoundUp(int group_size, int global_size); - -// companion inline function for error checking and exit on error WITH Cleanup Callback (if supplied) -// ********************************************************************* -inline void __shrCheckErrorEX(int iSample, int iReference, void (*pCleanup)(int), const char* cFile, const int iLine) -{ - if (iReference != iSample) - { - shrLogEx(LOGBOTH | ERRORMSG, iSample, "line %i , in file %s !!!\n\n" , iLine, cFile); - if (pCleanup != NULL) - { - pCleanup(EXIT_FAILURE); - } - else - { - shrLogEx(LOGBOTH | CLOSELOG, 0, "Exiting...\n"); - exit(EXIT_FAILURE); - } - } -} - -// Standardized Exit -// ********************************************************************* -inline void __shrExitEX(int argc, const char** argv, int iExitCode) -{ -#ifdef WIN32 - if (!shrCheckCmdLineFlag(argc, argv, "noprompt") && !shrCheckCmdLineFlag(argc, argv, "qatest")) -#else - if (shrCheckCmdLineFlag(argc, argv, "prompt") && !shrCheckCmdLineFlag(argc, argv, "qatest")) -#endif - { - shrLogEx(LOGBOTH | CLOSELOG, 0, "\nPress to Quit...\n"); - getchar(); - } - else - { - shrLogEx(LOGBOTH | CLOSELOG, 0, "%s Exiting...\n", argv[0]); - } - fflush(stderr); - exit(iExitCode); -} - -#endif \ No newline at end of file From e7f8b40d9305ec2889d72686aa2d3902e1f496ab Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 31 Dec 2023 11:46:41 -0800 Subject: [PATCH 39/57] minor update --- runtime/opae/.gitignore | 1 + runtime/rtlsim/.gitignore | 3 +- sim/rtlsim/.gitignore | 1 - tests/opencl/fft/.depend | 7 - tests/opencl/fft/fft4 | Bin 19016 -> 0 bytes tests/opencl/fft/fft_radix4.dump | 5495 ------------------------------ tests/opencl/fft/kernel.pocl | Bin 74401 -> 0 bytes 7 files changed, 2 insertions(+), 5505 deletions(-) create mode 100644 runtime/opae/.gitignore delete mode 100644 tests/opencl/fft/.depend delete mode 100755 tests/opencl/fft/fft4 delete mode 100644 tests/opencl/fft/fft_radix4.dump delete mode 100644 tests/opencl/fft/kernel.pocl diff --git a/runtime/opae/.gitignore b/runtime/opae/.gitignore new file mode 100644 index 00000000..541b1f36 --- /dev/null +++ b/runtime/opae/.gitignore @@ -0,0 +1 @@ +/obj_dir/* \ No newline at end of file diff --git a/runtime/rtlsim/.gitignore b/runtime/rtlsim/.gitignore index dc7603c4..541b1f36 100644 --- a/runtime/rtlsim/.gitignore +++ b/runtime/rtlsim/.gitignore @@ -1,2 +1 @@ -obj_dir -*.so +/obj_dir/* \ No newline at end of file diff --git a/sim/rtlsim/.gitignore b/sim/rtlsim/.gitignore index d24f77ea..541b1f36 100644 --- a/sim/rtlsim/.gitignore +++ b/sim/rtlsim/.gitignore @@ -1,2 +1 @@ -VX_config.h /obj_dir/* \ No newline at end of file diff --git a/tests/opencl/fft/.depend b/tests/opencl/fft/.depend deleted file mode 100644 index e2cadcd3..00000000 --- a/tests/opencl/fft/.depend +++ /dev/null @@ -1,7 +0,0 @@ -main.o: main.cc /opt/pocl/runtime/include/CL/opencl.h \ - /opt/pocl/runtime/include/CL/cl.h \ - /opt/pocl/runtime/include/CL/cl_version.h \ - /opt/pocl/runtime/include/CL/cl_platform.h \ - /opt/pocl/runtime/include/CL/cl_gl.h \ - /opt/pocl/runtime/include/CL/cl_gl_ext.h \ - /opt/pocl/runtime/include/CL/cl_ext.h common.h diff --git a/tests/opencl/fft/fft4 b/tests/opencl/fft/fft4 deleted file mode 100755 index 044377ffa4e28495df685213058fff9f98666f4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19016 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 diff --git a/tests/opencl/fft/fft_radix4.dump b/tests/opencl/fft/fft_radix4.dump deleted file mode 100644 index b8fc3a32..00000000 --- a/tests/opencl/fft/fft_radix4.dump +++ /dev/null @@ -1,5495 +0,0 @@ - -/tmp/pocl_vortex_kernel_ZOVlwB.elf: file format elf32-littleriscv - -Disassembly of section .init: - -80000000 <_start>: -80000000: f3 22 10 fc csrr t0, nw -80000004: 17 13 00 00 auipc t1, 1 -80000008: 13 03 43 8d addi t1, t1, -1836 -8000000c: 0b 90 62 00 vx_wspawn t0, t1 -80000010: 93 02 f0 ff li t0, -1 -80000014: 0b 80 02 00 vx_tmc t0 -80000018: ef 00 d0 08 jal 0x800008a4 -8000001c: 93 02 10 00 li t0, 1 -80000020: 0b 80 02 00 vx_tmc t0 -80000024: ef 00 d0 0d jal 0x80000900 -80000028: f3 22 10 fc csrr t0, nw -8000002c: 17 13 00 00 auipc t1, 1 -80000030: 13 03 03 8c addi t1, t1, -1856 -80000034: 0b 90 62 00 vx_wspawn t0, t1 -80000038: 93 02 f0 ff li t0, -1 -8000003c: 0b 80 02 00 vx_tmc t0 -80000040: ef 00 10 0d jal 0x80000910 <__init_tls> -80000044: 93 02 10 00 li t0, 1 -80000048: 0b 80 02 00 vx_tmc t0 -8000004c: ef 00 50 0b jal 0x80000900 -80000050: 17 45 00 00 auipc a0, 4 -80000054: 13 05 c5 f7 addi a0, a0, -132 -80000058: 17 56 00 00 auipc a2, 5 -8000005c: 13 06 46 f7 addi a2, a2, -140 -80000060: 33 06 a6 40 sub a2, a2, a0 -80000064: 93 05 00 00 li a1, 0 -80000068: ef 20 c0 2e jal 0x80002354 -8000006c: 17 15 00 00 auipc a0, 1 -80000070: 13 05 c5 97 addi a0, a0, -1668 -80000074: ef 20 80 12 jal 0x8000219c -80000078: ef 00 d0 0d jal 0x80000954 <__libc_init_array> -8000007c: ef 00 40 05 jal 0x800000d0

-80000080: 6f 00 40 00 j 0x80000084 - -Disassembly of section .text: - -80000084 : -80000084: 13 01 01 ff addi sp, sp, -16 -80000088: 93 05 00 00 li a1, 0 -8000008c: 23 24 81 00 sw s0, 8(sp) -80000090: 23 26 11 00 sw ra, 12(sp) -80000094: 13 04 05 00 mv s0, a0 -80000098: ef 20 40 43 jal 0x800024cc <__call_exitprocs> -8000009c: 17 45 00 00 auipc a0, 4 -800000a0: 03 25 c5 f2 lw a0, -212(a0) -800000a4: 83 27 c5 03 lw a5, 60(a0) -800000a8: 63 84 07 00 beqz a5, 0x800000b0 -800000ac: e7 80 07 00 jalr a5 -800000b0: 13 05 04 00 mv a0, s0 -800000b4: ef 00 00 7e jal 0x80000894 <_exit> - -800000b8 : -800000b8: 93 07 00 00 li a5, 0 -800000bc: 63 88 07 00 beqz a5, 0x800000cc -800000c0: 17 15 00 00 auipc a0, 1 -800000c4: 13 05 85 92 addi a0, a0, -1752 -800000c8: 6f 20 40 0d j 0x8000219c -800000cc: 67 80 00 00 ret - -800000d0
: -800000d0: 13 01 01 ff addi sp, sp, -16 -800000d4: 23 26 11 00 sw ra, 12(sp) -800000d8: 37 05 00 80 lui a0, 524288 -800000dc: 93 05 45 14 addi a1, a0, 324 -800000e0: 37 05 ff 7f lui a0, 524272 -800000e4: 13 06 45 03 addi a2, a0, 52 -800000e8: ef 00 10 36 jal 0x80000c48 -800000ec: 13 05 00 00 li a0, 0 -800000f0: 83 20 c1 00 lw ra, 12(sp) -800000f4: 13 01 01 01 addi sp, sp, 16 -800000f8: 67 80 00 00 ret - -800000fc <_Z7_cl_cosf>: -800000fc: 13 01 01 ff addi sp, sp, -16 -80000100: 23 26 11 00 sw ra, 12(sp) -80000104: 23 24 81 00 sw s0, 8(sp) -80000108: 13 04 01 01 addi s0, sp, 16 -8000010c: 83 20 c1 00 lw ra, 12(sp) -80000110: 03 24 81 00 lw s0, 8(sp) -80000114: 13 01 01 01 addi sp, sp, 16 -80000118: 17 13 00 00 auipc t1, 1 -8000011c: 67 00 03 f4 jr -192(t1) - -80000120 <_Z7_cl_sinf>: -80000120: 13 01 01 ff addi sp, sp, -16 -80000124: 23 26 11 00 sw ra, 12(sp) -80000128: 23 24 81 00 sw s0, 8(sp) -8000012c: 13 04 01 01 addi s0, sp, 16 -80000130: 83 20 c1 00 lw ra, 12(sp) -80000134: 03 24 81 00 lw s0, 8(sp) -80000138: 13 01 01 01 addi sp, sp, 16 -8000013c: 17 13 00 00 auipc t1, 1 -80000140: 67 00 c3 fb jr -68(t1) - -80000144 <_pocl_kernel_fft_radix4_workgroup>: -80000144: 13 01 01 f0 addi sp, sp, -256 -80000148: 23 2e 11 0e sw ra, 252(sp) -8000014c: 23 2c 81 0e sw s0, 248(sp) -80000150: 23 2a 91 0e sw s1, 244(sp) -80000154: 23 28 21 0f sw s2, 240(sp) -80000158: 23 26 31 0f sw s3, 236(sp) -8000015c: 23 24 41 0f sw s4, 232(sp) -80000160: 23 22 51 0f sw s5, 228(sp) -80000164: 23 20 61 0f sw s6, 224(sp) -80000168: 23 2e 71 0d sw s7, 220(sp) -8000016c: 23 2c 81 0d sw s8, 216(sp) -80000170: 23 2a 91 0d sw s9, 212(sp) -80000174: 23 28 a1 0d sw s10, 208(sp) -80000178: 23 26 b1 0d sw s11, 204(sp) -8000017c: 27 24 81 0c fsw fs0, 200(sp) -80000180: 27 22 91 0c fsw fs1, 196(sp) -80000184: 27 20 21 0d fsw fs2, 192(sp) -80000188: 27 2e 31 0b fsw fs3, 188(sp) -8000018c: 13 04 01 10 addi s0, sp, 256 -80000190: 13 71 01 f8 andi sp, sp, -128 -80000194: 93 04 01 00 mv s1, sp -80000198: 83 26 05 00 lw a3, 0(a0) -8000019c: 03 27 45 00 lw a4, 4(a0) -800001a0: 83 27 85 00 lw a5, 8(a0) -800001a4: 83 a8 85 01 lw a7, 24(a1) -800001a8: 83 a2 c5 01 lw t0, 28(a1) -800001ac: 03 ab 05 02 lw s6, 32(a1) -800001b0: 83 25 c5 00 lw a1, 12(a0) -800001b4: 03 25 05 01 lw a0, 16(a0) -800001b8: 33 88 12 03 mul a6, t0, a7 -800001bc: 23 a2 04 07 sw a6, 100(s1) -800001c0: 33 08 68 03 mul a6, a6, s6 -800001c4: 23 ae 04 03 sw a6, 60(s1) -800001c8: 13 18 28 00 slli a6, a6, 2 -800001cc: 13 08 f8 00 addi a6, a6, 15 -800001d0: 13 78 08 ff andi a6, a6, -16 -800001d4: 23 a2 04 05 sw a6, 68(s1) -800001d8: 33 08 01 41 sub a6, sp, a6 -800001dc: 13 7d 08 f8 andi s10, a6, -128 -800001e0: 13 01 0d 00 mv sp, s10 -800001e4: 13 b8 18 00 seqz a6, a7 -800001e8: 0b 28 08 00 vx_split a6, a6 -800001ec: 93 8b 08 00 mv s7, a7 -800001f0: 63 94 08 00 bnez a7, 0x800001f8 <_pocl_kernel_fft_radix4_workgroup+0xb4> -800001f4: 93 0b 10 00 li s7, 1 -800001f8: 83 a3 06 00 lw t2, 0(a3) -800001fc: 83 26 07 00 lw a3, 0(a4) -80000200: 23 a8 d4 04 sw a3, 80(s1) -80000204: 83 ac 07 00 lw s9, 0(a5) -80000208: 83 a0 05 00 lw ra, 0(a1) -8000020c: 83 25 05 00 lw a1, 0(a0) -80000210: b3 8a c8 02 mul s5, a7, a2 -80000214: 0b 30 08 00 vx_join a6 -80000218: 13 b5 12 00 seqz a0, t0 -8000021c: 0b 25 05 00 vx_split a0, a0 -80000220: 63 94 02 00 bnez t0, 0x80000228 <_pocl_kernel_fft_radix4_workgroup+0xe4> -80000224: 93 02 10 00 li t0, 1 -80000228: 0b 30 05 00 vx_join a0 -8000022c: 13 35 1b 00 seqz a0, s6 -80000230: 0b 25 05 00 vx_split a0, a0 -80000234: 63 14 0b 00 bnez s6, 0x8000023c <_pocl_kernel_fft_radix4_workgroup+0xf8> -80000238: 13 0b 10 00 li s6, 1 -8000023c: 23 a0 74 04 sw t2, 64(s1) -80000240: 23 ac b4 06 sw a1, 120(s1) -80000244: 23 a6 54 06 sw t0, 108(s1) -80000248: 0b 30 05 00 vx_join a0 -8000024c: 93 05 00 00 li a1, 0 -80000250: 03 a5 44 06 lw a0, 100(s1) -80000254: 13 15 25 00 slli a0, a0, 2 -80000258: 23 a4 a4 06 sw a0, 104(s1) -8000025c: 37 25 00 80 lui a0, 524290 -80000260: 07 29 c5 63 flw fs2, 1596(a0) -80000264: 37 25 00 80 lui a0, 524290 -80000268: 87 29 05 64 flw fs3, 1600(a0) -8000026c: 23 a4 14 05 sw a7, 72(s1) -80000270: 93 98 28 00 slli a7, a7, 2 -80000274: 23 ae 14 07 sw a7, 124(s1) -80000278: 73 25 40 cc csrr a0, tmask -8000027c: 23 a6 a4 04 sw a0, 76(s1) -80000280: 13 09 30 00 li s2, 3 -80000284: 23 aa a4 05 sw s10, 84(s1) -80000288: 23 a0 64 07 sw s6, 96(s1) -8000028c: 6f 00 00 03 j 0x800002bc <_pocl_kernel_fft_radix4_workgroup+0x178> -80000290: 83 a5 c4 05 lw a1, 92(s1) -80000294: 93 85 15 00 addi a1, a1, 1 -80000298: 03 a5 84 06 lw a0, 104(s1) -8000029c: 03 ad 84 05 lw s10, 88(s1) -800002a0: 33 0d ad 00 add s10, s10, a0 -800002a4: 03 ab 04 06 lw s6, 96(s1) -800002a8: 33 c5 65 01 xor a0, a1, s6 -800002ac: 33 35 a0 00 snez a0, a0 -800002b0: 03 a6 c4 04 lw a2, 76(s1) -800002b4: 0b 50 c5 00 vx_pred a0, a2 -800002b8: 63 8a 65 0b beq a1, s6, 0x8000036c <_pocl_kernel_fft_radix4_workgroup+0x228> -800002bc: 23 ae b4 04 sw a1, 92(s1) -800002c0: 13 0c 00 00 li s8, 0 -800002c4: 73 25 40 cc csrr a0, tmask -800002c8: 23 a8 a4 06 sw a0, 112(s1) -800002cc: 23 ac a4 05 sw s10, 88(s1) -800002d0: 6f 00 c0 02 j 0x800002fc <_pocl_kernel_fft_radix4_workgroup+0x1b8> -800002d4: 13 0c 1c 00 addi s8, s8, 1 -800002d8: 03 a5 c4 07 lw a0, 124(s1) -800002dc: 03 ad 44 07 lw s10, 116(s1) -800002e0: 33 0d ad 00 add s10, s10, a0 -800002e4: 83 a5 c4 06 lw a1, 108(s1) -800002e8: 33 45 bc 00 xor a0, s8, a1 -800002ec: 33 35 a0 00 snez a0, a0 -800002f0: 03 a6 04 07 lw a2, 112(s1) -800002f4: 0b 50 c5 00 vx_pred a0, a2 -800002f8: e3 0c bc f8 beq s8, a1, 0x80000290 <_pocl_kernel_fft_radix4_workgroup+0x14c> -800002fc: 13 0a 00 00 li s4, 0 -80000300: f3 29 40 cc csrr s3, tmask -80000304: 23 aa a4 07 sw s10, 116(s1) -80000308: 03 ab 84 07 lw s6, 120(s1) -8000030c: 6f 00 00 02 j 0x8000032c <_pocl_kernel_fft_radix4_workgroup+0x1e8> -80000310: 13 0a 1a 00 addi s4, s4, 1 -80000314: 13 0b 8b 00 addi s6, s6, 8 -80000318: 13 0d 4d 00 addi s10, s10, 4 -8000031c: 33 c5 4b 01 xor a0, s7, s4 -80000320: 33 35 a0 00 snez a0, a0 -80000324: 0b 50 35 01 vx_pred a0, s3 -80000328: e3 86 4b fb beq s7, s4, 0x800002d4 <_pocl_kernel_fft_radix4_workgroup+0x190> -8000032c: 33 85 4a 01 add a0, s5, s4 -80000330: 23 20 ad 00 sw a0, 0(s10) -80000334: e3 4e 49 fd blt s2, s4, 0x80000310 <_pocl_kernel_fft_radix4_workgroup+0x1cc> -80000338: 53 70 0a d0 fcvt.s.w ft0, s4 -8000033c: 53 70 20 11 fmul.s ft0, ft0, fs2 -80000340: 53 74 30 11 fmul.s fs0, ft0, fs3 -80000344: 53 05 84 20 fmv.s fa0, fs0 -80000348: 93 8d 00 00 mv s11, ra -8000034c: ef f0 1f db jal 0x800000fc <_Z7_cl_cosf> -80000350: d3 04 a5 20 fmv.s fs1, fa0 -80000354: 53 05 84 20 fmv.s fa0, fs0 -80000358: ef f0 9f dc jal 0x80000120 <_Z7_cl_sinf> -8000035c: 93 80 0d 00 mv ra, s11 -80000360: 27 22 ab 00 fsw fa0, 4(s6) -80000364: 27 20 9b 00 fsw fs1, 0(s6) -80000368: 6f f0 9f fa j 0x80000310 <_pocl_kernel_fft_radix4_workgroup+0x1cc> -8000036c: 03 a5 c4 03 lw a0, 60(s1) -80000370: 13 05 f5 00 addi a0, a0, 15 -80000374: 13 75 05 ff andi a0, a0, -16 -80000378: 33 05 a1 40 sub a0, sp, a0 -8000037c: 13 75 05 f8 andi a0, a0, -128 -80000380: 13 01 05 00 mv sp, a0 -80000384: 93 05 00 00 li a1, 0 -80000388: 73 26 40 cc csrr a2, tmask -8000038c: 83 a6 44 05 lw a3, 84(s1) -80000390: 13 07 05 00 mv a4, a0 -80000394: 03 ad 84 04 lw s10, 72(s1) -80000398: 83 ad c4 06 lw s11, 108(s1) -8000039c: 83 a9 04 04 lw s3, 64(s1) -800003a0: 6f 00 80 02 j 0x800003c8 <_pocl_kernel_fft_radix4_workgroup+0x284> -800003a4: 93 85 15 00 addi a1, a1, 1 -800003a8: 83 a7 44 06 lw a5, 100(s1) -800003ac: 33 07 f7 00 add a4, a4, a5 -800003b0: 83 a7 84 06 lw a5, 104(s1) -800003b4: b3 86 f6 00 add a3, a3, a5 -800003b8: b3 c7 65 01 xor a5, a1, s6 -800003bc: b3 37 f0 00 snez a5, a5 -800003c0: 0b d0 c7 00 vx_pred a5, a2 -800003c4: 63 80 65 0b beq a1, s6, 0x80000464 <_pocl_kernel_fft_radix4_workgroup+0x320> -800003c8: 93 07 00 00 li a5, 0 -800003cc: 73 28 40 cc csrr a6, tmask -800003d0: 93 88 06 00 mv a7, a3 -800003d4: 93 02 07 00 mv t0, a4 -800003d8: 6f 00 40 02 j 0x800003fc <_pocl_kernel_fft_radix4_workgroup+0x2b8> -800003dc: 93 87 17 00 addi a5, a5, 1 -800003e0: b3 82 a2 01 add t0, t0, s10 -800003e4: 03 a3 c4 07 lw t1, 124(s1) -800003e8: b3 88 68 00 add a7, a7, t1 -800003ec: 33 c3 b7 01 xor t1, a5, s11 -800003f0: 33 33 60 00 snez t1, t1 -800003f4: 0b 50 03 01 vx_pred t1, a6 -800003f8: e3 86 b7 fb beq a5, s11, 0x800003a4 <_pocl_kernel_fft_radix4_workgroup+0x260> -800003fc: 73 23 40 cc csrr t1, tmask -80000400: 93 83 08 00 mv t2, a7 -80000404: 13 8e 02 00 mv t3, t0 -80000408: 93 8e 00 00 mv t4, ra -8000040c: 13 8f 0b 00 mv t5, s7 -80000410: 6f 00 40 02 j 0x80000434 <_pocl_kernel_fft_radix4_workgroup+0x2f0> -80000414: 0b b0 0f 00 vx_join t6 -80000418: 13 0f ff ff addi t5, t5, -1 -8000041c: 93 8e 8e 00 addi t4, t4, 8 -80000420: 13 0e 1e 00 addi t3, t3, 1 -80000424: 93 83 43 00 addi t2, t2, 4 -80000428: b3 3f e0 01 snez t6, t5 -8000042c: 0b d0 6f 00 vx_pred t6, t1 -80000430: e3 06 0f fa beqz t5, 0x800003dc <_pocl_kernel_fft_radix4_workgroup+0x298> -80000434: 03 a9 03 00 lw s2, 0(t2) -80000438: b3 3f 99 01 sltu t6, s2, s9 -8000043c: 23 00 fe 01 sb t6, 0(t3) -80000440: 8b af 0f 00 vx_split t6, t6 -80000444: e3 78 99 fd bgeu s2, s9, 0x80000414 <_pocl_kernel_fft_radix4_workgroup+0x2d0> -80000448: 13 19 39 00 slli s2, s2, 3 -8000044c: 33 89 29 01 add s2, s3, s2 -80000450: 07 20 49 00 flw ft0, 4(s2) -80000454: 87 20 09 00 flw ft1, 0(s2) -80000458: 27 a2 0e 00 fsw ft0, 4(t4) -8000045c: 27 a0 1e 00 fsw ft1, 0(t4) -80000460: 6f f0 5f fb j 0x80000414 <_pocl_kernel_fft_radix4_workgroup+0x2d0> -80000464: 83 a6 44 04 lw a3, 68(s1) -80000468: b3 05 d1 40 sub a1, sp, a3 -8000046c: 13 f6 05 f8 andi a2, a1, -128 -80000470: 13 01 06 00 mv sp, a2 -80000474: b3 05 d1 40 sub a1, sp, a3 -80000478: 93 f5 05 f8 andi a1, a1, -128 -8000047c: 13 81 05 00 mv sp, a1 -80000480: 93 06 00 00 li a3, 0 -80000484: 73 27 40 cc csrr a4, tmask -80000488: 93 07 10 00 li a5, 1 -8000048c: 13 88 05 00 mv a6, a1 -80000490: 93 08 06 00 mv a7, a2 -80000494: 83 ac 84 06 lw s9, 104(s1) -80000498: 93 02 00 00 li t0, 0 -8000049c: 73 23 40 cc csrr t1, tmask -800004a0: 93 03 08 00 mv t2, a6 -800004a4: 13 8e 08 00 mv t3, a7 -800004a8: f3 2e 40 cc csrr t4, tmask -800004ac: 13 8f 00 00 mv t5, ra -800004b0: 93 8f 03 00 mv t6, t2 -800004b4: 13 09 0e 00 mv s2, t3 -800004b8: 93 89 0b 00 mv s3, s7 -800004bc: 23 a0 ef 01 sw t5, 0(t6) -800004c0: 23 20 f9 00 sw a5, 0(s2) -800004c4: 93 89 f9 ff addi s3, s3, -1 -800004c8: 13 09 49 00 addi s2, s2, 4 -800004cc: 93 8f 4f 00 addi t6, t6, 4 -800004d0: 13 0f 8f 00 addi t5, t5, 8 -800004d4: 33 3a 30 01 snez s4, s3 -800004d8: 0b 50 da 01 vx_pred s4, t4 -800004dc: e3 90 09 fe bnez s3, 0x800004bc <_pocl_kernel_fft_radix4_workgroup+0x378> -800004e0: 93 82 12 00 addi t0, t0, 1 -800004e4: 83 ae c4 07 lw t4, 124(s1) -800004e8: 33 0e de 01 add t3, t3, t4 -800004ec: b3 83 d3 01 add t2, t2, t4 -800004f0: b3 ce b2 01 xor t4, t0, s11 -800004f4: b3 3e d0 01 snez t4, t4 -800004f8: 0b d0 6e 00 vx_pred t4, t1 -800004fc: e3 96 b2 fb bne t0, s11, 0x800004a8 <_pocl_kernel_fft_radix4_workgroup+0x364> -80000500: 93 86 16 00 addi a3, a3, 1 -80000504: b3 88 98 01 add a7, a7, s9 -80000508: 33 08 98 01 add a6, a6, s9 -8000050c: b3 c2 66 01 xor t0, a3, s6 -80000510: b3 32 50 00 snez t0, t0 -80000514: 0b d0 e2 00 vx_pred t0, a4 -80000518: e3 90 66 f9 bne a3, s6, 0x80000498 <_pocl_kernel_fft_radix4_workgroup+0x354> -8000051c: 93 08 00 00 li a7, 0 -80000520: f3 26 40 cc csrr a3, tmask -80000524: 23 aa d4 06 sw a3, 116(s1) -80000528: 13 07 00 01 li a4, 16 -8000052c: 93 07 80 01 li a5, 24 -80000530: 53 00 00 f0 fmv.w.x ft0, zero -80000534: 6f 00 c0 01 j 0x80000550 <_pocl_kernel_fft_radix4_workgroup+0x40c> -80000538: 0b b0 02 00 vx_join t0 -8000053c: 83 ac 84 06 lw s9, 104(s1) -80000540: 93 42 18 00 xori t0, a6, 1 -80000544: 83 a6 44 07 lw a3, 116(s1) -80000548: 0b d0 d2 00 vx_pred t0, a3 -8000054c: 63 10 08 22 bnez a6, 0x8000076c <_pocl_kernel_fft_radix4_workgroup+0x628> -80000550: 13 03 00 00 li t1, 0 -80000554: 33 8e 1c 03 mul t3, s9, a7 -80000558: b3 83 c5 01 add t2, a1, t3 -8000055c: 33 0e c6 01 add t3, a2, t3 -80000560: f3 2e 40 cc csrr t4, tmask -80000564: 13 0f 00 00 li t5, 0 -80000568: f3 2f 40 cc csrr t6, tmask -8000056c: 93 0a 0e 00 mv s5, t3 -80000570: 13 8b 03 00 mv s6, t2 -80000574: 93 8c 00 00 mv s9, ra -80000578: 83 a6 84 07 lw a3, 120(s1) -8000057c: 03 a8 0a 00 lw a6, 0(s5) -80000580: b3 52 0f 03 divu t0, t5, a6 -80000584: 13 f9 32 00 andi s2, t0, 3 -80000588: 93 12 28 00 slli t0, a6, 2 -8000058c: 93 f9 c2 0f andi s3, t0, 252 -80000590: b3 59 37 03 divu s3, a4, s3 -80000594: 33 09 39 03 mul s2, s2, s3 -80000598: 13 19 39 00 slli s2, s2, 3 -8000059c: 83 29 0b 00 lw s3, 0(s6) -800005a0: 33 89 26 01 add s2, a3, s2 -800005a4: 87 20 49 00 flw ft1, 4(s2) -800005a8: 07 21 09 00 flw ft2, 0(s2) -800005ac: 87 a1 49 00 flw ft3, 4(s3) -800005b0: 07 a2 09 00 flw ft4, 0(s3) -800005b4: 33 09 0f 01 add s2, t5, a6 -800005b8: 13 19 39 00 slli s2, s2, 3 -800005bc: 33 89 20 01 add s2, ra, s2 -800005c0: 87 22 49 00 flw ft5, 4(s2) -800005c4: 07 23 09 00 flw ft6, 0(s2) -800005c8: 13 1a 48 00 slli s4, a6, 4 -800005cc: 33 8a 4c 01 add s4, s9, s4 -800005d0: 87 23 4a 00 flw ft7, 4(s4) -800005d4: 07 25 0a 00 flw fa0, 0(s4) -800005d8: 33 0c f8 02 mul s8, a6, a5 -800005dc: 33 8c 8c 01 add s8, s9, s8 -800005e0: 87 25 4c 00 flw fa1, 4(s8) -800005e4: 07 26 0c 00 flw fa2, 0(s8) -800005e8: 53 73 61 10 fmul.s ft6, ft2, ft6 -800005ec: d3 f2 50 10 fmul.s ft5, ft1, ft5 -800005f0: d3 76 21 10 fmul.s fa3, ft2, ft2 -800005f4: 53 f7 10 10 fmul.s fa4, ft1, ft1 -800005f8: 53 f5 a6 10 fmul.s fa0, fa3, fa0 -800005fc: d3 73 77 10 fmul.s ft7, fa4, ft7 -80000600: 53 71 d1 10 fmul.s ft2, ft2, fa3 -80000604: d3 f0 e0 10 fmul.s ft1, ft1, fa4 -80000608: 53 71 c1 10 fmul.s ft2, ft2, fa2 -8000060c: d3 f0 b0 10 fmul.s ft1, ft1, fa1 -80000610: d3 75 a2 00 fadd.s fa1, ft4, fa0 -80000614: 53 f6 71 00 fadd.s fa2, ft3, ft7 -80000618: 53 72 a2 08 fsub.s ft4, ft4, fa0 -8000061c: d3 f1 71 08 fsub.s ft3, ft3, ft7 -80000620: d3 73 23 00 fadd.s ft7, ft6, ft2 -80000624: 53 f5 12 00 fadd.s fa0, ft5, ft1 -80000628: 53 71 23 08 fsub.s ft2, ft6, ft2 -8000062c: d3 f0 12 08 fsub.s ft1, ft5, ft1 -80000630: 53 71 01 10 fmul.s ft2, ft2, ft0 -80000634: d3 f2 75 00 fadd.s ft5, fa1, ft7 -80000638: 53 73 a6 00 fadd.s ft6, fa2, fa0 -8000063c: 27 a0 59 00 fsw ft5, 0(s3) -80000640: 27 a2 69 00 fsw ft6, 4(s3) -80000644: d3 72 22 00 fadd.s ft5, ft4, ft2 -80000648: 53 f3 11 08 fsub.s ft6, ft3, ft1 -8000064c: 27 20 59 00 fsw ft5, 0(s2) -80000650: 27 22 69 00 fsw ft6, 4(s2) -80000654: d3 f2 75 08 fsub.s ft5, fa1, ft7 -80000658: 53 73 a6 08 fsub.s ft6, fa2, fa0 -8000065c: 27 20 5a 00 fsw ft5, 0(s4) -80000660: 27 22 6a 00 fsw ft6, 4(s4) -80000664: 53 71 22 08 fsub.s ft2, ft4, ft2 -80000668: d3 f0 11 00 fadd.s ft1, ft3, ft1 -8000066c: 27 20 2c 00 fsw ft2, 0(s8) -80000670: 27 22 1c 00 fsw ft1, 4(s8) -80000674: 13 0f 1f 00 addi t5, t5, 1 -80000678: 93 8c 8c 00 addi s9, s9, 8 -8000067c: 13 0b 4b 00 addi s6, s6, 4 -80000680: 93 8a 4a 00 addi s5, s5, 4 -80000684: 33 c9 eb 01 xor s2, s7, t5 -80000688: 33 39 20 01 snez s2, s2 -8000068c: 0b 50 f9 01 vx_pred s2, t6 -80000690: e3 96 eb ef bne s7, t5, 0x8000057c <_pocl_kernel_fft_radix4_workgroup+0x438> -80000694: 13 03 13 00 addi t1, t1, 1 -80000698: 03 af c4 07 lw t5, 124(s1) -8000069c: b3 83 e3 01 add t2, t2, t5 -800006a0: 33 0e ee 01 add t3, t3, t5 -800006a4: 33 4f b3 01 xor t5, t1, s11 -800006a8: 33 3f e0 01 snez t5, t5 -800006ac: 0b 50 df 01 vx_pred t5, t4 -800006b0: e3 1a b3 eb bne t1, s11, 0x80000564 <_pocl_kernel_fft_radix4_workgroup+0x420> -800006b4: 93 88 18 00 addi a7, a7, 1 -800006b8: 03 ab 04 06 lw s6, 96(s1) -800006bc: 33 c3 68 01 xor t1, a7, s6 -800006c0: 13 33 13 00 seqz t1, t1 -800006c4: 0b 23 03 00 vx_split t1, t1 -800006c8: 93 03 10 00 li t2, 1 -800006cc: 03 ac 44 05 lw s8, 84(s1) -800006d0: 63 90 68 09 bne a7, s6, 0x80000750 <_pocl_kernel_fft_radix4_workgroup+0x60c> -800006d4: 93 08 00 00 li a7, 0 -800006d8: f3 23 40 cc csrr t2, tmask -800006dc: 13 0e 06 00 mv t3, a2 -800006e0: 83 ac 84 06 lw s9, 104(s1) -800006e4: 93 0e 00 00 li t4, 0 -800006e8: 73 2f 40 cc csrr t5, tmask -800006ec: 93 0f 0e 00 mv t6, t3 -800006f0: 73 29 40 cc csrr s2, tmask -800006f4: 93 89 0f 00 mv s3, t6 -800006f8: 13 8a 0b 00 mv s4, s7 -800006fc: 23 a0 59 00 sw t0, 0(s3) -80000700: 13 0a fa ff addi s4, s4, -1 -80000704: 93 89 49 00 addi s3, s3, 4 -80000708: b3 3a 40 01 snez s5, s4 -8000070c: 0b d0 2a 01 vx_pred s5, s2 -80000710: e3 16 0a fe bnez s4, 0x800006fc <_pocl_kernel_fft_radix4_workgroup+0x5b8> -80000714: 93 8e 1e 00 addi t4, t4, 1 -80000718: 03 a9 c4 07 lw s2, 124(s1) -8000071c: b3 8f 2f 01 add t6, t6, s2 -80000720: 33 c9 be 01 xor s2, t4, s11 -80000724: 33 39 20 01 snez s2, s2 -80000728: 0b 50 e9 01 vx_pred s2, t5 -8000072c: e3 92 be fd bne t4, s11, 0x800006f0 <_pocl_kernel_fft_radix4_workgroup+0x5ac> -80000730: 93 88 18 00 addi a7, a7, 1 -80000734: 33 0e 9e 01 add t3, t3, s9 -80000738: b3 ce 68 01 xor t4, a7, s6 -8000073c: b3 3e d0 01 snez t4, t4 -80000740: 0b d0 7e 00 vx_pred t4, t2 -80000744: e3 90 68 fb bne a7, s6, 0x800006e4 <_pocl_kernel_fft_radix4_workgroup+0x5a0> -80000748: 93 08 00 00 li a7, 0 -8000074c: 93 33 48 00 sltiu t2, a6, 4 -80000750: 0b 30 03 00 vx_join t1 -80000754: 8b a2 03 00 vx_split t0, t2 -80000758: 13 08 10 00 li a6, 1 -8000075c: 83 aa 04 05 lw s5, 80(s1) -80000760: e3 8c 03 dc beqz t2, 0x80000538 <_pocl_kernel_fft_radix4_workgroup+0x3f4> -80000764: 13 08 00 00 li a6, 0 -80000768: 6f f0 1f dd j 0x80000538 <_pocl_kernel_fft_radix4_workgroup+0x3f4> -8000076c: 13 06 00 00 li a2, 0 -80000770: f3 26 40 cc csrr a3, tmask -80000774: 03 aa 04 06 lw s4, 96(s1) -80000778: 6f 00 80 02 j 0x800007a0 <_pocl_kernel_fft_radix4_workgroup+0x65c> -8000077c: 13 06 16 00 addi a2, a2, 1 -80000780: b3 85 95 01 add a1, a1, s9 -80000784: 33 0c 9c 01 add s8, s8, s9 -80000788: 03 a7 44 06 lw a4, 100(s1) -8000078c: 33 05 e5 00 add a0, a0, a4 -80000790: 33 47 46 01 xor a4, a2, s4 -80000794: 33 37 e0 00 snez a4, a4 -80000798: 0b 50 d7 00 vx_pred a4, a3 -8000079c: 63 04 46 0b beq a2, s4, 0x80000844 <_pocl_kernel_fft_radix4_workgroup+0x700> -800007a0: 13 07 00 00 li a4, 0 -800007a4: f3 27 40 cc csrr a5, tmask -800007a8: 13 08 05 00 mv a6, a0 -800007ac: 93 08 0c 00 mv a7, s8 -800007b0: 93 82 05 00 mv t0, a1 -800007b4: 6f 00 80 02 j 0x800007dc <_pocl_kernel_fft_radix4_workgroup+0x698> -800007b8: 13 07 17 00 addi a4, a4, 1 -800007bc: 03 a3 c4 07 lw t1, 124(s1) -800007c0: b3 82 62 00 add t0, t0, t1 -800007c4: b3 88 68 00 add a7, a7, t1 -800007c8: 33 08 a8 01 add a6, a6, s10 -800007cc: 33 43 b7 01 xor t1, a4, s11 -800007d0: 33 33 60 00 snez t1, t1 -800007d4: 0b 50 f3 00 vx_pred t1, a5 -800007d8: e3 02 b7 fb beq a4, s11, 0x8000077c <_pocl_kernel_fft_radix4_workgroup+0x638> -800007dc: 73 23 40 cc csrr t1, tmask -800007e0: 93 03 08 00 mv t2, a6 -800007e4: 13 8e 08 00 mv t3, a7 -800007e8: 93 8e 02 00 mv t4, t0 -800007ec: 13 8f 0b 00 mv t5, s7 -800007f0: 6f 00 40 02 j 0x80000814 <_pocl_kernel_fft_radix4_workgroup+0x6d0> -800007f4: 0b b0 0f 00 vx_join t6 -800007f8: 13 0f ff ff addi t5, t5, -1 -800007fc: 93 8e 4e 00 addi t4, t4, 4 -80000800: 13 0e 4e 00 addi t3, t3, 4 -80000804: 93 83 13 00 addi t2, t2, 1 -80000808: b3 3f e0 01 snez t6, t5 -8000080c: 0b d0 6f 00 vx_pred t6, t1 -80000810: e3 04 0f fa beqz t5, 0x800007b8 <_pocl_kernel_fft_radix4_workgroup+0x674> -80000814: 03 c9 03 00 lbu s2, 0(t2) -80000818: 8b 2f 09 00 vx_split t6, s2 -8000081c: e3 0c 09 fc beqz s2, 0x800007f4 <_pocl_kernel_fft_radix4_workgroup+0x6b0> -80000820: 03 a9 0e 00 lw s2, 0(t4) -80000824: 83 29 0e 00 lw s3, 0(t3) -80000828: 07 20 49 00 flw ft0, 4(s2) -8000082c: 87 20 09 00 flw ft1, 0(s2) -80000830: 93 99 39 00 slli s3, s3, 3 -80000834: b3 89 3a 01 add s3, s5, s3 -80000838: 27 a2 09 00 fsw ft0, 4(s3) -8000083c: 27 a0 19 00 fsw ft1, 0(s3) -80000840: 6f f0 5f fb j 0x800007f4 <_pocl_kernel_fft_radix4_workgroup+0x6b0> -80000844: 13 01 04 f0 addi sp, s0, -256 -80000848: 83 20 c1 0f lw ra, 252(sp) -8000084c: 03 24 81 0f lw s0, 248(sp) -80000850: 83 24 41 0f lw s1, 244(sp) -80000854: 03 29 01 0f lw s2, 240(sp) -80000858: 83 29 c1 0e lw s3, 236(sp) -8000085c: 03 2a 81 0e lw s4, 232(sp) -80000860: 83 2a 41 0e lw s5, 228(sp) -80000864: 03 2b 01 0e lw s6, 224(sp) -80000868: 83 2b c1 0d lw s7, 220(sp) -8000086c: 03 2c 81 0d lw s8, 216(sp) -80000870: 83 2c 41 0d lw s9, 212(sp) -80000874: 03 2d 01 0d lw s10, 208(sp) -80000878: 83 2d c1 0c lw s11, 204(sp) -8000087c: 07 24 81 0c flw fs0, 200(sp) -80000880: 87 24 41 0c flw fs1, 196(sp) -80000884: 07 29 01 0c flw fs2, 192(sp) -80000888: 87 29 c1 0b flw fs3, 188(sp) -8000088c: 13 01 01 10 addi sp, sp, 256 -80000890: 67 80 00 00 ret - -80000894 <_exit>: -80000894: 13 04 05 00 mv s0, a0 -80000898: ef 00 80 5a jal 0x80000e40 -8000089c: 93 01 04 00 mv gp, s0 -800008a0: 0b 00 00 00 vx_tmc zero - -800008a4 : -800008a4: 97 41 00 00 auipc gp, 4 -800008a8: 93 81 c1 e9 addi gp, gp, -356 -800008ac: 37 01 00 ff lui sp, 1044480 -800008b0: f3 22 40 f1 csrr t0, mhartid -800008b4: 13 93 d2 00 slli t1, t0, 13 -800008b8: 33 01 61 40 sub sp, sp, t1 -800008bc: 13 03 00 00 li t1, 0 -800008c0: b3 82 62 02 mul t0, t0, t1 -800008c4: 17 42 00 00 auipc tp, 4 -800008c8: 13 02 72 74 addi tp, tp, 1863 -800008cc: 33 02 52 00 add tp, tp, t0 -800008d0: 13 72 02 fc andi tp, tp, -64 -800008d4: 67 80 00 00 ret - -800008d8 : -800008d8: 93 02 f0 ff li t0, -1 -800008dc: 0b 80 02 00 vx_tmc t0 -800008e0: ef f0 5f fc jal 0x800008a4 -800008e4: 0b 00 00 00 vx_tmc zero -800008e8: 67 80 00 00 ret - -800008ec : -800008ec: 93 02 f0 ff li t0, -1 -800008f0: 0b 80 02 00 vx_tmc t0 -800008f4: ef 00 c0 01 jal 0x80000910 <__init_tls> -800008f8: 0b 00 00 00 vx_tmc zero -800008fc: 67 80 00 00 ret - -80000900 : -80000900: f3 22 30 cc csrr t0, gid -80000904: 13 03 10 00 li t1, 1 -80000908: e3 9c 62 fe bne t0, t1, 0x80000900 -8000090c: 67 80 00 00 ret - -80000910 <__init_tls>: -80000910: 13 01 01 ff addi sp, sp, -16 -80000914: 13 06 00 00 li a2, 0 -80000918: 97 35 00 00 auipc a1, 3 -8000091c: 93 85 c5 1f addi a1, a1, 508 -80000920: 13 05 02 00 mv a0, tp -80000924: 23 24 81 00 sw s0, 8(sp) -80000928: 23 26 11 00 sw ra, 12(sp) -8000092c: 13 04 02 00 mv s0, tp -80000930: ef 10 10 08 jal 0x800021b0 -80000934: 13 05 00 00 li a0, 0 -80000938: 33 05 a4 00 add a0, s0, a0 -8000093c: 03 24 81 00 lw s0, 8(sp) -80000940: 83 20 c1 00 lw ra, 12(sp) -80000944: 13 06 00 00 li a2, 0 -80000948: 93 05 00 00 li a1, 0 -8000094c: 13 01 01 01 addi sp, sp, 16 -80000950: 6f 10 50 20 j 0x80002354 - -80000954 <__libc_init_array>: -80000954: 13 01 01 ff addi sp, sp, -16 -80000958: 23 24 81 00 sw s0, 8(sp) -8000095c: 23 20 21 01 sw s2, 0(sp) -80000960: 97 37 00 00 auipc a5, 3 -80000964: 93 87 47 1b addi a5, a5, 436 -80000968: 17 34 00 00 auipc s0, 3 -8000096c: 13 04 c4 1a addi s0, s0, 428 -80000970: 23 26 11 00 sw ra, 12(sp) -80000974: 23 22 91 00 sw s1, 4(sp) -80000978: 33 89 87 40 sub s2, a5, s0 -8000097c: 63 80 87 02 beq a5, s0, 0x8000099c <__libc_init_array+0x48> -80000980: 13 59 29 40 srai s2, s2, 2 -80000984: 93 04 00 00 li s1, 0 -80000988: 83 27 04 00 lw a5, 0(s0) -8000098c: 93 84 14 00 addi s1, s1, 1 -80000990: 13 04 44 00 addi s0, s0, 4 -80000994: e7 80 07 00 jalr a5 -80000998: e3 e8 24 ff bltu s1, s2, 0x80000988 <__libc_init_array+0x34> -8000099c: 97 37 00 00 auipc a5, 3 -800009a0: 93 87 c7 17 addi a5, a5, 380 -800009a4: 17 34 00 00 auipc s0, 3 -800009a8: 13 04 04 17 addi s0, s0, 368 -800009ac: 33 89 87 40 sub s2, a5, s0 -800009b0: 13 59 29 40 srai s2, s2, 2 -800009b4: 63 8e 87 00 beq a5, s0, 0x800009d0 <__libc_init_array+0x7c> -800009b8: 93 04 00 00 li s1, 0 -800009bc: 83 27 04 00 lw a5, 0(s0) -800009c0: 93 84 14 00 addi s1, s1, 1 -800009c4: 13 04 44 00 addi s0, s0, 4 -800009c8: e7 80 07 00 jalr a5 -800009cc: e3 e8 24 ff bltu s1, s2, 0x800009bc <__libc_init_array+0x68> -800009d0: 83 20 c1 00 lw ra, 12(sp) -800009d4: 03 24 81 00 lw s0, 8(sp) -800009d8: 83 24 41 00 lw s1, 4(sp) -800009dc: 03 29 01 00 lw s2, 0(sp) -800009e0: 13 01 01 01 addi sp, sp, 16 -800009e4: 67 80 00 00 ret - -800009e8 <__libc_fini_array>: -800009e8: 13 01 01 ff addi sp, sp, -16 -800009ec: 23 24 81 00 sw s0, 8(sp) -800009f0: 97 37 00 00 auipc a5, 3 -800009f4: 93 87 87 12 addi a5, a5, 296 -800009f8: 17 34 00 00 auipc s0, 3 -800009fc: 13 04 04 12 addi s0, s0, 288 -80000a00: 33 04 f4 40 sub s0, s0, a5 -80000a04: 23 22 91 00 sw s1, 4(sp) -80000a08: 23 26 11 00 sw ra, 12(sp) -80000a0c: 93 54 24 40 srai s1, s0, 2 -80000a10: 63 80 04 02 beqz s1, 0x80000a30 <__libc_fini_array+0x48> -80000a14: 13 04 c4 ff addi s0, s0, -4 -80000a18: 33 04 f4 00 add s0, s0, a5 -80000a1c: 83 27 04 00 lw a5, 0(s0) -80000a20: 93 84 f4 ff addi s1, s1, -1 -80000a24: 13 04 c4 ff addi s0, s0, -4 -80000a28: e7 80 07 00 jalr a5 -80000a2c: e3 98 04 fe bnez s1, 0x80000a1c <__libc_fini_array+0x34> -80000a30: 83 20 c1 00 lw ra, 12(sp) -80000a34: 03 24 81 00 lw s0, 8(sp) -80000a38: 83 24 41 00 lw s1, 4(sp) -80000a3c: 13 01 01 01 addi sp, sp, 16 -80000a40: 67 80 00 00 ret - -80000a44 : -80000a44: 13 01 01 fe addi sp, sp, -32 -80000a48: 23 2e 11 00 sw ra, 28(sp) -80000a4c: 23 2c 81 00 sw s0, 24(sp) -80000a50: 23 2a 91 00 sw s1, 20(sp) -80000a54: 23 28 21 01 sw s2, 16(sp) -80000a58: 23 26 31 01 sw s3, 12(sp) -80000a5c: 23 24 41 01 sw s4, 8(sp) -80000a60: 73 25 00 fc csrr a0, nt -80000a64: 73 26 20 cc csrr a2, cid -80000a68: 73 27 10 cc csrr a4, wid -80000a6c: f3 26 00 cc csrr a3, tid -80000a70: 97 37 00 00 auipc a5, 3 -80000a74: 93 87 c7 55 addi a5, a5, 1372 -80000a78: 13 16 26 00 slli a2, a2, 2 -80000a7c: b3 87 c7 00 add a5, a5, a2 -80000a80: 83 a4 07 00 lw s1, 0(a5) -80000a84: 83 a7 44 01 lw a5, 20(s1) -80000a88: 03 a6 04 01 lw a2, 16(s1) -80000a8c: 33 2a f7 00 slt s4, a4, a5 -80000a90: 33 04 e6 02 mul s0, a2, a4 -80000a94: 33 0a ca 00 add s4, s4, a2 -80000a98: 63 54 f7 00 bge a4, a5, 0x80000aa0 -80000a9c: 93 07 07 00 mv a5, a4 -80000aa0: 33 04 f4 00 add s0, s0, a5 -80000aa4: 83 a5 04 00 lw a1, 0(s1) -80000aa8: 03 a6 c4 00 lw a2, 12(s1) -80000aac: 03 c7 84 01 lbu a4, 24(s1) -80000ab0: 03 a9 05 00 lw s2, 0(a1) -80000ab4: 83 a9 45 00 lw s3, 4(a1) -80000ab8: 33 04 a4 02 mul s0, s0, a0 -80000abc: b3 07 da 02 mul a5, s4, a3 -80000ac0: 33 04 c4 00 add s0, s0, a2 -80000ac4: 33 04 f4 00 add s0, s0, a5 -80000ac8: b3 09 39 03 mul s3, s2, s3 -80000acc: 33 0a 8a 00 add s4, s4, s0 -80000ad0: 63 00 07 08 beqz a4, 0x80000b50 -80000ad4: 63 44 44 03 blt s0, s4, 0x80000afc -80000ad8: 83 20 c1 01 lw ra, 28(sp) -80000adc: 03 24 81 01 lw s0, 24(sp) -80000ae0: 83 24 41 01 lw s1, 20(sp) -80000ae4: 03 29 01 01 lw s2, 16(sp) -80000ae8: 83 29 c1 00 lw s3, 12(sp) -80000aec: 03 2a 81 00 lw s4, 8(sp) -80000af0: 13 01 01 02 addi sp, sp, 32 -80000af4: 67 80 00 00 ret -80000af8: 83 a5 04 00 lw a1, 0(s1) -80000afc: 03 c7 94 01 lbu a4, 25(s1) -80000b00: 83 c6 a4 01 lbu a3, 26(s1) -80000b04: 03 a8 44 00 lw a6, 4(s1) -80000b08: 33 57 e4 40 sra a4, s0, a4 -80000b0c: b3 87 e9 02 mul a5, s3, a4 -80000b10: 03 a5 84 00 lw a0, 8(s1) -80000b14: b3 07 f4 40 sub a5, s0, a5 -80000b18: b3 d6 d7 40 sra a3, a5, a3 -80000b1c: 33 06 d9 02 mul a2, s2, a3 -80000b20: 13 04 14 00 addi s0, s0, 1 -80000b24: 33 86 c7 40 sub a2, a5, a2 -80000b28: e7 00 08 00 jalr a6 -80000b2c: e3 16 8a fc bne s4, s0, 0x80000af8 -80000b30: 83 20 c1 01 lw ra, 28(sp) -80000b34: 03 24 81 01 lw s0, 24(sp) -80000b38: 83 24 41 01 lw s1, 20(sp) -80000b3c: 03 29 01 01 lw s2, 16(sp) -80000b40: 83 29 c1 00 lw s3, 12(sp) -80000b44: 03 2a 81 00 lw s4, 8(sp) -80000b48: 13 01 01 02 addi sp, sp, 32 -80000b4c: 67 80 00 00 ret -80000b50: 63 46 44 01 blt s0, s4, 0x80000b5c -80000b54: 6f f0 5f f8 j 0x80000ad8 -80000b58: 83 a5 04 00 lw a1, 0(s1) -80000b5c: 33 66 34 03 rem a2, s0, s3 -80000b60: 83 a7 44 00 lw a5, 4(s1) -80000b64: 03 a5 84 00 lw a0, 8(s1) -80000b68: 33 47 34 03 div a4, s0, s3 -80000b6c: 13 04 14 00 addi s0, s0, 1 -80000b70: b3 46 26 03 div a3, a2, s2 -80000b74: 33 66 26 03 rem a2, a2, s2 -80000b78: e7 80 07 00 jalr a5 -80000b7c: e3 1e 8a fc bne s4, s0, 0x80000b58 -80000b80: 83 20 c1 01 lw ra, 28(sp) -80000b84: 03 24 81 01 lw s0, 24(sp) -80000b88: 83 24 41 01 lw s1, 20(sp) -80000b8c: 03 29 01 01 lw s2, 16(sp) -80000b90: 83 29 c1 00 lw s3, 12(sp) -80000b94: 03 2a 81 00 lw s4, 8(sp) -80000b98: 13 01 01 02 addi sp, sp, 32 -80000b9c: 67 80 00 00 ret - -80000ba0 : -80000ba0: 73 27 20 cc csrr a4, cid -80000ba4: 73 28 00 cc csrr a6, tid -80000ba8: 97 37 00 00 auipc a5, 3 -80000bac: 93 87 47 42 addi a5, a5, 1060 -80000bb0: 13 17 27 00 slli a4, a4, 2 -80000bb4: b3 87 e7 00 add a5, a5, a4 -80000bb8: 83 a7 07 00 lw a5, 0(a5) -80000bbc: 83 a5 07 00 lw a1, 0(a5) -80000bc0: 83 a6 c7 00 lw a3, 12(a5) -80000bc4: 03 c7 87 01 lbu a4, 24(a5) -80000bc8: 03 a6 05 00 lw a2, 0(a1) -80000bcc: 83 a8 45 00 lw a7, 4(a1) -80000bd0: 33 08 d8 00 add a6, a6, a3 -80000bd4: b3 08 16 03 mul a7, a2, a7 -80000bd8: 63 08 07 02 beqz a4, 0x80000c08 -80000bdc: 03 c7 97 01 lbu a4, 25(a5) -80000be0: 83 c6 a7 01 lbu a3, 26(a5) -80000be4: 03 a3 47 00 lw t1, 4(a5) -80000be8: 33 57 e8 40 sra a4, a6, a4 -80000bec: 03 a5 87 00 lw a0, 8(a5) -80000bf0: b3 88 e8 02 mul a7, a7, a4 -80000bf4: 33 08 18 41 sub a6, a6, a7 -80000bf8: b3 56 d8 40 sra a3, a6, a3 -80000bfc: 33 06 d6 02 mul a2, a2, a3 -80000c00: 33 06 c8 40 sub a2, a6, a2 -80000c04: 67 00 03 00 jr t1 -80000c08: 33 63 18 03 rem t1, a6, a7 -80000c0c: 03 ae 47 00 lw t3, 4(a5) -80000c10: 03 a5 87 00 lw a0, 8(a5) -80000c14: b3 46 c3 02 div a3, t1, a2 -80000c18: 33 47 18 03 div a4, a6, a7 -80000c1c: 33 66 c3 02 rem a2, t1, a2 -80000c20: 67 00 0e 00 jr t3 - -80000c24 : -80000c24: 13 01 01 ff addi sp, sp, -16 -80000c28: 23 26 11 00 sw ra, 12(sp) -80000c2c: 93 07 f0 ff li a5, -1 -80000c30: 0b 80 07 00 vx_tmc a5 -80000c34: ef f0 1f e1 jal 0x80000a44 -80000c38: 0b 00 00 00 vx_tmc zero -80000c3c: 83 20 c1 00 lw ra, 12(sp) -80000c40: 13 01 01 01 addi sp, sp, 16 -80000c44: 67 80 00 00 ret - -80000c48 : -80000c48: 13 01 01 f9 addi sp, sp, -112 -80000c4c: 23 2e 31 05 sw s3, 92(sp) -80000c50: 23 2a 51 05 sw s5, 84(sp) -80000c54: 83 29 45 00 lw s3, 4(a0) -80000c58: 83 2a 05 00 lw s5, 0(a0) -80000c5c: 03 27 85 00 lw a4, 8(a0) -80000c60: 23 26 11 06 sw ra, 108(sp) -80000c64: 23 24 81 06 sw s0, 104(sp) -80000c68: 23 22 91 06 sw s1, 100(sp) -80000c6c: 23 20 21 07 sw s2, 96(sp) -80000c70: 23 2c 41 05 sw s4, 88(sp) -80000c74: 23 28 61 05 sw s6, 80(sp) -80000c78: 23 26 71 05 sw s7, 76(sp) -80000c7c: 23 24 81 05 sw s8, 72(sp) -80000c80: 23 22 91 05 sw s9, 68(sp) -80000c84: 23 20 a1 05 sw s10, 64(sp) -80000c88: 23 2e b1 03 sw s11, 60(sp) -80000c8c: f3 26 20 fc csrr a3, nw -80000c90: f3 2c 10 fc csrr s9, nw -80000c94: 73 2d 00 fc csrr s10, nt -80000c98: f3 24 20 cc csrr s1, cid -80000c9c: 93 07 f0 3f li a5, 1023 -80000ca0: 63 c4 97 0e blt a5, s1, 0x80000d88 -80000ca4: b3 89 3a 03 mul s3, s5, s3 -80000ca8: 93 0b 06 00 mv s7, a2 -80000cac: 13 04 05 00 mv s0, a0 -80000cb0: 13 8c 05 00 mv s8, a1 -80000cb4: 93 07 10 00 li a5, 1 -80000cb8: 33 07 37 03 mul a4, a4, s3 -80000cbc: 33 86 ac 03 mul a2, s9, s10 -80000cc0: 63 54 e6 00 bge a2, a4, 0x80000cc8 -80000cc4: b3 47 c7 02 div a5, a4, a2 -80000cc8: 63 ce f6 0e blt a3, a5, 0x80000dc4 -80000ccc: 63 de f4 0a bge s1, a5, 0x80000d88 -80000cd0: 13 86 f7 ff addi a2, a5, -1 -80000cd4: b3 46 f7 02 div a3, a4, a5 -80000cd8: 13 8a 06 00 mv s4, a3 -80000cdc: 63 16 96 00 bne a2, s1, 0x80000ce8 -80000ce0: 33 67 f7 02 rem a4, a4, a5 -80000ce4: 33 0a d7 00 add s4, a4, a3 -80000ce8: b3 4d aa 03 div s11, s4, s10 -80000cec: 33 6a aa 03 rem s4, s4, s10 -80000cf0: 63 c0 9d 0f blt s11, s9, 0x80000dd0 -80000cf4: b3 e7 9d 03 rem a5, s11, s9 -80000cf8: 33 cb 9d 03 div s6, s11, s9 -80000cfc: 23 26 f1 00 sw a5, 12(sp) -80000d00: 13 85 09 00 mv a0, s3 -80000d04: 23 24 d1 00 sw a3, 8(sp) -80000d08: ef 10 90 0e jal 0x800025f0 <__clzsi2> -80000d0c: 13 09 05 00 mv s2, a0 -80000d10: 13 85 0a 00 mv a0, s5 -80000d14: ef 10 d0 0d jal 0x800025f0 <__clzsi2> -80000d18: 83 26 81 00 lw a3, 8(sp) -80000d1c: 13 07 f0 01 li a4, 31 -80000d20: 33 09 27 41 sub s2, a4, s2 -80000d24: 93 87 f9 ff addi a5, s3, -1 -80000d28: b3 f7 37 01 and a5, a5, s3 -80000d2c: 13 79 f9 0f andi s2, s2, 255 -80000d30: 13 19 89 00 slli s2, s2, 8 -80000d34: 93 b7 17 00 seqz a5, a5 -80000d38: b3 e7 27 01 or a5, a5, s2 -80000d3c: 17 36 00 00 auipc a2, 3 -80000d40: 13 06 06 29 addi a2, a2, 656 -80000d44: 33 07 a7 40 sub a4, a4, a0 -80000d48: 23 16 f1 02 sh a5, 44(sp) -80000d4c: 93 07 41 01 addi a5, sp, 20 -80000d50: 23 2a 81 00 sw s0, 20(sp) -80000d54: 23 2c 81 01 sw s8, 24(sp) -80000d58: 23 2e 71 01 sw s7, 28(sp) -80000d5c: 23 22 61 03 sw s6, 36(sp) -80000d60: 23 07 e1 02 sb a4, 46(sp) -80000d64: b3 86 96 02 mul a3, a3, s1 -80000d68: 93 94 24 00 slli s1, s1, 2 -80000d6c: 33 06 96 00 add a2, a2, s1 -80000d70: 23 20 f6 00 sw a5, 0(a2) -80000d74: 23 20 d1 02 sw a3, 32(sp) -80000d78: 83 26 c1 00 lw a3, 12(sp) -80000d7c: 23 24 d1 02 sw a3, 40(sp) -80000d80: 63 4e b0 05 bgtz s11, 0x80000ddc -80000d84: 63 16 0a 08 bnez s4, 0x80000e10 -80000d88: 83 20 c1 06 lw ra, 108(sp) -80000d8c: 03 24 81 06 lw s0, 104(sp) -80000d90: 83 24 41 06 lw s1, 100(sp) -80000d94: 03 29 01 06 lw s2, 96(sp) -80000d98: 83 29 c1 05 lw s3, 92(sp) -80000d9c: 03 2a 81 05 lw s4, 88(sp) -80000da0: 83 2a 41 05 lw s5, 84(sp) -80000da4: 03 2b 01 05 lw s6, 80(sp) -80000da8: 83 2b c1 04 lw s7, 76(sp) -80000dac: 03 2c 81 04 lw s8, 72(sp) -80000db0: 83 2c 41 04 lw s9, 68(sp) -80000db4: 03 2d 01 04 lw s10, 64(sp) -80000db8: 83 2d c1 03 lw s11, 60(sp) -80000dbc: 13 01 01 07 addi sp, sp, 112 -80000dc0: 67 80 00 00 ret -80000dc4: 93 87 06 00 mv a5, a3 -80000dc8: e3 c4 f4 f0 blt s1, a5, 0x80000cd0 -80000dcc: 6f f0 df fb j 0x80000d88 -80000dd0: 23 26 01 00 sw zero, 12(sp) -80000dd4: 13 0b 10 00 li s6, 1 -80000dd8: 6f f0 9f f2 j 0x80000d00 -80000ddc: 93 87 0d 00 mv a5, s11 -80000de0: 63 d4 bc 01 bge s9, s11, 0x80000de8 -80000de4: 93 87 0c 00 mv a5, s9 -80000de8: 17 07 00 00 auipc a4, 0 -80000dec: 13 07 c7 e3 addi a4, a4, -452 -80000df0: 0b 90 e7 00 vx_wspawn a5, a4 -80000df4: 93 07 f0 ff li a5, -1 -80000df8: 0b 80 07 00 vx_tmc a5 -80000dfc: ef f0 9f c4 jal 0x80000a44 -80000e00: 13 05 10 00 li a0, 1 -80000e04: 0b 00 05 00 vx_tmc a0 -80000e08: ef f0 9f af jal 0x80000900 -80000e0c: e3 0e 0a f6 beqz s4, 0x80000d88 -80000e10: b3 8d ad 03 mul s11, s11, s10 -80000e14: 03 27 01 02 lw a4, 32(sp) -80000e18: 93 07 10 00 li a5, 1 -80000e1c: b3 97 47 01 sll a5, a5, s4 -80000e20: 93 87 f7 ff addi a5, a5, -1 -80000e24: 33 07 b7 01 add a4, a4, s11 -80000e28: 23 20 e1 02 sw a4, 32(sp) -80000e2c: 0b 80 07 00 vx_tmc a5 -80000e30: ef f0 1f d7 jal 0x80000ba0 -80000e34: 13 05 10 00 li a0, 1 -80000e38: 0b 00 05 00 vx_tmc a0 -80000e3c: 6f f0 df f4 j 0x80000d88 - -80000e40 : -80000e40: f3 27 20 cc csrr a5, cid -80000e44: 37 47 00 ff lui a4, 1044484 -80000e48: 13 07 07 04 addi a4, a4, 64 -80000e4c: 93 97 87 00 slli a5, a5, 8 -80000e50: b3 87 e7 00 add a5, a5, a4 -80000e54: 73 27 00 b0 csrr a4, mcycle -80000e58: 23 a0 e7 00 sw a4, 0(a5) -80000e5c: 73 27 10 b0 csrr a4, 2817 -80000e60: 23 a2 e7 00 sw a4, 4(a5) -80000e64: 73 27 20 b0 csrr a4, minstret -80000e68: 23 a4 e7 00 sw a4, 8(a5) -80000e6c: 73 27 30 b0 csrr a4, mhpmcounter3 -80000e70: 23 a6 e7 00 sw a4, 12(a5) -80000e74: 73 27 40 b0 csrr a4, mhpmcounter4 -80000e78: 23 a8 e7 00 sw a4, 16(a5) -80000e7c: 73 27 50 b0 csrr a4, mhpmcounter5 -80000e80: 23 aa e7 00 sw a4, 20(a5) -80000e84: 73 27 60 b0 csrr a4, mhpmcounter6 -80000e88: 23 ac e7 00 sw a4, 24(a5) -80000e8c: 73 27 70 b0 csrr a4, mhpmcounter7 -80000e90: 23 ae e7 00 sw a4, 28(a5) -80000e94: 73 27 80 b0 csrr a4, mhpmcounter8 -80000e98: 23 a0 e7 02 sw a4, 32(a5) -80000e9c: 73 27 90 b0 csrr a4, mhpmcounter9 -80000ea0: 23 a2 e7 02 sw a4, 36(a5) -80000ea4: 73 27 a0 b0 csrr a4, mhpmcounter10 -80000ea8: 23 a4 e7 02 sw a4, 40(a5) -80000eac: 73 27 b0 b0 csrr a4, mhpmcounter11 -80000eb0: 23 a6 e7 02 sw a4, 44(a5) -80000eb4: 73 27 c0 b0 csrr a4, mhpmcounter12 -80000eb8: 23 a8 e7 02 sw a4, 48(a5) -80000ebc: 73 27 d0 b0 csrr a4, mhpmcounter13 -80000ec0: 23 aa e7 02 sw a4, 52(a5) -80000ec4: 73 27 e0 b0 csrr a4, mhpmcounter14 -80000ec8: 23 ac e7 02 sw a4, 56(a5) -80000ecc: 73 27 f0 b0 csrr a4, mhpmcounter15 -80000ed0: 23 ae e7 02 sw a4, 60(a5) -80000ed4: 73 27 00 b1 csrr a4, mhpmcounter16 -80000ed8: 23 a0 e7 04 sw a4, 64(a5) -80000edc: 73 27 10 b1 csrr a4, mhpmcounter17 -80000ee0: 23 a2 e7 04 sw a4, 68(a5) -80000ee4: 73 27 20 b1 csrr a4, mhpmcounter18 -80000ee8: 23 a4 e7 04 sw a4, 72(a5) -80000eec: 73 27 30 b1 csrr a4, mhpmcounter19 -80000ef0: 23 a6 e7 04 sw a4, 76(a5) -80000ef4: 73 27 40 b1 csrr a4, mhpmcounter20 -80000ef8: 23 a8 e7 04 sw a4, 80(a5) -80000efc: 73 27 50 b1 csrr a4, mhpmcounter21 -80000f00: 23 aa e7 04 sw a4, 84(a5) -80000f04: 73 27 60 b1 csrr a4, mhpmcounter22 -80000f08: 23 ac e7 04 sw a4, 88(a5) -80000f0c: 73 27 70 b1 csrr a4, mhpmcounter23 -80000f10: 23 ae e7 04 sw a4, 92(a5) -80000f14: 73 27 80 b1 csrr a4, mhpmcounter24 -80000f18: 23 a0 e7 06 sw a4, 96(a5) -80000f1c: 73 27 90 b1 csrr a4, mhpmcounter25 -80000f20: 23 a2 e7 06 sw a4, 100(a5) -80000f24: 73 27 a0 b1 csrr a4, mhpmcounter26 -80000f28: 23 a4 e7 06 sw a4, 104(a5) -80000f2c: 73 27 b0 b1 csrr a4, mhpmcounter27 -80000f30: 23 a6 e7 06 sw a4, 108(a5) -80000f34: 73 27 c0 b1 csrr a4, mhpmcounter28 -80000f38: 23 a8 e7 06 sw a4, 112(a5) -80000f3c: 73 27 d0 b1 csrr a4, mhpmcounter29 -80000f40: 23 aa e7 06 sw a4, 116(a5) -80000f44: 73 27 e0 b1 csrr a4, mhpmcounter30 -80000f48: 23 ac e7 06 sw a4, 120(a5) -80000f4c: 73 27 f0 b1 csrr a4, mhpmcounter31 -80000f50: 23 ae e7 06 sw a4, 124(a5) -80000f54: 73 27 00 b8 csrr a4, mcycleh -80000f58: 23 a0 e7 08 sw a4, 128(a5) -80000f5c: 73 27 10 b8 csrr a4, 2945 -80000f60: 23 a2 e7 08 sw a4, 132(a5) -80000f64: 73 27 20 b8 csrr a4, minstreth -80000f68: 23 a4 e7 08 sw a4, 136(a5) -80000f6c: 73 27 30 b8 csrr a4, mhpmcounter3h -80000f70: 23 a6 e7 08 sw a4, 140(a5) -80000f74: 73 27 40 b8 csrr a4, mhpmcounter4h -80000f78: 23 a8 e7 08 sw a4, 144(a5) -80000f7c: 73 27 50 b8 csrr a4, mhpmcounter5h -80000f80: 23 aa e7 08 sw a4, 148(a5) -80000f84: 73 27 60 b8 csrr a4, mhpmcounter6h -80000f88: 23 ac e7 08 sw a4, 152(a5) -80000f8c: 73 27 70 b8 csrr a4, mhpmcounter7h -80000f90: 23 ae e7 08 sw a4, 156(a5) -80000f94: 73 27 80 b8 csrr a4, mhpmcounter8h -80000f98: 23 a0 e7 0a sw a4, 160(a5) -80000f9c: 73 27 90 b8 csrr a4, mhpmcounter9h -80000fa0: 23 a2 e7 0a sw a4, 164(a5) -80000fa4: 73 27 a0 b8 csrr a4, mhpmcounter10h -80000fa8: 23 a4 e7 0a sw a4, 168(a5) -80000fac: 73 27 b0 b8 csrr a4, mhpmcounter11h -80000fb0: 23 a6 e7 0a sw a4, 172(a5) -80000fb4: 73 27 c0 b8 csrr a4, mhpmcounter12h -80000fb8: 23 a8 e7 0a sw a4, 176(a5) -80000fbc: 73 27 d0 b8 csrr a4, mhpmcounter13h -80000fc0: 23 aa e7 0a sw a4, 180(a5) -80000fc4: 73 27 e0 b8 csrr a4, mhpmcounter14h -80000fc8: 23 ac e7 0a sw a4, 184(a5) -80000fcc: 73 27 f0 b8 csrr a4, mhpmcounter15h -80000fd0: 23 ae e7 0a sw a4, 188(a5) -80000fd4: 73 27 00 b9 csrr a4, mhpmcounter16h -80000fd8: 23 a0 e7 0c sw a4, 192(a5) -80000fdc: 73 27 10 b9 csrr a4, mhpmcounter17h -80000fe0: 23 a2 e7 0c sw a4, 196(a5) -80000fe4: 73 27 20 b9 csrr a4, mhpmcounter18h -80000fe8: 23 a4 e7 0c sw a4, 200(a5) -80000fec: 73 27 30 b9 csrr a4, mhpmcounter19h -80000ff0: 23 a6 e7 0c sw a4, 204(a5) -80000ff4: 73 27 40 b9 csrr a4, mhpmcounter20h -80000ff8: 23 a8 e7 0c sw a4, 208(a5) -80000ffc: 73 27 50 b9 csrr a4, mhpmcounter21h -80001000: 23 aa e7 0c sw a4, 212(a5) -80001004: 73 27 60 b9 csrr a4, mhpmcounter22h -80001008: 23 ac e7 0c sw a4, 216(a5) -8000100c: 73 27 70 b9 csrr a4, mhpmcounter23h -80001010: 23 ae e7 0c sw a4, 220(a5) -80001014: 73 27 80 b9 csrr a4, mhpmcounter24h -80001018: 23 a0 e7 0e sw a4, 224(a5) -8000101c: 73 27 90 b9 csrr a4, mhpmcounter25h -80001020: 23 a2 e7 0e sw a4, 228(a5) -80001024: 73 27 a0 b9 csrr a4, mhpmcounter26h -80001028: 23 a4 e7 0e sw a4, 232(a5) -8000102c: 73 27 b0 b9 csrr a4, mhpmcounter27h -80001030: 23 a6 e7 0e sw a4, 236(a5) -80001034: 73 27 c0 b9 csrr a4, mhpmcounter28h -80001038: 23 a8 e7 0e sw a4, 240(a5) -8000103c: 73 27 d0 b9 csrr a4, mhpmcounter29h -80001040: 23 aa e7 0e sw a4, 244(a5) -80001044: 73 27 e0 b9 csrr a4, mhpmcounter30h -80001048: 23 ac e7 0e sw a4, 248(a5) -8000104c: 73 27 f0 b9 csrr a4, mhpmcounter31h -80001050: 23 ae e7 0e sw a4, 252(a5) -80001054: 67 80 00 00 ret - -80001058 : -80001058: d3 07 05 e0 fmv.x.w a5, fa0 -8000105c: b7 16 49 3f lui a3, 259217 -80001060: 93 86 86 fd addi a3, a3, -40 -80001064: 13 97 17 00 slli a4, a5, 1 -80001068: 13 57 17 00 srli a4, a4, 1 -8000106c: 63 fc e6 04 bgeu a3, a4, 0x800010c4 -80001070: b7 06 80 7f lui a3, 522240 -80001074: 63 66 d7 00 bltu a4, a3, 0x80001080 -80001078: 53 75 a5 08 fsub.s fa0, fa0, fa0 -8000107c: 67 80 00 00 ret -80001080: 13 01 01 fe addi sp, sp, -32 -80001084: 13 05 81 00 addi a0, sp, 8 -80001088: 23 2e 11 00 sw ra, 28(sp) -8000108c: ef 00 00 11 jal 0x8000119c <__ieee754_rem_pio2f> -80001090: 13 75 35 00 andi a0, a0, 3 -80001094: 93 07 10 00 li a5, 1 -80001098: 63 0a f5 02 beq a0, a5, 0x800010cc -8000109c: 93 07 20 00 li a5, 2 -800010a0: 87 25 c1 00 flw fa1, 12(sp) -800010a4: 07 25 81 00 flw fa0, 8(sp) -800010a8: 63 02 f5 04 beq a0, a5, 0x800010ec -800010ac: 63 0c 05 02 beqz a0, 0x800010e4 -800010b0: 13 05 10 00 li a0, 1 -800010b4: ef 00 10 64 jal 0x80001ef4 <__kernel_sinf> -800010b8: 83 20 c1 01 lw ra, 28(sp) -800010bc: 13 01 01 02 addi sp, sp, 32 -800010c0: 67 80 00 00 ret -800010c4: d3 05 00 f0 fmv.w.x fa1, zero -800010c8: 6f 00 00 3f j 0x800014b8 <__kernel_cosf> -800010cc: 87 25 c1 00 flw fa1, 12(sp) -800010d0: 07 25 81 00 flw fa0, 8(sp) -800010d4: 13 05 10 00 li a0, 1 -800010d8: ef 00 d0 61 jal 0x80001ef4 <__kernel_sinf> -800010dc: 53 15 a5 20 fneg.s fa0, fa0 -800010e0: 6f f0 9f fd j 0x800010b8 -800010e4: ef 00 40 3d jal 0x800014b8 <__kernel_cosf> -800010e8: 6f f0 1f fd j 0x800010b8 -800010ec: ef 00 c0 3c jal 0x800014b8 <__kernel_cosf> -800010f0: 53 15 a5 20 fneg.s fa0, fa0 -800010f4: 6f f0 5f fc j 0x800010b8 - -800010f8 : -800010f8: d3 07 05 e0 fmv.x.w a5, fa0 -800010fc: b7 16 49 3f lui a3, 259217 -80001100: 93 86 86 fd addi a3, a3, -40 -80001104: 13 97 17 00 slli a4, a5, 1 -80001108: 13 57 17 00 srli a4, a4, 1 -8000110c: 63 fc e6 04 bgeu a3, a4, 0x80001164 -80001110: b7 06 80 7f lui a3, 522240 -80001114: 63 66 d7 00 bltu a4, a3, 0x80001120 -80001118: 53 75 a5 08 fsub.s fa0, fa0, fa0 -8000111c: 67 80 00 00 ret -80001120: 13 01 01 fe addi sp, sp, -32 -80001124: 13 05 81 00 addi a0, sp, 8 -80001128: 23 2e 11 00 sw ra, 28(sp) -8000112c: ef 00 00 07 jal 0x8000119c <__ieee754_rem_pio2f> -80001130: 13 75 35 00 andi a0, a0, 3 -80001134: 93 07 10 00 li a5, 1 -80001138: 63 0c f5 02 beq a0, a5, 0x80001170 -8000113c: 93 07 20 00 li a5, 2 -80001140: 87 25 c1 00 flw fa1, 12(sp) -80001144: 07 25 81 00 flw fa0, 8(sp) -80001148: 63 02 f5 04 beq a0, a5, 0x8000118c -8000114c: 63 0a 05 02 beqz a0, 0x80001180 -80001150: ef 00 80 36 jal 0x800014b8 <__kernel_cosf> -80001154: 53 15 a5 20 fneg.s fa0, fa0 -80001158: 83 20 c1 01 lw ra, 28(sp) -8000115c: 13 01 01 02 addi sp, sp, 32 -80001160: 67 80 00 00 ret -80001164: d3 05 00 f0 fmv.w.x fa1, zero -80001168: 13 05 00 00 li a0, 0 -8000116c: 6f 00 90 58 j 0x80001ef4 <__kernel_sinf> -80001170: 87 25 c1 00 flw fa1, 12(sp) -80001174: 07 25 81 00 flw fa0, 8(sp) -80001178: ef 00 00 34 jal 0x800014b8 <__kernel_cosf> -8000117c: 6f f0 df fd j 0x80001158 -80001180: 13 05 10 00 li a0, 1 -80001184: ef 00 10 57 jal 0x80001ef4 <__kernel_sinf> -80001188: 6f f0 1f fd j 0x80001158 -8000118c: 13 05 10 00 li a0, 1 -80001190: ef 00 50 56 jal 0x80001ef4 <__kernel_sinf> -80001194: 53 15 a5 20 fneg.s fa0, fa0 -80001198: 6f f0 1f fc j 0x80001158 - -8000119c <__ieee754_rem_pio2f>: -8000119c: 13 01 01 fd addi sp, sp, -48 -800011a0: 23 22 91 02 sw s1, 36(sp) -800011a4: d3 04 05 e0 fmv.x.w s1, fa0 -800011a8: 23 20 21 03 sw s2, 32(sp) -800011ac: 37 09 00 80 lui s2, 524288 -800011b0: 23 24 81 02 sw s0, 40(sp) -800011b4: b7 17 49 3f lui a5, 259217 -800011b8: 13 44 f9 ff not s0, s2 -800011bc: 23 2e 31 01 sw s3, 28(sp) -800011c0: 23 26 11 02 sw ra, 44(sp) -800011c4: 23 2c 41 01 sw s4, 24(sp) -800011c8: 33 74 94 00 and s0, s0, s1 -800011cc: 93 87 87 fd addi a5, a5, -40 -800011d0: 93 09 05 00 mv s3, a0 -800011d4: 63 f6 87 12 bgeu a5, s0, 0x80001300 <__ieee754_rem_pio2f+0x164> -800011d8: b7 d7 16 40 lui a5, 262509 -800011dc: 93 87 37 be addi a5, a5, -1053 -800011e0: 13 8a 04 00 mv s4, s1 -800011e4: 63 e4 87 06 bltu a5, s0, 0x8000124c <__ieee754_rem_pio2f+0xb0> -800011e8: 97 37 00 00 auipc a5, 3 -800011ec: 87 a7 87 d5 flw fa5, -680(a5) -800011f0: 13 49 09 ff xori s2, s2, -16 -800011f4: b7 17 c9 3f lui a5, 261265 -800011f8: 33 79 99 00 and s2, s2, s1 -800011fc: 93 87 07 fd addi a5, a5, -48 -80001200: 63 54 90 26 blez s1, 0x80001468 <__ieee754_rem_pio2f+0x2cc> -80001204: d3 77 f5 08 fsub.s fa5, fa0, fa5 -80001208: 63 0e f9 10 beq s2, a5, 0x80001324 <__ieee754_rem_pio2f+0x188> -8000120c: 97 37 00 00 auipc a5, 3 -80001210: 87 a6 87 d3 flw fa3, -712(a5) -80001214: 53 f7 d7 08 fsub.s fa4, fa5, fa3 -80001218: d3 f7 e7 08 fsub.s fa5, fa5, fa4 -8000121c: d3 f7 d7 08 fsub.s fa5, fa5, fa3 -80001220: 27 a0 e9 00 fsw fa4, 0(s3) -80001224: 27 a2 f9 00 fsw fa5, 4(s3) -80001228: 13 05 10 00 li a0, 1 -8000122c: 83 20 c1 02 lw ra, 44(sp) -80001230: 03 24 81 02 lw s0, 40(sp) -80001234: 83 24 41 02 lw s1, 36(sp) -80001238: 03 29 01 02 lw s2, 32(sp) -8000123c: 83 29 c1 01 lw s3, 28(sp) -80001240: 03 2a 81 01 lw s4, 24(sp) -80001244: 13 01 01 03 addi sp, sp, 48 -80001248: 67 80 00 00 ret -8000124c: b7 17 49 43 lui a5, 275601 -80001250: 93 87 07 f8 addi a5, a5, -128 -80001254: 63 fa 87 0e bgeu a5, s0, 0x80001348 <__ieee754_rem_pio2f+0x1ac> -80001258: b7 07 80 7f lui a5, 522240 -8000125c: 63 7a f4 0a bgeu s0, a5, 0x80001310 <__ieee754_rem_pio2f+0x174> -80001260: 13 56 74 41 srai a2, s0, 23 -80001264: 13 06 a6 f7 addi a2, a2, -134 -80001268: 93 17 76 01 slli a5, a2, 23 -8000126c: 33 04 f4 40 sub s0, s0, a5 -80001270: d3 07 04 f0 fmv.w.x fa5, s0 -80001274: 17 37 00 00 auipc a4, 3 -80001278: 87 26 c7 ce flw fa3, -788(a4) -8000127c: 53 06 00 f0 fmv.w.x fa2, zero -80001280: d3 97 07 c0 fcvt.w.s a5, fa5, rtz -80001284: 93 06 30 00 li a3, 3 -80001288: 53 f7 07 d0 fcvt.s.w fa4, a5 -8000128c: d3 f7 e7 08 fsub.s fa5, fa5, fa4 -80001290: 27 22 e1 00 fsw fa4, 4(sp) -80001294: d3 f7 d7 10 fmul.s fa5, fa5, fa3 -80001298: d3 97 07 c0 fcvt.w.s a5, fa5, rtz -8000129c: 53 f7 07 d0 fcvt.s.w fa4, a5 -800012a0: d3 f7 e7 08 fsub.s fa5, fa5, fa4 -800012a4: 27 24 e1 00 fsw fa4, 8(sp) -800012a8: d3 f7 d7 10 fmul.s fa5, fa5, fa3 -800012ac: d3 a7 c7 a0 feq.s a5, fa5, fa2 -800012b0: 27 26 f1 00 fsw fa5, 12(sp) -800012b4: 63 88 07 00 beqz a5, 0x800012c4 <__ieee754_rem_pio2f+0x128> -800012b8: d3 26 c7 a0 feq.s a3, fa4, fa2 -800012bc: 93 b6 16 00 seqz a3, a3 -800012c0: 93 86 16 00 addi a3, a3, 1 -800012c4: 97 17 00 00 auipc a5, 1 -800012c8: 93 87 07 40 addi a5, a5, 1024 -800012cc: 13 07 20 00 li a4, 2 -800012d0: 93 85 09 00 mv a1, s3 -800012d4: 13 05 41 00 addi a0, sp, 4 -800012d8: ef 00 c0 32 jal 0x80001604 <__kernel_rem_pio2f> -800012dc: e3 58 0a f4 bgez s4, 0x8000122c <__ieee754_rem_pio2f+0x90> -800012e0: 07 a7 09 00 flw fa4, 0(s3) -800012e4: 87 a7 49 00 flw fa5, 4(s3) -800012e8: 33 05 a0 40 neg a0, a0 -800012ec: 53 17 e7 20 fneg.s fa4, fa4 -800012f0: d3 97 f7 20 fneg.s fa5, fa5 -800012f4: 27 a0 e9 00 fsw fa4, 0(s3) -800012f8: 27 a2 f9 00 fsw fa5, 4(s3) -800012fc: 6f f0 1f f3 j 0x8000122c <__ieee754_rem_pio2f+0x90> -80001300: 27 a0 a9 00 fsw fa0, 0(s3) -80001304: 23 22 05 00 sw zero, 4(a0) -80001308: 13 05 00 00 li a0, 0 -8000130c: 6f f0 1f f2 j 0x8000122c <__ieee754_rem_pio2f+0x90> -80001310: d3 77 a5 08 fsub.s fa5, fa0, fa0 -80001314: 27 22 f5 00 fsw fa5, 4(a0) -80001318: 27 20 f5 00 fsw fa5, 0(a0) -8000131c: 13 05 00 00 li a0, 0 -80001320: 6f f0 df f0 j 0x8000122c <__ieee754_rem_pio2f+0x90> -80001324: 97 37 00 00 auipc a5, 3 -80001328: 07 a7 47 c2 flw fa4, -988(a5) -8000132c: d3 f7 e7 08 fsub.s fa5, fa5, fa4 -80001330: 97 37 00 00 auipc a5, 3 -80001334: 87 a6 c7 c1 flw fa3, -996(a5) -80001338: 53 f7 d7 08 fsub.s fa4, fa5, fa3 -8000133c: d3 f7 e7 08 fsub.s fa5, fa5, fa4 -80001340: d3 f7 d7 08 fsub.s fa5, fa5, fa3 -80001344: 6f f0 df ed j 0x80001220 <__ieee754_rem_pio2f+0x84> -80001348: ef 00 90 45 jal 0x80001fa0 -8000134c: 97 37 00 00 auipc a5, 3 -80001350: 87 a6 47 c0 flw fa3, -1020(a5) -80001354: 97 37 00 00 auipc a5, 3 -80001358: 07 a6 07 c0 flw fa2, -1024(a5) -8000135c: c3 76 d5 60 fmadd.s fa3, fa0, fa3, fa2 -80001360: 97 37 00 00 auipc a5, 3 -80001364: 87 a7 07 be flw fa5, -1056(a5) -80001368: 97 37 00 00 auipc a5, 3 -8000136c: 07 a7 c7 bd flw fa4, -1060(a5) -80001370: 93 07 f0 01 li a5, 31 -80001374: 53 95 06 c0 fcvt.w.s a0, fa3, rtz -80001378: d3 76 05 d0 fcvt.s.w fa3, a0 -8000137c: cb f7 f6 50 fnmsub.s fa5, fa3, fa5, fa0 -80001380: 53 f7 e6 10 fmul.s fa4, fa3, fa4 -80001384: 63 c0 a7 06 blt a5, a0, 0x800013e4 <__ieee754_rem_pio2f+0x248> -80001388: 13 07 f5 ff addi a4, a0, -1 -8000138c: 13 17 27 00 slli a4, a4, 2 -80001390: 97 17 00 00 auipc a5, 1 -80001394: 93 87 47 2b addi a5, a5, 692 -80001398: b3 87 e7 00 add a5, a5, a4 -8000139c: 83 a7 07 00 lw a5, 0(a5) -800013a0: 13 49 09 f0 xori s2, s2, -256 -800013a4: 33 79 99 00 and s2, s2, s1 -800013a8: 63 0e f9 02 beq s2, a5, 0x800013e4 <__ieee754_rem_pio2f+0x248> -800013ac: d3 f6 e7 08 fsub.s fa3, fa5, fa4 -800013b0: d3 87 06 e0 fmv.x.w a5, fa3 -800013b4: d3 86 07 f0 fmv.w.x fa3, a5 -800013b8: 23 a0 f9 00 sw a5, 0(s3) -800013bc: d3 f7 d7 08 fsub.s fa5, fa5, fa3 -800013c0: d3 f7 e7 08 fsub.s fa5, fa5, fa4 -800013c4: 27 a2 f9 00 fsw fa5, 4(s3) -800013c8: e3 52 0a e6 bgez s4, 0x8000122c <__ieee754_rem_pio2f+0x90> -800013cc: 53 97 d6 20 fneg.s fa4, fa3 -800013d0: d3 97 f7 20 fneg.s fa5, fa5 -800013d4: 33 05 a0 40 neg a0, a0 -800013d8: 27 a0 e9 00 fsw fa4, 0(s3) -800013dc: 27 a2 f9 00 fsw fa5, 4(s3) -800013e0: 6f f0 df e4 j 0x8000122c <__ieee754_rem_pio2f+0x90> -800013e4: 53 f6 e7 08 fsub.s fa2, fa5, fa4 -800013e8: 13 54 74 41 srai s0, s0, 23 -800013ec: 93 06 80 00 li a3, 8 -800013f0: d3 07 06 e0 fmv.x.w a5, fa2 -800013f4: 13 d7 77 01 srli a4, a5, 23 -800013f8: 13 77 f7 0f andi a4, a4, 255 -800013fc: 33 07 e4 40 sub a4, s0, a4 -80001400: e3 da e6 fa bge a3, a4, 0x800013b4 <__ieee754_rem_pio2f+0x218> -80001404: 97 37 00 00 auipc a5, 3 -80001408: 87 a5 47 b4 flw fa1, -1212(a5) -8000140c: 4b f6 b6 78 fnmsub.s fa2, fa3, fa1, fa5 -80001410: 97 37 00 00 auipc a5, 3 -80001414: 07 a7 c7 b3 flw fa4, -1220(a5) -80001418: 93 06 90 01 li a3, 25 -8000141c: 53 f5 c7 08 fsub.s fa0, fa5, fa2 -80001420: d3 07 c6 20 fmv.s fa5, fa2 -80001424: cb f5 b6 50 fnmsub.s fa1, fa3, fa1, fa0 -80001428: 47 f7 e6 58 fmsub.s fa4, fa3, fa4, fa1 -8000142c: d3 75 e6 08 fsub.s fa1, fa2, fa4 -80001430: d3 87 05 e0 fmv.x.w a5, fa1 -80001434: 13 d7 77 01 srli a4, a5, 23 -80001438: 13 77 f7 0f andi a4, a4, 255 -8000143c: 33 04 e4 40 sub s0, s0, a4 -80001440: e3 da 86 f6 bge a3, s0, 0x800013b4 <__ieee754_rem_pio2f+0x218> -80001444: 97 37 00 00 auipc a5, 3 -80001448: 87 a5 47 b1 flw fa1, -1260(a5) -8000144c: cb f7 b6 60 fnmsub.s fa5, fa3, fa1, fa2 -80001450: 97 37 00 00 auipc a5, 3 -80001454: 07 a7 c7 b0 flw fa4, -1268(a5) -80001458: 53 76 f6 08 fsub.s fa2, fa2, fa5 -8000145c: cb f5 b6 60 fnmsub.s fa1, fa3, fa1, fa2 -80001460: 47 f7 e6 58 fmsub.s fa4, fa3, fa4, fa1 -80001464: 6f f0 9f f4 j 0x800013ac <__ieee754_rem_pio2f+0x210> -80001468: d3 77 f5 00 fadd.s fa5, fa0, fa5 -8000146c: 63 04 f9 02 beq s2, a5, 0x80001494 <__ieee754_rem_pio2f+0x2f8> -80001470: 97 37 00 00 auipc a5, 3 -80001474: 87 a6 47 ad flw fa3, -1324(a5) -80001478: 53 f7 d7 00 fadd.s fa4, fa5, fa3 -8000147c: d3 f7 e7 08 fsub.s fa5, fa5, fa4 -80001480: d3 f7 d7 00 fadd.s fa5, fa5, fa3 -80001484: 27 a0 e9 00 fsw fa4, 0(s3) -80001488: 27 a2 f9 00 fsw fa5, 4(s3) -8000148c: 13 05 f0 ff li a0, -1 -80001490: 6f f0 df d9 j 0x8000122c <__ieee754_rem_pio2f+0x90> -80001494: 97 37 00 00 auipc a5, 3 -80001498: 07 a7 47 ab flw fa4, -1356(a5) -8000149c: d3 f7 e7 00 fadd.s fa5, fa5, fa4 -800014a0: 97 37 00 00 auipc a5, 3 -800014a4: 87 a6 c7 aa flw fa3, -1364(a5) -800014a8: 53 f7 d7 00 fadd.s fa4, fa5, fa3 -800014ac: d3 f7 e7 08 fsub.s fa5, fa5, fa4 -800014b0: d3 f7 d7 00 fadd.s fa5, fa5, fa3 -800014b4: 6f f0 1f fd j 0x80001484 <__ieee754_rem_pio2f+0x2e8> - -800014b8 <__kernel_cosf>: -800014b8: d3 07 05 e0 fmv.x.w a5, fa0 -800014bc: b7 06 00 32 lui a3, 204800 -800014c0: 13 97 17 00 slli a4, a5, 1 -800014c4: 13 57 17 00 srli a4, a4, 1 -800014c8: 63 70 d7 08 bgeu a4, a3, 0x80001548 <__kernel_cosf+0x90> -800014cc: 53 17 05 c0 fcvt.w.s a4, fa0, rtz -800014d0: 63 04 07 12 beqz a4, 0x800015f8 <__kernel_cosf+0x140> -800014d4: 53 77 a5 10 fmul.s fa4, fa0, fa0 -800014d8: 17 37 00 00 auipc a4, 3 -800014dc: 87 26 c7 a9 flw fa3, -1380(a4) -800014e0: 17 37 00 00 auipc a4, 3 -800014e4: 87 27 07 a9 flw fa5, -1392(a4) -800014e8: 17 37 00 00 auipc a4, 3 -800014ec: 07 20 07 a9 flw ft0, -1392(a4) -800014f0: 17 37 00 00 auipc a4, 3 -800014f4: 07 25 c7 a8 flw fa0, -1396(a4) -800014f8: c3 77 f7 68 fmadd.s fa5, fa4, fa5, fa3 -800014fc: 17 37 00 00 auipc a4, 3 -80001500: 07 26 47 a8 flw fa2, -1404(a4) -80001504: 17 37 00 00 auipc a4, 3 -80001508: 87 26 07 a8 flw fa3, -1408(a4) -8000150c: c3 f7 e7 00 fmadd.s fa5, fa5, fa4, ft0 -80001510: c3 77 f7 50 fmadd.s fa5, fa4, fa5, fa0 -80001514: c3 77 f7 60 fmadd.s fa5, fa4, fa5, fa2 -80001518: c3 77 f7 68 fmadd.s fa5, fa4, fa5, fa3 -8000151c: d3 77 f7 10 fmul.s fa5, fa4, fa5 -80001520: d3 86 07 f0 fmv.w.x fa3, a5 -80001524: 97 37 00 00 auipc a5, 3 -80001528: 07 a5 87 a4 flw fa0, -1464(a5) -8000152c: d3 f5 b6 10 fmul.s fa1, fa3, fa1 -80001530: 97 37 00 00 auipc a5, 3 -80001534: 87 a6 47 a2 flw fa3, -1500(a5) -80001538: c7 77 f7 58 fmsub.s fa5, fa4, fa5, fa1 -8000153c: c7 77 d7 78 fmsub.s fa5, fa4, fa3, fa5 -80001540: 53 75 f5 08 fsub.s fa0, fa0, fa5 -80001544: 67 80 00 00 ret -80001548: 53 77 a5 10 fmul.s fa4, fa0, fa0 -8000154c: 97 36 00 00 auipc a3, 3 -80001550: 87 a6 86 a2 flw fa3, -1496(a3) -80001554: 97 36 00 00 auipc a3, 3 -80001558: 87 a7 c6 a1 flw fa5, -1508(a3) -8000155c: 97 36 00 00 auipc a3, 3 -80001560: 07 a0 c6 a1 flw ft0, -1508(a3) -80001564: 97 36 00 00 auipc a3, 3 -80001568: 07 a5 86 a1 flw fa0, -1512(a3) -8000156c: c3 77 f7 68 fmadd.s fa5, fa4, fa5, fa3 -80001570: 97 36 00 00 auipc a3, 3 -80001574: 07 a6 06 a1 flw fa2, -1520(a3) -80001578: 97 36 00 00 auipc a3, 3 -8000157c: 87 a6 c6 a0 flw fa3, -1524(a3) -80001580: b7 a6 99 3e lui a3, 256410 -80001584: 93 86 96 99 addi a3, a3, -1639 -80001588: c3 f7 e7 00 fmadd.s fa5, fa5, fa4, ft0 -8000158c: c3 f7 e7 50 fmadd.s fa5, fa5, fa4, fa0 -80001590: c3 f7 e7 60 fmadd.s fa5, fa5, fa4, fa2 -80001594: c3 f7 e7 68 fmadd.s fa5, fa5, fa4, fa3 -80001598: d3 f7 e7 10 fmul.s fa5, fa5, fa4 -8000159c: e3 f2 e6 f8 bgeu a3, a4, 0x80001520 <__kernel_cosf+0x68> -800015a0: b7 06 48 3f lui a3, 259200 -800015a4: 63 e0 e6 04 bltu a3, a4, 0x800015e4 <__kernel_cosf+0x12c> -800015a8: b7 06 00 ff lui a3, 1044480 -800015ac: 33 07 d7 00 add a4, a4, a3 -800015b0: d3 06 07 f0 fmv.w.x fa3, a4 -800015b4: 97 36 00 00 auipc a3, 3 -800015b8: 07 a5 86 9b flw fa0, -1608(a3) -800015bc: 53 75 d5 08 fsub.s fa0, fa0, fa3 -800015c0: 53 86 07 f0 fmv.w.x fa2, a5 -800015c4: d3 75 b6 10 fmul.s fa1, fa2, fa1 -800015c8: 97 37 00 00 auipc a5, 3 -800015cc: 07 a6 c7 98 flw fa2, -1652(a5) -800015d0: c7 76 c7 68 fmsub.s fa3, fa4, fa2, fa3 -800015d4: c7 77 f7 58 fmsub.s fa5, fa4, fa5, fa1 -800015d8: d3 f7 f6 08 fsub.s fa5, fa3, fa5 -800015dc: 53 75 f5 08 fsub.s fa0, fa0, fa5 -800015e0: 67 80 00 00 ret -800015e4: 17 37 00 00 auipc a4, 3 -800015e8: 07 25 07 98 flw fa0, -1664(a4) -800015ec: 17 37 00 00 auipc a4, 3 -800015f0: 87 26 c7 97 flw fa3, -1668(a4) -800015f4: 6f f0 df fc j 0x800015c0 <__kernel_cosf+0x108> -800015f8: 97 37 00 00 auipc a5, 3 -800015fc: 07 a5 47 97 flw fa0, -1676(a5) -80001600: 67 80 00 00 ret - -80001604 <__kernel_rem_pio2f>: -80001604: 13 01 01 e3 addi sp, sp, -464 -80001608: 13 18 27 00 slli a6, a4, 2 -8000160c: 23 22 e1 02 sw a4, 36(sp) -80001610: 17 17 00 00 auipc a4, 1 -80001614: 13 07 87 3f addi a4, a4, 1016 -80001618: 23 24 81 1c sw s0, 456(sp) -8000161c: 23 2e 31 1b sw s3, 444(sp) -80001620: 23 26 71 1b sw s7, 428(sp) -80001624: 33 07 07 01 add a4, a4, a6 -80001628: 23 26 11 1c sw ra, 460(sp) -8000162c: 23 22 91 1c sw s1, 452(sp) -80001630: 23 20 21 1d sw s2, 448(sp) -80001634: 23 2c 41 1b sw s4, 440(sp) -80001638: 23 2a 51 1b sw s5, 436(sp) -8000163c: 23 28 61 1b sw s6, 432(sp) -80001640: 23 24 81 1b sw s8, 424(sp) -80001644: 23 22 91 1b sw s9, 420(sp) -80001648: 23 20 a1 1b sw s10, 416(sp) -8000164c: 23 2e b1 19 sw s11, 412(sp) -80001650: 27 26 81 18 fsw fs0, 396(sp) -80001654: 27 24 91 18 fsw fs1, 392(sp) -80001658: 27 22 21 19 fsw fs2, 388(sp) -8000165c: 27 20 31 19 fsw fs3, 384(sp) -80001660: 27 2e 41 17 fsw fs4, 380(sp) -80001664: 27 2c 51 17 fsw fs5, 376(sp) -80001668: 27 2a 61 17 fsw fs6, 372(sp) -8000166c: 23 2a d1 00 sw a3, 20(sp) -80001670: 23 26 c1 02 sw a2, 44(sp) -80001674: 93 08 c0 ff li a7, -4 -80001678: 23 20 b1 02 sw a1, 32(sp) -8000167c: 23 2c f1 00 sw a5, 24(sp) -80001680: 83 2b 07 00 lw s7, 0(a4) -80001684: 93 09 05 00 mv s3, a0 -80001688: 13 84 f6 ff addi s0, a3, -1 -8000168c: 63 44 16 7b blt a2, a7, 0x80001e34 <__kernel_rem_pio2f+0x830> -80001690: 93 07 d6 ff addi a5, a2, -3 -80001694: 93 d4 f7 41 srai s1, a5, 31 -80001698: 93 f4 74 00 andi s1, s1, 7 -8000169c: b3 84 f4 00 add s1, s1, a5 -800016a0: 93 d7 34 40 srai a5, s1, 3 -800016a4: 93 8c 17 00 addi s9, a5, 1 -800016a8: 23 28 f1 00 sw a5, 16(sp) -800016ac: 93 97 3c 00 slli a5, s9, 3 -800016b0: 23 24 f1 02 sw a5, 40(sp) -800016b4: 83 27 c1 02 lw a5, 44(sp) -800016b8: 83 26 81 02 lw a3, 40(sp) -800016bc: 33 87 8b 00 add a4, s7, s0 -800016c0: 33 8a d7 40 sub s4, a5, a3 -800016c4: 83 27 01 01 lw a5, 16(sp) -800016c8: b3 87 87 40 sub a5, a5, s0 -800016cc: 63 40 07 04 bltz a4, 0x8000170c <__kernel_rem_pio2f+0x108> -800016d0: 83 26 81 01 lw a3, 24(sp) -800016d4: 13 05 17 00 addi a0, a4, 1 -800016d8: 93 95 27 00 slli a1, a5, 2 -800016dc: 13 07 01 08 addi a4, sp, 128 -800016e0: b3 85 b6 00 add a1, a3, a1 -800016e4: 33 05 f5 00 add a0, a0, a5 -800016e8: d3 07 00 f0 fmv.w.x fa5, zero -800016ec: 63 c6 07 00 bltz a5, 0x800016f8 <__kernel_rem_pio2f+0xf4> -800016f0: 03 a3 05 00 lw t1, 0(a1) -800016f4: d3 77 03 d0 fcvt.s.w fa5, t1 -800016f8: 93 87 17 00 addi a5, a5, 1 -800016fc: 27 20 f7 00 fsw fa5, 0(a4) -80001700: 13 07 47 00 addi a4, a4, 4 -80001704: 93 85 45 00 addi a1, a1, 4 -80001708: e3 90 a7 fe bne a5, a0, 0x800016e8 <__kernel_rem_pio2f+0xe4> -8000170c: 63 c2 0b 06 bltz s7, 0x80001770 <__kernel_rem_pio2f+0x16c> -80001710: 93 17 24 00 slli a5, s0, 2 -80001714: 13 07 01 08 addi a4, sp, 128 -80001718: 93 85 47 00 addi a1, a5, 4 -8000171c: 33 05 f7 00 add a0, a4, a5 -80001720: 83 27 41 01 lw a5, 20(sp) -80001724: 13 0e 01 12 addi t3, sp, 288 -80001728: 13 03 04 00 mv t1, s0 -8000172c: b3 8e fb 00 add t4, s7, a5 -80001730: b3 85 35 01 add a1, a1, s3 -80001734: d3 07 00 f0 fmv.w.x fa5, zero -80001738: 13 07 05 00 mv a4, a0 -8000173c: 93 87 09 00 mv a5, s3 -80001740: 63 4e 04 00 bltz s0, 0x8000175c <__kernel_rem_pio2f+0x158> -80001744: 87 a6 07 00 flw fa3, 0(a5) -80001748: 07 27 07 00 flw fa4, 0(a4) -8000174c: 93 87 47 00 addi a5, a5, 4 -80001750: 13 07 c7 ff addi a4, a4, -4 -80001754: c3 f7 e6 78 fmadd.s fa5, fa3, fa4, fa5 -80001758: e3 96 b7 fe bne a5, a1, 0x80001744 <__kernel_rem_pio2f+0x140> -8000175c: 27 20 fe 00 fsw fa5, 0(t3) -80001760: 13 03 13 00 addi t1, t1, 1 -80001764: 13 0e 4e 00 addi t3, t3, 4 -80001768: 13 05 45 00 addi a0, a0, 4 -8000176c: e3 14 d3 fd bne t1, t4, 0x80001734 <__kernel_rem_pio2f+0x130> -80001770: 03 27 41 01 lw a4, 20(sp) -80001774: 93 97 2b 00 slli a5, s7, 2 -80001778: 93 0a 01 03 addi s5, sp, 48 -8000177c: 13 8b 87 ff addi s6, a5, -8 -80001780: 13 1d 27 00 slli s10, a4, 2 -80001784: 13 07 c1 02 addi a4, sp, 44 -80001788: b3 04 f7 00 add s1, a4, a5 -8000178c: b3 87 6a 01 add a5, s5, s6 -80001790: 23 2e f1 00 sw a5, 28(sp) -80001794: 97 27 00 00 auipc a5, 2 -80001798: 87 a4 87 7f flw fs1, 2040(a5) -8000179c: 97 27 00 00 auipc a5, 2 -800017a0: 07 a4 47 7f flw fs0, 2036(a5) -800017a4: 97 27 00 00 auipc a5, 2 -800017a8: 07 a9 87 7c flw fs2, 1992(a5) -800017ac: b7 07 00 40 lui a5, 262144 -800017b0: 93 87 f7 ff addi a5, a5, -1 -800017b4: 13 89 fb ff addi s2, s7, -1 -800017b8: 23 26 f1 00 sw a5, 12(sp) -800017bc: 13 19 29 00 slli s2, s2, 2 -800017c0: 97 27 00 00 auipc a5, 2 -800017c4: 87 aa 87 7c flw fs5, 1992(a5) -800017c8: 97 27 00 00 auipc a5, 2 -800017cc: 07 aa 87 79 flw fs4, 1944(a5) -800017d0: 97 27 00 00 auipc a5, 2 -800017d4: 87 a9 47 78 flw fs3, 1924(a5) -800017d8: 93 07 09 14 addi a5, s2, 320 -800017dc: 33 8d a9 01 add s10, s3, s10 -800017e0: 13 8b 0b 00 mv s6, s7 -800017e4: 33 89 57 01 add s2, a5, s5 -800017e8: 93 1d 2b 00 slli s11, s6, 2 -800017ec: 93 87 0d 14 addi a5, s11, 320 -800017f0: 13 07 01 03 addi a4, sp, 48 -800017f4: b3 87 e7 00 add a5, a5, a4 -800017f8: 07 a5 07 fb flw fa0, -80(a5) -800017fc: 63 56 60 05 blez s6, 0x80001848 <__kernel_rem_pio2f+0x244> -80001800: 83 27 c1 00 lw a5, 12(sp) -80001804: 13 0f 01 12 addi t5, sp, 288 -80001808: 13 85 0a 00 mv a0, s5 -8000180c: b3 07 fb 00 add a5, s6, a5 -80001810: 93 97 27 00 slli a5, a5, 2 -80001814: b3 07 ff 00 add a5, t5, a5 -80001818: d3 77 55 11 fmul.s fa5, fa0, fs5 -8000181c: 87 a6 07 00 flw fa3, 0(a5) -80001820: 13 05 45 00 addi a0, a0, 4 -80001824: 13 8e 07 00 mv t3, a5 -80001828: 93 87 c7 ff addi a5, a5, -4 -8000182c: d3 9e 07 c0 fcvt.w.s t4, fa5, rtz -80001830: d3 f7 0e d0 fcvt.s.w fa5, t4 -80001834: 4b f7 47 51 fnmsub.s fa4, fa5, fs4, fa0 -80001838: 53 f5 d7 00 fadd.s fa0, fa5, fa3 -8000183c: d3 1e 07 c0 fcvt.w.s t4, fa4, rtz -80001840: 23 2e d5 ff sw t4, -4(a0) -80001844: e3 1a cf fd bne t5, t3, 0x80001818 <__kernel_rem_pio2f+0x214> -80001848: 13 05 0a 00 mv a0, s4 -8000184c: ef 00 90 02 jal 0x80002074 -80001850: 53 0b a5 20 fmv.s fs6, fa0 -80001854: 53 75 95 10 fmul.s fa0, fa0, fs1 -80001858: ef 00 00 75 jal 0x80001fa8 -8000185c: cb 77 85 b0 fnmsub.s fa5, fa0, fs0, fs6 -80001860: d3 9c 07 c0 fcvt.w.s s9, fa5, rtz -80001864: 53 f7 0c d0 fcvt.s.w fa4, s9 -80001868: 53 fb e7 08 fsub.s fs6, fa5, fa4 -8000186c: 63 5a 40 13 blez s4, 0x800019a0 <__kernel_rem_pio2f+0x39c> -80001870: 93 07 fb ff addi a5, s6, -1 -80001874: 93 97 27 00 slli a5, a5, 2 -80001878: 93 87 07 14 addi a5, a5, 320 -8000187c: 13 07 01 03 addi a4, sp, 48 -80001880: b3 87 e7 00 add a5, a5, a4 -80001884: 03 ae 07 ec lw t3, -320(a5) -80001888: 13 05 80 00 li a0, 8 -8000188c: 33 05 45 41 sub a0, a0, s4 -80001890: 33 5f ae 40 sra t5, t3, a0 -80001894: 33 15 af 00 sll a0, t5, a0 -80001898: 33 0e ae 40 sub t3, t3, a0 -8000189c: 13 05 70 00 li a0, 7 -800018a0: 33 05 45 41 sub a0, a0, s4 -800018a4: 23 a0 c7 ed sw t3, -320(a5) -800018a8: 33 5c ae 40 sra s8, t3, a0 -800018ac: b3 8c ec 01 add s9, s9, t5 -800018b0: 63 48 80 31 bgtz s8, 0x80001bc0 <__kernel_rem_pio2f+0x5bc> -800018b4: 53 07 00 f0 fmv.w.x fa4, zero -800018b8: d3 27 eb a0 feq.s a5, fs6, fa4 -800018bc: 63 80 07 1c beqz a5, 0x80001a7c <__kernel_rem_pio2f+0x478> -800018c0: 63 d6 6b 03 bge s7, s6, 0x800018ec <__kernel_rem_pio2f+0x2e8> -800018c4: 83 27 c1 00 lw a5, 12(sp) -800018c8: 13 05 00 00 li a0, 0 -800018cc: b3 07 fb 00 add a5, s6, a5 -800018d0: 93 97 27 00 slli a5, a5, 2 -800018d4: b3 87 fa 00 add a5, s5, a5 -800018d8: 03 af 07 00 lw t5, 0(a5) -800018dc: 93 87 c7 ff addi a5, a5, -4 -800018e0: 33 65 e5 01 or a0, a0, t5 -800018e4: e3 9a 97 fe bne a5, s1, 0x800018d8 <__kernel_rem_pio2f+0x2d4> -800018e8: 63 10 05 32 bnez a0, 0x80001c08 <__kernel_rem_pio2f+0x604> -800018ec: 83 27 09 ec lw a5, -320(s2) -800018f0: 63 94 07 30 bnez a5, 0x80001bf8 <__kernel_rem_pio2f+0x5f4> -800018f4: 83 27 c1 01 lw a5, 28(sp) -800018f8: 13 05 10 00 li a0, 1 -800018fc: 03 ae 07 00 lw t3, 0(a5) -80001900: 13 05 15 00 addi a0, a0, 1 -80001904: 93 87 c7 ff addi a5, a5, -4 -80001908: e3 0a 0e fe beqz t3, 0x800018fc <__kernel_rem_pio2f+0x2f8> -8000190c: 93 07 1b 00 addi a5, s6, 1 -80001910: 93 8f 07 00 mv t6, a5 -80001914: 33 0f ab 00 add t5, s6, a0 -80001918: 03 27 01 01 lw a4, 16(sp) -8000191c: 83 26 81 01 lw a3, 24(sp) -80001920: 33 0e f7 00 add t3, a4, a5 -80001924: 03 27 41 01 lw a4, 20(sp) -80001928: 13 1e 2e 00 slli t3, t3, 2 -8000192c: 33 8e c6 01 add t3, a3, t3 -80001930: 33 07 67 01 add a4, a4, s6 -80001934: 13 17 27 00 slli a4, a4, 2 -80001938: 93 06 01 08 addi a3, sp, 128 -8000193c: 93 97 27 00 slli a5, a5, 2 -80001940: 33 85 e6 00 add a0, a3, a4 -80001944: 13 07 01 12 addi a4, sp, 288 -80001948: b3 0e f7 00 add t4, a4, a5 -8000194c: 83 27 0e 00 lw a5, 0(t3) -80001950: d3 f7 07 d0 fcvt.s.w fa5, a5 -80001954: 27 20 f5 00 fsw fa5, 0(a0) -80001958: d3 07 00 f0 fmv.w.x fa5, zero -8000195c: 63 42 04 02 bltz s0, 0x80001980 <__kernel_rem_pio2f+0x37c> -80001960: 13 07 05 00 mv a4, a0 -80001964: 93 87 09 00 mv a5, s3 -80001968: 87 a6 07 00 flw fa3, 0(a5) -8000196c: 07 27 07 00 flw fa4, 0(a4) -80001970: 93 87 47 00 addi a5, a5, 4 -80001974: 13 07 c7 ff addi a4, a4, -4 -80001978: c3 f7 e6 78 fmadd.s fa5, fa3, fa4, fa5 -8000197c: e3 96 a7 ff bne a5, s10, 0x80001968 <__kernel_rem_pio2f+0x364> -80001980: 27 a0 fe 00 fsw fa5, 0(t4) -80001984: 93 8f 1f 00 addi t6, t6, 1 -80001988: 13 0e 4e 00 addi t3, t3, 4 -8000198c: 13 05 45 00 addi a0, a0, 4 -80001990: 93 8e 4e 00 addi t4, t4, 4 -80001994: e3 5c ff fb bge t5, t6, 0x8000194c <__kernel_rem_pio2f+0x348> -80001998: 13 0b 0f 00 mv s6, t5 -8000199c: 6f f0 df e4 j 0x800017e8 <__kernel_rem_pio2f+0x1e4> -800019a0: 63 10 0a 20 bnez s4, 0x80001ba0 <__kernel_rem_pio2f+0x59c> -800019a4: 93 07 fb ff addi a5, s6, -1 -800019a8: 93 97 27 00 slli a5, a5, 2 -800019ac: 93 87 07 14 addi a5, a5, 320 -800019b0: 13 07 01 03 addi a4, sp, 48 -800019b4: b3 87 e7 00 add a5, a5, a4 -800019b8: 03 ae 07 ec lw t3, -320(a5) -800019bc: 13 5c 7e 40 srai s8, t3, 7 -800019c0: e3 5a 80 ef blez s8, 0x800018b4 <__kernel_rem_pio2f+0x2b0> -800019c4: 93 8c 1c 00 addi s9, s9, 1 -800019c8: 63 5c 60 4d blez s6, 0x80001ea0 <__kernel_rem_pio2f+0x89c> -800019cc: 93 87 0a 00 mv a5, s5 -800019d0: 13 0f 00 00 li t5, 0 -800019d4: 93 0f 00 00 li t6, 0 -800019d8: 93 03 f0 0f li t2, 255 -800019dc: 93 02 00 10 li t0, 256 -800019e0: 03 a5 07 00 lw a0, 0(a5) -800019e4: 63 90 0f 02 bnez t6, 0x80001a04 <__kernel_rem_pio2f+0x400> -800019e8: b3 80 a2 40 sub ra, t0, a0 -800019ec: 63 02 05 02 beqz a0, 0x80001a10 <__kernel_rem_pio2f+0x40c> -800019f0: 23 a0 17 00 sw ra, 0(a5) -800019f4: 13 0f 1f 00 addi t5, t5, 1 -800019f8: 93 87 47 00 addi a5, a5, 4 -800019fc: 63 58 6f 43 bge t5, s6, 0x80001e2c <__kernel_rem_pio2f+0x828> -80001a00: 03 a5 07 00 lw a0, 0(a5) -80001a04: 33 85 a3 40 sub a0, t2, a0 -80001a08: 93 0f 10 00 li t6, 1 -80001a0c: 23 a0 a7 00 sw a0, 0(a5) -80001a10: 13 0f 1f 00 addi t5, t5, 1 -80001a14: 93 87 47 00 addi a5, a5, 4 -80001a18: e3 44 6f fd blt t5, s6, 0x800019e0 <__kernel_rem_pio2f+0x3dc> -80001a1c: 63 5a 40 03 blez s4, 0x80001a50 <__kernel_rem_pio2f+0x44c> -80001a20: 93 07 10 00 li a5, 1 -80001a24: 63 08 fa 1a beq s4, a5, 0x80001bd4 <__kernel_rem_pio2f+0x5d0> -80001a28: 93 07 20 00 li a5, 2 -80001a2c: 63 12 fa 02 bne s4, a5, 0x80001a50 <__kernel_rem_pio2f+0x44c> -80001a30: 93 07 fb ff addi a5, s6, -1 -80001a34: 93 97 27 00 slli a5, a5, 2 -80001a38: 93 87 07 14 addi a5, a5, 320 -80001a3c: 13 07 01 03 addi a4, sp, 48 -80001a40: b3 87 e7 00 add a5, a5, a4 -80001a44: 03 a5 07 ec lw a0, -320(a5) -80001a48: 13 75 f5 03 andi a0, a0, 63 -80001a4c: 23 a0 a7 ec sw a0, -320(a5) -80001a50: 93 07 20 00 li a5, 2 -80001a54: e3 10 fc e6 bne s8, a5, 0x800018b4 <__kernel_rem_pio2f+0x2b0> -80001a58: 53 7b 69 09 fsub.s fs6, fs2, fs6 -80001a5c: e3 8c 0f e4 beqz t6, 0x800018b4 <__kernel_rem_pio2f+0x2b0> -80001a60: 53 05 29 21 fmv.s fa0, fs2 -80001a64: 13 05 0a 00 mv a0, s4 -80001a68: ef 00 c0 60 jal 0x80002074 -80001a6c: 53 7b ab 08 fsub.s fs6, fs6, fa0 -80001a70: 53 07 00 f0 fmv.w.x fa4, zero -80001a74: d3 27 eb a0 feq.s a5, fs6, fa4 -80001a78: e3 94 07 e4 bnez a5, 0x800018c0 <__kernel_rem_pio2f+0x2bc> -80001a7c: 83 27 81 02 lw a5, 40(sp) -80001a80: 03 27 c1 02 lw a4, 44(sp) -80001a84: 53 05 6b 21 fmv.s fa0, fs6 -80001a88: 33 85 e7 40 sub a0, a5, a4 -80001a8c: ef 00 80 5e jal 0x80002074 -80001a90: 97 27 00 00 auipc a5, 2 -80001a94: 07 a7 07 4d flw fa4, 1232(a5) -80001a98: d3 07 a7 a0 fle.s a5, fa4, fa0 -80001a9c: 63 84 07 3a beqz a5, 0x80001e44 <__kernel_rem_pio2f+0x840> -80001aa0: 97 27 00 00 auipc a5, 2 -80001aa4: 87 a6 87 4e flw fa3, 1256(a5) -80001aa8: d3 76 d5 10 fmul.s fa3, fa0, fa3 -80001aac: 13 07 01 03 addi a4, sp, 48 -80001ab0: 93 87 0d 14 addi a5, s11, 320 -80001ab4: 13 04 1b 00 addi s0, s6, 1 -80001ab8: b3 8d e7 00 add s11, a5, a4 -80001abc: 93 17 24 00 slli a5, s0, 2 -80001ac0: 93 87 07 14 addi a5, a5, 320 -80001ac4: b3 87 e7 00 add a5, a5, a4 -80001ac8: 53 97 06 c0 fcvt.w.s a4, fa3, rtz -80001acc: 13 0a 8a 00 addi s4, s4, 8 -80001ad0: d3 76 07 d0 fcvt.s.w fa3, a4 -80001ad4: 4b f7 e6 50 fnmsub.s fa4, fa3, fa4, fa0 -80001ad8: 53 97 06 c0 fcvt.w.s a4, fa3, rtz -80001adc: 53 16 07 c0 fcvt.w.s a2, fa4, rtz -80001ae0: 23 a0 cd ec sw a2, -320(s11) -80001ae4: 23 a0 e7 ec sw a4, -320(a5) -80001ae8: 53 05 29 21 fmv.s fa0, fs2 -80001aec: 13 05 0a 00 mv a0, s4 -80001af0: ef 00 40 58 jal 0x80002074 -80001af4: 53 07 a5 20 fmv.s fa4, fa0 -80001af8: 63 42 04 16 bltz s0, 0x80001c5c <__kernel_rem_pio2f+0x658> -80001afc: 13 15 24 00 slli a0, s0, 2 -80001b00: 93 07 01 12 addi a5, sp, 288 -80001b04: 33 88 a7 00 add a6, a5, a0 -80001b08: 13 07 08 00 mv a4, a6 -80001b0c: b3 87 aa 00 add a5, s5, a0 -80001b10: 97 26 00 00 auipc a3, 2 -80001b14: 87 a6 86 47 flw fa3, 1144(a3) -80001b18: 83 a5 07 00 lw a1, 0(a5) -80001b1c: 13 07 c7 ff addi a4, a4, -4 -80001b20: 13 86 07 00 mv a2, a5 -80001b24: d3 f7 05 d0 fcvt.s.w fa5, a1 -80001b28: 93 87 c7 ff addi a5, a5, -4 -80001b2c: d3 f7 e7 10 fmul.s fa5, fa5, fa4 -80001b30: 53 77 d7 10 fmul.s fa4, fa4, fa3 -80001b34: 27 22 f7 00 fsw fa5, 4(a4) -80001b38: e3 90 ca fe bne s5, a2, 0x80001b18 <__kernel_rem_pio2f+0x514> -80001b3c: 13 03 01 0d addi t1, sp, 208 -80001b40: 93 08 03 00 mv a7, t1 -80001b44: 93 05 00 00 li a1, 0 -80001b48: d3 07 00 f0 fmv.w.x fa5, zero -80001b4c: 63 cc 0b 02 bltz s7, 0x80001b84 <__kernel_rem_pio2f+0x580> -80001b50: 17 17 00 00 auipc a4, 1 -80001b54: 13 07 c7 e8 addi a4, a4, -372 -80001b58: 13 06 08 00 mv a2, a6 -80001b5c: 93 07 00 00 li a5, 0 -80001b60: 6f 00 c0 00 j 0x80001b6c <__kernel_rem_pio2f+0x568> -80001b64: 13 06 46 00 addi a2, a2, 4 -80001b68: 63 ce f5 00 blt a1, a5, 0x80001b84 <__kernel_rem_pio2f+0x580> -80001b6c: 87 26 07 00 flw fa3, 0(a4) -80001b70: 07 27 06 00 flw fa4, 0(a2) -80001b74: 93 87 17 00 addi a5, a5, 1 -80001b78: 13 07 47 00 addi a4, a4, 4 -80001b7c: c3 f7 e6 78 fmadd.s fa5, fa3, fa4, fa5 -80001b80: e3 d2 fb fe bge s7, a5, 0x80001b64 <__kernel_rem_pio2f+0x560> -80001b84: 27 a0 f8 00 fsw fa5, 0(a7) -80001b88: 93 87 15 00 addi a5, a1, 1 -80001b8c: 93 88 48 00 addi a7, a7, 4 -80001b90: 13 08 c8 ff addi a6, a6, -4 -80001b94: 63 86 85 14 beq a1, s0, 0x80001ce0 <__kernel_rem_pio2f+0x6dc> -80001b98: 93 85 07 00 mv a1, a5 -80001b9c: 6f f0 df fa j 0x80001b48 <__kernel_rem_pio2f+0x544> -80001ba0: d3 87 69 a1 fle.s a5, fs3, fs6 -80001ba4: 13 0c 00 00 li s8, 0 -80001ba8: e3 86 07 d0 beqz a5, 0x800018b4 <__kernel_rem_pio2f+0x2b0> -80001bac: 93 8c 1c 00 addi s9, s9, 1 -80001bb0: 13 0c 20 00 li s8, 2 -80001bb4: e3 4c 60 e1 bgtz s6, 0x800019cc <__kernel_rem_pio2f+0x3c8> -80001bb8: 53 7b 69 09 fsub.s fs6, fs2, fs6 -80001bbc: 6f f0 9f cf j 0x800018b4 <__kernel_rem_pio2f+0x2b0> -80001bc0: 93 8c 1c 00 addi s9, s9, 1 -80001bc4: 93 0f 00 00 li t6, 0 -80001bc8: e3 42 60 e1 bgtz s6, 0x800019cc <__kernel_rem_pio2f+0x3c8> -80001bcc: 93 07 10 00 li a5, 1 -80001bd0: e3 1c fa e4 bne s4, a5, 0x80001a28 <__kernel_rem_pio2f+0x424> -80001bd4: 93 07 fb ff addi a5, s6, -1 -80001bd8: 93 97 27 00 slli a5, a5, 2 -80001bdc: 93 87 07 14 addi a5, a5, 320 -80001be0: 13 07 01 03 addi a4, sp, 48 -80001be4: b3 87 e7 00 add a5, a5, a4 -80001be8: 03 a5 07 ec lw a0, -320(a5) -80001bec: 13 75 f5 07 andi a0, a0, 127 -80001bf0: 23 a0 a7 ec sw a0, -320(a5) -80001bf4: 6f f0 df e5 j 0x80001a50 <__kernel_rem_pio2f+0x44c> -80001bf8: 93 07 1b 00 addi a5, s6, 1 -80001bfc: 93 8f 07 00 mv t6, a5 -80001c00: 13 8f 07 00 mv t5, a5 -80001c04: 6f f0 5f d1 j 0x80001918 <__kernel_rem_pio2f+0x314> -80001c08: 13 04 fb ff addi s0, s6, -1 -80001c0c: 93 17 24 00 slli a5, s0, 2 -80001c10: 93 87 07 14 addi a5, a5, 320 -80001c14: 13 07 01 03 addi a4, sp, 48 -80001c18: b3 87 e7 00 add a5, a5, a4 -80001c1c: 83 a7 07 ec lw a5, -320(a5) -80001c20: 13 0a 8a ff addi s4, s4, -8 -80001c24: e3 92 07 ec bnez a5, 0x80001ae8 <__kernel_rem_pio2f+0x4e4> -80001c28: 93 17 2b 00 slli a5, s6, 2 -80001c2c: 93 87 87 ff addi a5, a5, -8 -80001c30: b3 87 fa 00 add a5, s5, a5 -80001c34: 03 a7 07 00 lw a4, 0(a5) -80001c38: 13 04 f4 ff addi s0, s0, -1 -80001c3c: 93 87 c7 ff addi a5, a5, -4 -80001c40: 13 0a 8a ff addi s4, s4, -8 -80001c44: e3 08 07 fe beqz a4, 0x80001c34 <__kernel_rem_pio2f+0x630> -80001c48: 53 05 29 21 fmv.s fa0, fs2 -80001c4c: 13 05 0a 00 mv a0, s4 -80001c50: ef 00 40 42 jal 0x80002074 -80001c54: 53 07 a5 20 fmv.s fa4, fa0 -80001c58: e3 52 04 ea bgez s0, 0x80001afc <__kernel_rem_pio2f+0x4f8> -80001c5c: 03 27 41 02 lw a4, 36(sp) -80001c60: 93 07 20 00 li a5, 2 -80001c64: 63 c6 e7 24 blt a5, a4, 0x80001eb0 <__kernel_rem_pio2f+0x8ac> -80001c68: 63 4e e0 24 bgtz a4, 0x80001ec4 <__kernel_rem_pio2f+0x8c0> -80001c6c: d3 07 00 f0 fmv.w.x fa5, zero -80001c70: 63 1a 07 00 bnez a4, 0x80001c84 <__kernel_rem_pio2f+0x680> -80001c74: 63 04 0c 00 beqz s8, 0x80001c7c <__kernel_rem_pio2f+0x678> -80001c78: d3 97 f7 20 fneg.s fa5, fa5 -80001c7c: 83 27 01 02 lw a5, 32(sp) -80001c80: 27 a0 f7 00 fsw fa5, 0(a5) -80001c84: 83 20 c1 1c lw ra, 460(sp) -80001c88: 03 24 81 1c lw s0, 456(sp) -80001c8c: 83 24 41 1c lw s1, 452(sp) -80001c90: 03 29 01 1c lw s2, 448(sp) -80001c94: 83 29 c1 1b lw s3, 444(sp) -80001c98: 03 2a 81 1b lw s4, 440(sp) -80001c9c: 83 2a 41 1b lw s5, 436(sp) -80001ca0: 03 2b 01 1b lw s6, 432(sp) -80001ca4: 83 2b c1 1a lw s7, 428(sp) -80001ca8: 03 2c 81 1a lw s8, 424(sp) -80001cac: 03 2d 01 1a lw s10, 416(sp) -80001cb0: 83 2d c1 19 lw s11, 412(sp) -80001cb4: 07 24 c1 18 flw fs0, 396(sp) -80001cb8: 87 24 81 18 flw fs1, 392(sp) -80001cbc: 07 29 41 18 flw fs2, 388(sp) -80001cc0: 87 29 01 18 flw fs3, 384(sp) -80001cc4: 07 2a c1 17 flw fs4, 380(sp) -80001cc8: 87 2a 81 17 flw fs5, 376(sp) -80001ccc: 07 2b 41 17 flw fs6, 372(sp) -80001cd0: 13 f5 7c 00 andi a0, s9, 7 -80001cd4: 83 2c 41 1a lw s9, 420(sp) -80001cd8: 13 01 01 1d addi sp, sp, 464 -80001cdc: 67 80 00 00 ret -80001ce0: 03 27 41 02 lw a4, 36(sp) -80001ce4: 93 07 20 00 li a5, 2 -80001ce8: 63 c6 e7 08 blt a5, a4, 0x80001d74 <__kernel_rem_pio2f+0x770> -80001cec: d3 07 00 f0 fmv.w.x fa5, zero -80001cf0: b3 07 a3 00 add a5, t1, a0 -80001cf4: 63 42 e0 02 bgtz a4, 0x80001d18 <__kernel_rem_pio2f+0x714> -80001cf8: e3 16 07 f8 bnez a4, 0x80001c84 <__kernel_rem_pio2f+0x680> -80001cfc: 07 a7 07 00 flw fa4, 0(a5) -80001d00: 13 87 07 00 mv a4, a5 -80001d04: 93 87 c7 ff addi a5, a5, -4 -80001d08: d3 f7 e7 00 fadd.s fa5, fa5, fa4 -80001d0c: e3 18 e3 fe bne t1, a4, 0x80001cfc <__kernel_rem_pio2f+0x6f8> -80001d10: e3 06 0c f6 beqz s8, 0x80001c7c <__kernel_rem_pio2f+0x678> -80001d14: 6f f0 5f f6 j 0x80001c78 <__kernel_rem_pio2f+0x674> -80001d18: 07 a7 07 00 flw fa4, 0(a5) -80001d1c: 13 87 07 00 mv a4, a5 -80001d20: 93 87 c7 ff addi a5, a5, -4 -80001d24: d3 f7 e7 00 fadd.s fa5, fa5, fa4 -80001d28: e3 18 e3 fe bne t1, a4, 0x80001d18 <__kernel_rem_pio2f+0x714> -80001d2c: 63 1a 0c 12 bnez s8, 0x80001e60 <__kernel_rem_pio2f+0x85c> -80001d30: 83 27 01 02 lw a5, 32(sp) -80001d34: 07 27 01 0d flw fa4, 208(sp) -80001d38: 27 a0 f7 00 fsw fa5, 0(a5) -80001d3c: d3 77 f7 08 fsub.s fa5, fa4, fa5 -80001d40: 63 04 04 02 beqz s0, 0x80001d68 <__kernel_rem_pio2f+0x764> -80001d44: 13 07 41 0d addi a4, sp, 212 -80001d48: 93 07 10 00 li a5, 1 -80001d4c: 07 27 07 00 flw fa4, 0(a4) -80001d50: 93 87 17 00 addi a5, a5, 1 -80001d54: 13 07 47 00 addi a4, a4, 4 -80001d58: d3 f7 e7 00 fadd.s fa5, fa5, fa4 -80001d5c: e3 58 f4 fe bge s0, a5, 0x80001d4c <__kernel_rem_pio2f+0x748> -80001d60: 63 04 0c 00 beqz s8, 0x80001d68 <__kernel_rem_pio2f+0x764> -80001d64: d3 97 f7 20 fneg.s fa5, fa5 -80001d68: 83 27 01 02 lw a5, 32(sp) -80001d6c: 27 a2 f7 00 fsw fa5, 4(a5) -80001d70: 6f f0 5f f1 j 0x80001c84 <__kernel_rem_pio2f+0x680> -80001d74: 03 27 41 02 lw a4, 36(sp) -80001d78: 93 07 30 00 li a5, 3 -80001d7c: e3 14 f7 f0 bne a4, a5, 0x80001c84 <__kernel_rem_pio2f+0x680> -80001d80: 63 0e 04 12 beqz s0, 0x80001ebc <__kernel_rem_pio2f+0x8b8> -80001d84: b3 06 a3 00 add a3, t1, a0 -80001d88: 93 07 c5 ff addi a5, a0, -4 -80001d8c: 07 a7 06 00 flw fa4, 0(a3) -80001d90: b3 07 f3 00 add a5, t1, a5 -80001d94: 13 87 07 00 mv a4, a5 -80001d98: 87 27 07 00 flw fa5, 0(a4) -80001d9c: d3 06 e7 20 fmv.s fa3, fa4 -80001da0: 13 06 07 00 mv a2, a4 -80001da4: 53 77 f7 00 fadd.s fa4, fa4, fa5 -80001da8: 13 07 c7 ff addi a4, a4, -4 -80001dac: d3 f7 e7 08 fsub.s fa5, fa5, fa4 -80001db0: 27 22 e7 00 fsw fa4, 4(a4) -80001db4: d3 f7 d7 00 fadd.s fa5, fa5, fa3 -80001db8: 27 24 f7 00 fsw fa5, 8(a4) -80001dbc: e3 1e 66 fc bne a2, t1, 0x80001d98 <__kernel_rem_pio2f+0x794> -80001dc0: 13 07 10 00 li a4, 1 -80001dc4: 63 0c e4 0e beq s0, a4, 0x80001ebc <__kernel_rem_pio2f+0x8b8> -80001dc8: 07 a7 06 00 flw fa4, 0(a3) -80001dcc: 87 a7 07 00 flw fa5, 0(a5) -80001dd0: d3 06 e7 20 fmv.s fa3, fa4 -80001dd4: 13 87 07 00 mv a4, a5 -80001dd8: 53 77 f7 00 fadd.s fa4, fa4, fa5 -80001ddc: 93 87 c7 ff addi a5, a5, -4 -80001de0: d3 f7 e7 08 fsub.s fa5, fa5, fa4 -80001de4: 27 a2 e7 00 fsw fa4, 4(a5) -80001de8: d3 f7 d7 00 fadd.s fa5, fa5, fa3 -80001dec: 27 a4 f7 00 fsw fa5, 8(a5) -80001df0: e3 1e f3 fc bne t1, a5, 0x80001dcc <__kernel_rem_pio2f+0x7c8> -80001df4: d3 07 00 f0 fmv.w.x fa5, zero -80001df8: 93 87 06 00 mv a5, a3 -80001dfc: 07 a7 07 00 flw fa4, 0(a5) -80001e00: 93 87 c7 ff addi a5, a5, -4 -80001e04: d3 f7 e7 00 fadd.s fa5, fa5, fa4 -80001e08: e3 1a f7 fe bne a4, a5, 0x80001dfc <__kernel_rem_pio2f+0x7f8> -80001e0c: 87 26 01 0d flw fa3, 208(sp) -80001e10: 07 27 41 0d flw fa4, 212(sp) -80001e14: 63 16 0c 06 bnez s8, 0x80001e80 <__kernel_rem_pio2f+0x87c> -80001e18: 83 27 01 02 lw a5, 32(sp) -80001e1c: 27 a0 d7 00 fsw fa3, 0(a5) -80001e20: 27 a2 e7 00 fsw fa4, 4(a5) -80001e24: 27 a4 f7 00 fsw fa5, 8(a5) -80001e28: 6f f0 df e5 j 0x80001c84 <__kernel_rem_pio2f+0x680> -80001e2c: 93 0f 10 00 li t6, 1 -80001e30: 6f f0 df be j 0x80001a1c <__kernel_rem_pio2f+0x418> -80001e34: 93 07 80 00 li a5, 8 -80001e38: 23 24 f1 02 sw a5, 40(sp) -80001e3c: 23 28 01 00 sw zero, 16(sp) -80001e40: 6f f0 5f 87 j 0x800016b4 <__kernel_rem_pio2f+0xb0> -80001e44: d3 17 05 c0 fcvt.w.s a5, fa0, rtz -80001e48: 13 87 0d 14 addi a4, s11, 320 -80001e4c: 93 06 01 03 addi a3, sp, 48 -80001e50: b3 0d d7 00 add s11, a4, a3 -80001e54: 13 04 0b 00 mv s0, s6 -80001e58: 23 a0 fd ec sw a5, -320(s11) -80001e5c: 6f f0 df c8 j 0x80001ae8 <__kernel_rem_pio2f+0x4e4> -80001e60: 53 97 f7 20 fneg.s fa4, fa5 -80001e64: 83 27 01 02 lw a5, 32(sp) -80001e68: 27 a0 e7 00 fsw fa4, 0(a5) -80001e6c: 07 27 01 0d flw fa4, 208(sp) -80001e70: d3 77 f7 08 fsub.s fa5, fa4, fa5 -80001e74: e3 18 04 ec bnez s0, 0x80001d44 <__kernel_rem_pio2f+0x740> -80001e78: d3 97 f7 20 fneg.s fa5, fa5 -80001e7c: 6f f0 df ee j 0x80001d68 <__kernel_rem_pio2f+0x764> -80001e80: 83 27 01 02 lw a5, 32(sp) -80001e84: d3 96 d6 20 fneg.s fa3, fa3 -80001e88: 53 17 e7 20 fneg.s fa4, fa4 -80001e8c: d3 97 f7 20 fneg.s fa5, fa5 -80001e90: 27 a0 d7 00 fsw fa3, 0(a5) -80001e94: 27 a2 e7 00 fsw fa4, 4(a5) -80001e98: 27 a4 f7 00 fsw fa5, 8(a5) -80001e9c: 6f f0 9f de j 0x80001c84 <__kernel_rem_pio2f+0x680> -80001ea0: 93 07 20 00 li a5, 2 -80001ea4: e3 18 fc a0 bne s8, a5, 0x800018b4 <__kernel_rem_pio2f+0x2b0> -80001ea8: 53 7b 69 09 fsub.s fs6, fs2, fs6 -80001eac: 6f f0 9f a0 j 0x800018b4 <__kernel_rem_pio2f+0x2b0> -80001eb0: 03 27 41 02 lw a4, 36(sp) -80001eb4: 93 07 30 00 li a5, 3 -80001eb8: e3 16 f7 dc bne a4, a5, 0x80001c84 <__kernel_rem_pio2f+0x680> -80001ebc: d3 07 00 f0 fmv.w.x fa5, zero -80001ec0: 6f f0 df f4 j 0x80001e0c <__kernel_rem_pio2f+0x808> -80001ec4: 63 1a 0c 00 bnez s8, 0x80001ed8 <__kernel_rem_pio2f+0x8d4> -80001ec8: 83 27 01 02 lw a5, 32(sp) -80001ecc: 87 27 01 0d flw fa5, 208(sp) -80001ed0: 23 a0 07 00 sw zero, 0(a5) -80001ed4: 6f f0 5f e9 j 0x80001d68 <__kernel_rem_pio2f+0x764> -80001ed8: 97 27 00 00 auipc a5, 2 -80001edc: 07 a7 c7 0b flw fa4, 188(a5) -80001ee0: 87 27 01 0d flw fa5, 208(sp) -80001ee4: 83 27 01 02 lw a5, 32(sp) -80001ee8: d3 97 f7 20 fneg.s fa5, fa5 -80001eec: 27 a0 e7 00 fsw fa4, 0(a5) -80001ef0: 6f f0 9f e7 j 0x80001d68 <__kernel_rem_pio2f+0x764> - -80001ef4 <__kernel_sinf>: -80001ef4: d3 07 05 e0 fmv.x.w a5, fa0 -80001ef8: b7 06 00 32 lui a3, 204800 -80001efc: 13 97 17 00 slli a4, a5, 1 -80001f00: 13 57 17 00 srli a4, a4, 1 -80001f04: 63 76 d7 00 bgeu a4, a3, 0x80001f10 <__kernel_sinf+0x1c> -80001f08: 53 17 05 c0 fcvt.w.s a4, fa0, rtz -80001f0c: 63 08 07 08 beqz a4, 0x80001f9c <__kernel_sinf+0xa8> -80001f10: d3 87 07 f0 fmv.w.x fa5, a5 -80001f14: 17 27 00 00 auipc a4, 2 -80001f18: 87 26 87 08 flw fa3, 136(a4) -80001f1c: 17 27 00 00 auipc a4, 2 -80001f20: 07 20 47 08 flw ft0, 132(a4) -80001f24: 53 f7 f7 10 fmul.s fa4, fa5, fa5 -80001f28: 17 27 00 00 auipc a4, 2 -80001f2c: 87 27 07 07 flw fa5, 112(a4) -80001f30: 17 27 00 00 auipc a4, 2 -80001f34: 07 26 47 07 flw fa2, 116(a4) -80001f38: 53 85 07 f0 fmv.w.x fa0, a5 -80001f3c: c3 77 f7 68 fmadd.s fa5, fa4, fa5, fa3 -80001f40: 17 27 00 00 auipc a4, 2 -80001f44: 87 26 87 06 flw fa3, 104(a4) -80001f48: 53 75 e5 10 fmul.s fa0, fa0, fa4 -80001f4c: c3 f7 e7 00 fmadd.s fa5, fa5, fa4, ft0 -80001f50: c3 f7 e7 60 fmadd.s fa5, fa5, fa4, fa2 -80001f54: c3 f7 e7 68 fmadd.s fa5, fa5, fa4, fa3 -80001f58: 63 1e 05 00 bnez a0, 0x80001f74 <__kernel_sinf+0x80> -80001f5c: 17 27 00 00 auipc a4, 2 -80001f60: 87 26 07 05 flw fa3, 80(a4) -80001f64: 43 77 f7 68 fmadd.s fa4, fa4, fa5, fa3 -80001f68: d3 87 07 f0 fmv.w.x fa5, a5 -80001f6c: 43 75 a7 78 fmadd.s fa0, fa4, fa0, fa5 -80001f70: 67 80 00 00 ret -80001f74: d3 77 f5 10 fmul.s fa5, fa0, fa5 -80001f78: 17 27 00 00 auipc a4, 2 -80001f7c: 87 26 c7 fd flw fa3, -36(a4) -80001f80: 17 27 00 00 auipc a4, 2 -80001f84: 07 26 07 03 flw fa2, 48(a4) -80001f88: c7 f7 d5 78 fmsub.s fa5, fa1, fa3, fa5 -80001f8c: c7 f7 e7 58 fmsub.s fa5, fa5, fa4, fa1 -80001f90: 43 75 c5 78 fmadd.s fa0, fa0, fa2, fa5 -80001f94: d3 87 07 f0 fmv.w.x fa5, a5 -80001f98: 53 f5 a7 08 fsub.s fa0, fa5, fa0 -80001f9c: 67 80 00 00 ret - -80001fa0 : -80001fa0: 53 25 a5 20 fabs.s fa0, fa0 -80001fa4: 67 80 00 00 ret - -80001fa8 : -80001fa8: d3 07 05 e0 fmv.x.w a5, fa0 -80001fac: 13 06 60 01 li a2, 22 -80001fb0: 93 96 17 00 slli a3, a5, 1 -80001fb4: 13 d7 86 01 srli a4, a3, 24 -80001fb8: 13 07 17 f8 addi a4, a4, -127 -80001fbc: 93 d6 16 00 srli a3, a3, 1 -80001fc0: 63 46 e6 08 blt a2, a4, 0x8000204c -80001fc4: 13 85 07 00 mv a0, a5 -80001fc8: 63 48 07 04 bltz a4, 0x80002018 -80001fcc: b7 05 80 00 lui a1, 2048 -80001fd0: 93 86 f5 ff addi a3, a1, -1 -80001fd4: b3 d6 e6 40 sra a3, a3, a4 -80001fd8: 33 f8 f6 00 and a6, a3, a5 -80001fdc: 53 06 05 e0 fmv.x.w a2, fa0 -80001fe0: 63 08 08 02 beqz a6, 0x80002010 -80001fe4: 17 28 00 00 auipc a6, 2 -80001fe8: 87 27 48 fd flw fa5, -44(a6) -80001fec: d3 77 f5 00 fadd.s fa5, fa0, fa5 -80001ff0: 53 07 00 f0 fmv.w.x fa4, zero -80001ff4: 53 18 f7 a0 flt.s a6, fa4, fa5 -80001ff8: 63 0c 08 00 beqz a6, 0x80002010 -80001ffc: 63 d6 07 00 bgez a5, 0x80002008 -80002000: b3 d5 e5 40 sra a1, a1, a4 -80002004: 33 85 f5 00 add a0, a1, a5 -80002008: 93 c6 f6 ff not a3, a3 -8000200c: 33 f6 a6 00 and a2, a3, a0 -80002010: 53 05 06 f0 fmv.w.x fa0, a2 -80002014: 67 80 00 00 ret -80002018: 17 27 00 00 auipc a4, 2 -8000201c: 87 27 07 fa flw fa5, -96(a4) -80002020: d3 77 f5 00 fadd.s fa5, fa0, fa5 -80002024: 53 07 00 f0 fmv.w.x fa4, zero -80002028: 53 06 05 e0 fmv.x.w a2, fa0 -8000202c: 53 17 f7 a0 flt.s a4, fa4, fa5 -80002030: e3 00 07 fe beqz a4, 0x80002010 -80002034: 53 06 07 e0 fmv.x.w a2, fa4 -80002038: e3 dc 07 fc bgez a5, 0x80002010 -8000203c: 63 96 06 02 bnez a3, 0x80002068 -80002040: 17 26 00 00 auipc a2, 2 -80002044: 03 26 46 f5 lw a2, -172(a2) -80002048: 6f f0 9f fc j 0x80002010 -8000204c: 37 07 80 7f lui a4, 522240 -80002050: 53 06 05 e0 fmv.x.w a2, fa0 -80002054: e3 ee e6 fa bltu a3, a4, 0x80002010 -80002058: d3 77 a5 00 fadd.s fa5, fa0, fa0 -8000205c: 53 86 07 e0 fmv.x.w a2, fa5 -80002060: 53 05 06 f0 fmv.w.x fa0, a2 -80002064: 67 80 00 00 ret -80002068: 17 26 00 00 auipc a2, 2 -8000206c: 03 26 c6 f4 lw a2, -180(a2) -80002070: 6f f0 1f fa j 0x80002010 - -80002074 : -80002074: d3 07 05 e0 fmv.x.w a5, fa0 -80002078: 93 96 17 00 slli a3, a5, 1 -8000207c: 13 d7 16 00 srli a4, a3, 1 -80002080: 63 82 06 06 beqz a3, 0x800020e4 -80002084: b7 06 80 7f lui a3, 522240 -80002088: 63 72 d7 06 bgeu a4, a3, 0x800020ec -8000208c: 33 f6 d7 00 and a2, a5, a3 -80002090: 63 16 06 06 bnez a2, 0x800020fc -80002094: 17 27 00 00 auipc a4, 2 -80002098: 87 27 87 f2 flw fa5, -216(a4) -8000209c: d3 77 f5 10 fmul.s fa5, fa0, fa5 -800020a0: 37 47 ff ff lui a4, 1048564 -800020a4: 13 07 07 cb addi a4, a4, -848 -800020a8: d3 87 07 e0 fmv.x.w a5, fa5 -800020ac: 63 4e e5 0a blt a0, a4, 0x80002168 -800020b0: 13 d7 77 41 srai a4, a5, 23 -800020b4: 13 77 f7 0f andi a4, a4, 255 -800020b8: 13 07 77 fe addi a4, a4, -25 -800020bc: 33 05 a7 00 add a0, a4, a0 -800020c0: 13 07 e0 0f li a4, 254 -800020c4: 93 86 07 00 mv a3, a5 -800020c8: 63 54 a7 04 bge a4, a0, 0x80002110 -800020cc: d3 87 07 f0 fmv.w.x fa5, a5 -800020d0: 17 27 00 00 auipc a4, 2 -800020d4: 07 27 87 ee flw fa4, -280(a4) -800020d8: d3 07 f7 20 fsgnj.s fa5, fa4, fa5 -800020dc: d3 f7 e7 10 fmul.s fa5, fa5, fa4 -800020e0: d3 87 07 e0 fmv.x.w a5, fa5 -800020e4: 53 85 07 f0 fmv.w.x fa0, a5 -800020e8: 67 80 00 00 ret -800020ec: d3 77 a5 00 fadd.s fa5, fa0, fa0 -800020f0: d3 87 07 e0 fmv.x.w a5, fa5 -800020f4: 53 85 07 f0 fmv.w.x fa0, a5 -800020f8: 67 80 00 00 ret -800020fc: 13 57 77 01 srli a4, a4, 23 -80002100: 33 05 a7 00 add a0, a4, a0 -80002104: 13 07 e0 0f li a4, 254 -80002108: 93 86 07 00 mv a3, a5 -8000210c: e3 40 a7 fc blt a4, a0, 0x800020cc -80002110: 63 4e a0 02 bgtz a0, 0x8000214c -80002114: 13 07 a0 fe li a4, -22 -80002118: 63 44 e5 06 blt a0, a4, 0x80002180 -8000211c: b7 07 80 80 lui a5, 526336 -80002120: 93 87 f7 ff addi a5, a5, -1 -80002124: 13 05 95 01 addi a0, a0, 25 -80002128: b3 f6 f6 00 and a3, a3, a5 -8000212c: 13 15 75 01 slli a0, a0, 23 -80002130: 33 65 d5 00 or a0, a0, a3 -80002134: 53 07 05 f0 fmv.w.x fa4, a0 -80002138: 97 27 00 00 auipc a5, 2 -8000213c: 87 a7 c7 e8 flw fa5, -372(a5) -80002140: d3 77 f7 10 fmul.s fa5, fa4, fa5 -80002144: d3 87 07 e0 fmv.x.w a5, fa5 -80002148: 6f f0 df f9 j 0x800020e4 -8000214c: b7 07 80 80 lui a5, 526336 -80002150: 93 87 f7 ff addi a5, a5, -1 -80002154: 13 15 75 01 slli a0, a0, 23 -80002158: b3 f6 f6 00 and a3, a3, a5 -8000215c: b3 67 d5 00 or a5, a0, a3 -80002160: 53 85 07 f0 fmv.w.x fa0, a5 -80002164: 67 80 00 00 ret -80002168: 53 87 07 f0 fmv.w.x fa4, a5 -8000216c: 17 27 00 00 auipc a4, 2 -80002170: 87 27 47 e5 flw fa5, -428(a4) -80002174: d3 77 f7 10 fmul.s fa5, fa4, fa5 -80002178: d3 87 07 e0 fmv.x.w a5, fa5 -8000217c: 6f f0 9f f6 j 0x800020e4 -80002180: d3 87 07 f0 fmv.w.x fa5, a5 -80002184: 17 27 00 00 auipc a4, 2 -80002188: 07 27 c7 e3 flw fa4, -452(a4) -8000218c: d3 07 f7 20 fsgnj.s fa5, fa4, fa5 -80002190: d3 f7 e7 10 fmul.s fa5, fa5, fa4 -80002194: d3 87 07 e0 fmv.x.w a5, fa5 -80002198: 6f f0 df f4 j 0x800020e4 - -8000219c : -8000219c: 93 05 05 00 mv a1, a0 -800021a0: 93 06 00 00 li a3, 0 -800021a4: 13 06 00 00 li a2, 0 -800021a8: 13 05 00 00 li a0, 0 -800021ac: 6f 00 40 28 j 0x80002430 <__register_exitproc> - -800021b0 : -800021b0: b3 47 b5 00 xor a5, a0, a1 -800021b4: 93 f7 37 00 andi a5, a5, 3 -800021b8: b3 08 c5 00 add a7, a0, a2 -800021bc: 63 94 07 06 bnez a5, 0x80002224 -800021c0: 93 07 30 00 li a5, 3 -800021c4: 63 f0 c7 06 bgeu a5, a2, 0x80002224 -800021c8: 93 77 35 00 andi a5, a0, 3 -800021cc: 13 07 05 00 mv a4, a0 -800021d0: 63 9a 07 06 bnez a5, 0x80002244 -800021d4: 13 f6 c8 ff andi a2, a7, -4 -800021d8: b3 06 e6 40 sub a3, a2, a4 -800021dc: 93 07 00 02 li a5, 32 -800021e0: 63 ce d7 08 blt a5, a3, 0x8000227c -800021e4: 93 86 05 00 mv a3, a1 -800021e8: 93 07 07 00 mv a5, a4 -800021ec: 63 78 c7 02 bgeu a4, a2, 0x8000221c -800021f0: 03 a8 06 00 lw a6, 0(a3) -800021f4: 93 87 47 00 addi a5, a5, 4 -800021f8: 93 86 46 00 addi a3, a3, 4 -800021fc: 23 ae 07 ff sw a6, -4(a5) -80002200: e3 e8 c7 fe bltu a5, a2, 0x800021f0 -80002204: 93 07 f6 ff addi a5, a2, -1 -80002208: b3 87 e7 40 sub a5, a5, a4 -8000220c: 93 f7 c7 ff andi a5, a5, -4 -80002210: 93 87 47 00 addi a5, a5, 4 -80002214: 33 07 f7 00 add a4, a4, a5 -80002218: b3 85 f5 00 add a1, a1, a5 -8000221c: 63 68 17 01 bltu a4, a7, 0x8000222c -80002220: 67 80 00 00 ret -80002224: 13 07 05 00 mv a4, a0 -80002228: 63 78 15 05 bgeu a0, a7, 0x80002278 -8000222c: 83 c7 05 00 lbu a5, 0(a1) -80002230: 13 07 17 00 addi a4, a4, 1 -80002234: 93 85 15 00 addi a1, a1, 1 -80002238: a3 0f f7 fe sb a5, -1(a4) -8000223c: e3 98 e8 fe bne a7, a4, 0x8000222c -80002240: 67 80 00 00 ret -80002244: 83 c6 05 00 lbu a3, 0(a1) -80002248: 13 07 17 00 addi a4, a4, 1 -8000224c: 93 77 37 00 andi a5, a4, 3 -80002250: a3 0f d7 fe sb a3, -1(a4) -80002254: 93 85 15 00 addi a1, a1, 1 -80002258: e3 8e 07 f6 beqz a5, 0x800021d4 -8000225c: 83 c6 05 00 lbu a3, 0(a1) -80002260: 13 07 17 00 addi a4, a4, 1 -80002264: 93 77 37 00 andi a5, a4, 3 -80002268: a3 0f d7 fe sb a3, -1(a4) -8000226c: 93 85 15 00 addi a1, a1, 1 -80002270: e3 9a 07 fc bnez a5, 0x80002244 -80002274: 6f f0 1f f6 j 0x800021d4 -80002278: 67 80 00 00 ret -8000227c: 13 01 01 ff addi sp, sp, -16 -80002280: 23 26 81 00 sw s0, 12(sp) -80002284: 13 04 00 02 li s0, 32 -80002288: 83 a3 05 00 lw t2, 0(a1) -8000228c: 83 a2 45 00 lw t0, 4(a1) -80002290: 83 af 85 00 lw t6, 8(a1) -80002294: 03 af c5 00 lw t5, 12(a1) -80002298: 83 ae 05 01 lw t4, 16(a1) -8000229c: 03 ae 45 01 lw t3, 20(a1) -800022a0: 03 a3 85 01 lw t1, 24(a1) -800022a4: 03 a8 c5 01 lw a6, 28(a1) -800022a8: 83 a6 05 02 lw a3, 32(a1) -800022ac: 13 07 47 02 addi a4, a4, 36 -800022b0: b3 07 e6 40 sub a5, a2, a4 -800022b4: 23 2e 77 fc sw t2, -36(a4) -800022b8: 23 20 57 fe sw t0, -32(a4) -800022bc: 23 22 f7 ff sw t6, -28(a4) -800022c0: 23 24 e7 ff sw t5, -24(a4) -800022c4: 23 26 d7 ff sw t4, -20(a4) -800022c8: 23 28 c7 ff sw t3, -16(a4) -800022cc: 23 2a 67 fe sw t1, -12(a4) -800022d0: 23 2c 07 ff sw a6, -8(a4) -800022d4: 23 2e d7 fe sw a3, -4(a4) -800022d8: 93 85 45 02 addi a1, a1, 36 -800022dc: e3 46 f4 fa blt s0, a5, 0x80002288 -800022e0: 93 86 05 00 mv a3, a1 -800022e4: 93 07 07 00 mv a5, a4 -800022e8: 63 78 c7 02 bgeu a4, a2, 0x80002318 -800022ec: 03 a8 06 00 lw a6, 0(a3) -800022f0: 93 87 47 00 addi a5, a5, 4 -800022f4: 93 86 46 00 addi a3, a3, 4 -800022f8: 23 ae 07 ff sw a6, -4(a5) -800022fc: e3 e8 c7 fe bltu a5, a2, 0x800022ec -80002300: 93 07 f6 ff addi a5, a2, -1 -80002304: b3 87 e7 40 sub a5, a5, a4 -80002308: 93 f7 c7 ff andi a5, a5, -4 -8000230c: 93 87 47 00 addi a5, a5, 4 -80002310: 33 07 f7 00 add a4, a4, a5 -80002314: b3 85 f5 00 add a1, a1, a5 -80002318: 63 68 17 01 bltu a4, a7, 0x80002328 -8000231c: 03 24 c1 00 lw s0, 12(sp) -80002320: 13 01 01 01 addi sp, sp, 16 -80002324: 67 80 00 00 ret -80002328: 83 c7 05 00 lbu a5, 0(a1) -8000232c: 13 07 17 00 addi a4, a4, 1 -80002330: 93 85 15 00 addi a1, a1, 1 -80002334: a3 0f f7 fe sb a5, -1(a4) -80002338: e3 82 e8 fe beq a7, a4, 0x8000231c -8000233c: 83 c7 05 00 lbu a5, 0(a1) -80002340: 13 07 17 00 addi a4, a4, 1 -80002344: 93 85 15 00 addi a1, a1, 1 -80002348: a3 0f f7 fe sb a5, -1(a4) -8000234c: e3 9e e8 fc bne a7, a4, 0x80002328 -80002350: 6f f0 df fc j 0x8000231c - -80002354 : -80002354: 13 03 f0 00 li t1, 15 -80002358: 13 07 05 00 mv a4, a0 -8000235c: 63 7e c3 02 bgeu t1, a2, 0x80002398 -80002360: 93 77 f7 00 andi a5, a4, 15 -80002364: 63 90 07 0a bnez a5, 0x80002404 -80002368: 63 92 05 08 bnez a1, 0x800023ec -8000236c: 93 76 06 ff andi a3, a2, -16 -80002370: 13 76 f6 00 andi a2, a2, 15 -80002374: b3 86 e6 00 add a3, a3, a4 -80002378: 23 20 b7 00 sw a1, 0(a4) -8000237c: 23 22 b7 00 sw a1, 4(a4) -80002380: 23 24 b7 00 sw a1, 8(a4) -80002384: 23 26 b7 00 sw a1, 12(a4) -80002388: 13 07 07 01 addi a4, a4, 16 -8000238c: e3 66 d7 fe bltu a4, a3, 0x80002378 -80002390: 63 14 06 00 bnez a2, 0x80002398 -80002394: 67 80 00 00 ret -80002398: b3 06 c3 40 sub a3, t1, a2 -8000239c: 93 96 26 00 slli a3, a3, 2 -800023a0: 97 02 00 00 auipc t0, 0 -800023a4: b3 86 56 00 add a3, a3, t0 -800023a8: 67 80 c6 00 jr 12(a3) -800023ac: 23 07 b7 00 sb a1, 14(a4) -800023b0: a3 06 b7 00 sb a1, 13(a4) -800023b4: 23 06 b7 00 sb a1, 12(a4) -800023b8: a3 05 b7 00 sb a1, 11(a4) -800023bc: 23 05 b7 00 sb a1, 10(a4) -800023c0: a3 04 b7 00 sb a1, 9(a4) -800023c4: 23 04 b7 00 sb a1, 8(a4) -800023c8: a3 03 b7 00 sb a1, 7(a4) -800023cc: 23 03 b7 00 sb a1, 6(a4) -800023d0: a3 02 b7 00 sb a1, 5(a4) -800023d4: 23 02 b7 00 sb a1, 4(a4) -800023d8: a3 01 b7 00 sb a1, 3(a4) -800023dc: 23 01 b7 00 sb a1, 2(a4) -800023e0: a3 00 b7 00 sb a1, 1(a4) -800023e4: 23 00 b7 00 sb a1, 0(a4) -800023e8: 67 80 00 00 ret -800023ec: 93 f5 f5 0f andi a1, a1, 255 -800023f0: 93 96 85 00 slli a3, a1, 8 -800023f4: b3 e5 d5 00 or a1, a1, a3 -800023f8: 93 96 05 01 slli a3, a1, 16 -800023fc: b3 e5 d5 00 or a1, a1, a3 -80002400: 6f f0 df f6 j 0x8000236c -80002404: 93 96 27 00 slli a3, a5, 2 -80002408: 97 02 00 00 auipc t0, 0 -8000240c: b3 86 56 00 add a3, a3, t0 -80002410: 93 82 00 00 mv t0, ra -80002414: e7 80 06 fa jalr -96(a3) -80002418: 93 80 02 00 mv ra, t0 -8000241c: 93 87 07 ff addi a5, a5, -16 -80002420: 33 07 f7 40 sub a4, a4, a5 -80002424: 33 06 f6 00 add a2, a2, a5 -80002428: e3 78 c3 f6 bgeu t1, a2, 0x80002398 -8000242c: 6f f0 df f3 j 0x80002368 - -80002430 <__register_exitproc>: -80002430: 17 27 00 00 auipc a4, 2 -80002434: 03 27 87 b9 lw a4, -1128(a4) -80002438: 83 27 87 14 lw a5, 328(a4) -8000243c: 63 8c 07 04 beqz a5, 0x80002494 <__register_exitproc+0x64> -80002440: 03 a7 47 00 lw a4, 4(a5) -80002444: 13 08 f0 01 li a6, 31 -80002448: 63 4e e8 06 blt a6, a4, 0x800024c4 <__register_exitproc+0x94> -8000244c: 13 18 27 00 slli a6, a4, 2 -80002450: 63 06 05 02 beqz a0, 0x8000247c <__register_exitproc+0x4c> -80002454: 33 83 07 01 add t1, a5, a6 -80002458: 23 24 c3 08 sw a2, 136(t1) -8000245c: 83 a8 87 18 lw a7, 392(a5) -80002460: 13 06 10 00 li a2, 1 -80002464: 33 16 e6 00 sll a2, a2, a4 -80002468: b3 e8 c8 00 or a7, a7, a2 -8000246c: 23 a4 17 19 sw a7, 392(a5) -80002470: 23 24 d3 10 sw a3, 264(t1) -80002474: 93 06 20 00 li a3, 2 -80002478: 63 04 d5 02 beq a0, a3, 0x800024a0 <__register_exitproc+0x70> -8000247c: 13 07 17 00 addi a4, a4, 1 -80002480: 23 a2 e7 00 sw a4, 4(a5) -80002484: b3 87 07 01 add a5, a5, a6 -80002488: 23 a4 b7 00 sw a1, 8(a5) -8000248c: 13 05 00 00 li a0, 0 -80002490: 67 80 00 00 ret -80002494: 93 07 c7 14 addi a5, a4, 332 -80002498: 23 24 f7 14 sw a5, 328(a4) -8000249c: 6f f0 5f fa j 0x80002440 <__register_exitproc+0x10> -800024a0: 83 a6 c7 18 lw a3, 396(a5) -800024a4: 13 07 17 00 addi a4, a4, 1 -800024a8: 23 a2 e7 00 sw a4, 4(a5) -800024ac: b3 e6 c6 00 or a3, a3, a2 -800024b0: 23 a6 d7 18 sw a3, 396(a5) -800024b4: b3 87 07 01 add a5, a5, a6 -800024b8: 23 a4 b7 00 sw a1, 8(a5) -800024bc: 13 05 00 00 li a0, 0 -800024c0: 67 80 00 00 ret -800024c4: 13 05 f0 ff li a0, -1 -800024c8: 67 80 00 00 ret - -800024cc <__call_exitprocs>: -800024cc: 13 01 01 fd addi sp, sp, -48 -800024d0: 23 2c 41 01 sw s4, 24(sp) -800024d4: 17 2a 00 00 auipc s4, 2 -800024d8: 03 2a 4a af lw s4, -1292(s4) -800024dc: 23 20 21 03 sw s2, 32(sp) -800024e0: 03 29 8a 14 lw s2, 328(s4) -800024e4: 23 26 11 02 sw ra, 44(sp) -800024e8: 23 24 81 02 sw s0, 40(sp) -800024ec: 23 22 91 02 sw s1, 36(sp) -800024f0: 23 2e 31 01 sw s3, 28(sp) -800024f4: 23 2a 51 01 sw s5, 20(sp) -800024f8: 23 28 61 01 sw s6, 16(sp) -800024fc: 23 26 71 01 sw s7, 12(sp) -80002500: 23 24 81 01 sw s8, 8(sp) -80002504: 63 00 09 04 beqz s2, 0x80002544 <__call_exitprocs+0x78> -80002508: 13 0b 05 00 mv s6, a0 -8000250c: 93 8b 05 00 mv s7, a1 -80002510: 93 0a 10 00 li s5, 1 -80002514: 93 09 f0 ff li s3, -1 -80002518: 83 24 49 00 lw s1, 4(s2) -8000251c: 13 84 f4 ff addi s0, s1, -1 -80002520: 63 42 04 02 bltz s0, 0x80002544 <__call_exitprocs+0x78> -80002524: 93 94 24 00 slli s1, s1, 2 -80002528: b3 04 99 00 add s1, s2, s1 -8000252c: 63 84 0b 04 beqz s7, 0x80002574 <__call_exitprocs+0xa8> -80002530: 83 a7 44 10 lw a5, 260(s1) -80002534: 63 80 77 05 beq a5, s7, 0x80002574 <__call_exitprocs+0xa8> -80002538: 13 04 f4 ff addi s0, s0, -1 -8000253c: 93 84 c4 ff addi s1, s1, -4 -80002540: e3 16 34 ff bne s0, s3, 0x8000252c <__call_exitprocs+0x60> -80002544: 83 20 c1 02 lw ra, 44(sp) -80002548: 03 24 81 02 lw s0, 40(sp) -8000254c: 83 24 41 02 lw s1, 36(sp) -80002550: 03 29 01 02 lw s2, 32(sp) -80002554: 83 29 c1 01 lw s3, 28(sp) -80002558: 03 2a 81 01 lw s4, 24(sp) -8000255c: 83 2a 41 01 lw s5, 20(sp) -80002560: 03 2b 01 01 lw s6, 16(sp) -80002564: 83 2b c1 00 lw s7, 12(sp) -80002568: 03 2c 81 00 lw s8, 8(sp) -8000256c: 13 01 01 03 addi sp, sp, 48 -80002570: 67 80 00 00 ret -80002574: 83 27 49 00 lw a5, 4(s2) -80002578: 83 a6 44 00 lw a3, 4(s1) -8000257c: 93 87 f7 ff addi a5, a5, -1 -80002580: 63 8e 87 04 beq a5, s0, 0x800025dc <__call_exitprocs+0x110> -80002584: 23 a2 04 00 sw zero, 4(s1) -80002588: e3 88 06 fa beqz a3, 0x80002538 <__call_exitprocs+0x6c> -8000258c: 83 27 89 18 lw a5, 392(s2) -80002590: 33 97 8a 00 sll a4, s5, s0 -80002594: 03 2c 49 00 lw s8, 4(s2) -80002598: b3 77 f7 00 and a5, a4, a5 -8000259c: 63 92 07 02 bnez a5, 0x800025c0 <__call_exitprocs+0xf4> -800025a0: e7 80 06 00 jalr a3 -800025a4: 03 27 49 00 lw a4, 4(s2) -800025a8: 83 27 8a 14 lw a5, 328(s4) -800025ac: 63 14 87 01 bne a4, s8, 0x800025b4 <__call_exitprocs+0xe8> -800025b0: e3 84 27 f9 beq a5, s2, 0x80002538 <__call_exitprocs+0x6c> -800025b4: e3 88 07 f8 beqz a5, 0x80002544 <__call_exitprocs+0x78> -800025b8: 13 89 07 00 mv s2, a5 -800025bc: 6f f0 df f5 j 0x80002518 <__call_exitprocs+0x4c> -800025c0: 83 27 c9 18 lw a5, 396(s2) -800025c4: 83 a5 44 08 lw a1, 132(s1) -800025c8: 33 77 f7 00 and a4, a4, a5 -800025cc: 63 1c 07 00 bnez a4, 0x800025e4 <__call_exitprocs+0x118> -800025d0: 13 05 0b 00 mv a0, s6 -800025d4: e7 80 06 00 jalr a3 -800025d8: 6f f0 df fc j 0x800025a4 <__call_exitprocs+0xd8> -800025dc: 23 22 89 00 sw s0, 4(s2) -800025e0: 6f f0 9f fa j 0x80002588 <__call_exitprocs+0xbc> -800025e4: 13 85 05 00 mv a0, a1 -800025e8: e7 80 06 00 jalr a3 -800025ec: 6f f0 9f fb j 0x800025a4 <__call_exitprocs+0xd8> - -800025f0 <__clzsi2>: -800025f0: b7 07 01 00 lui a5, 16 -800025f4: 63 7a f5 02 bgeu a0, a5, 0x80002628 <__clzsi2+0x38> -800025f8: 93 37 05 10 sltiu a5, a0, 256 -800025fc: 93 c7 17 00 xori a5, a5, 1 -80002600: 93 97 37 00 slli a5, a5, 3 -80002604: 13 07 00 02 li a4, 32 -80002608: 33 07 f7 40 sub a4, a4, a5 -8000260c: 33 55 f5 00 srl a0, a0, a5 -80002610: 97 07 00 00 auipc a5, 0 -80002614: 93 87 47 40 addi a5, a5, 1028 -80002618: b3 87 a7 00 add a5, a5, a0 -8000261c: 03 c5 07 00 lbu a0, 0(a5) -80002620: 33 05 a7 40 sub a0, a4, a0 -80002624: 67 80 00 00 ret -80002628: 37 07 00 01 lui a4, 4096 -8000262c: 93 07 00 01 li a5, 16 -80002630: e3 6a e5 fc bltu a0, a4, 0x80002604 <__clzsi2+0x14> -80002634: 93 07 80 01 li a5, 24 -80002638: 6f f0 df fc j 0x80002604 <__clzsi2+0x14> - -Disassembly of section .rodata: - -8000263c <.rodata>: -8000263c: db 0f c9 c0 -80002640: 00 00 -80002642: 80 3d - -80002644 : -80002644: 00 0f -80002646: c9 3f -80002648: 00 0f -8000264a: 49 40 -8000264c: 00 cb -8000264e: 96 40 -80002650: 00 0f -80002652: c9 40 -80002654: 00 53 -80002656: fb 40 00 cb -8000265a: 16 41 -8000265c: 00 ed -8000265e: 2f 41 00 0f -80002662: 49 41 -80002664: 00 31 -80002666: 62 41 -80002668: 00 53 -8000266a: 7b 41 00 3a -8000266e: 8a 41 -80002670: 00 cb -80002672: 96 41 -80002674: 00 5c -80002676: a3 41 00 ed -8000267a: af 41 00 7e -8000267e: bc 41 -80002680: 00 0f -80002682: c9 41 -80002684: 00 a0 -80002686: d5 41 -80002688: 00 31 -8000268a: e2 41 -8000268c: 00 c2 -8000268e: ee 41 -80002690: 00 53 -80002692: fb 41 00 f2 -80002696: 03 42 00 3a lbu tp, 928(zero) -8000269a: 0a 42 -8000269c: 00 83 -8000269e: 10 42 -800026a0: 00 cb -800026a2: 16 42 -800026a4: 00 14 -800026a6: 1d 42 -800026a8: 00 5c -800026aa: 23 42 00 a5 -800026ae: 29 42 -800026b0: 00 ed -800026b2: 2f 42 00 36 -800026b6: 36 42 -800026b8: 00 7e -800026ba: 3c 42 -800026bc: 00 c7 -800026be: 42 42 -800026c0: 00 0f -800026c2: 49 42 - -800026c4 : -800026c4: a2 00 -800026c6: 00 00 -800026c8: f9 00 -800026ca: 00 00 -800026cc: 83 00 00 00 lb ra, 0(zero) -800026d0: 6e 00 -800026d2: 00 00 -800026d4: 4e 00 -800026d6: 00 00 -800026d8: 44 00 -800026da: 00 00 -800026dc: 15 00 -800026de: 00 00 -800026e0: 29 00 -800026e2: 00 00 -800026e4: fc 00 -800026e6: 00 00 -800026e8: 27 00 00 00 -800026ec: 57 00 00 00 -800026f0: d1 00 -800026f2: 00 00 -800026f4: f5 00 -800026f6: 00 00 -800026f8: 34 00 -800026fa: 00 00 -800026fc: dd 00 -800026fe: 00 00 -80002700: c0 00 -80002702: 00 00 -80002704: db 00 00 00 -80002708: 62 00 -8000270a: 00 00 -8000270c: 95 00 -8000270e: 00 00 -80002710: 99 00 -80002712: 00 00 -80002714: 3c 00 -80002716: 00 00 -80002718: 43 00 00 00 fmadd.s ft0, ft0, ft0, ft0, rne -8000271c: 90 00 -8000271e: 00 00 -80002720: 41 00 -80002722: 00 00 -80002724: fe 00 -80002726: 00 00 -80002728: 51 00 -8000272a: 00 00 -8000272c: 63 00 00 00 beqz zero, 0x8000272c -80002730: ab 00 00 00 vx_tex ra, 0, zero, zero, zero -80002734: de 00 -80002736: 00 00 -80002738: bb 00 00 00 -8000273c: c5 00 -8000273e: 00 00 -80002740: 61 00 -80002742: 00 00 -80002744: b7 00 00 00 lui ra, 0 -80002748: 24 00 -8000274a: 00 00 -8000274c: 6e 00 -8000274e: 00 00 -80002750: 3a 00 -80002752: 00 00 -80002754: 42 00 -80002756: 00 00 -80002758: 4d 00 -8000275a: 00 00 -8000275c: d2 00 -8000275e: 00 00 -80002760: e0 00 -80002762: 00 00 -80002764: 06 00 -80002766: 00 00 -80002768: 49 00 -8000276a: 00 00 -8000276c: 2e 00 -8000276e: 00 00 -80002770: ea 00 -80002772: 00 00 -80002774: 09 00 -80002776: 00 00 -80002778: d1 00 -8000277a: 00 00 -8000277c: 92 00 -8000277e: 00 00 -80002780: 1c 00 -80002782: 00 00 -80002784: fe 00 -80002786: 00 00 -80002788: 1d 00 -8000278a: 00 00 -8000278c: eb 00 00 00 -80002790: 1c 00 -80002792: 00 00 -80002794: b1 00 -80002796: 00 00 -80002798: 29 00 -8000279a: 00 00 -8000279c: a7 00 00 00 -800027a0: 3e 00 -800027a2: 00 00 -800027a4: e8 00 -800027a6: 00 00 -800027a8: 82 00 -800027aa: 00 00 -800027ac: 35 00 -800027ae: 00 00 -800027b0: f5 00 -800027b2: 00 00 -800027b4: 2e 00 -800027b6: 00 00 -800027b8: bb 00 00 00 -800027bc: 44 00 -800027be: 00 00 -800027c0: 84 00 -800027c2: 00 00 -800027c4: e9 00 -800027c6: 00 00 -800027c8: 9c 00 -800027ca: 00 00 -800027cc: 70 00 -800027ce: 00 00 -800027d0: 26 00 -800027d2: 00 00 -800027d4: b4 00 -800027d6: 00 00 -800027d8: 5f 00 00 00 -800027dc: 7e 00 -800027de: 00 00 -800027e0: 41 00 -800027e2: 00 00 -800027e4: 39 00 -800027e6: 00 00 -800027e8: 91 00 -800027ea: 00 00 -800027ec: d6 00 -800027ee: 00 00 -800027f0: 39 00 -800027f2: 00 00 -800027f4: 83 00 00 00 lb ra, 0(zero) -800027f8: 53 00 00 00 fadd.s ft0, ft0, ft0, rne -800027fc: 39 00 -800027fe: 00 00 -80002800: f4 00 -80002802: 00 00 -80002804: 9c 00 -80002806: 00 00 -80002808: 84 00 -8000280a: 00 00 -8000280c: 5f 00 00 00 -80002810: 8b 00 00 00 -80002814: bd 00 -80002816: 00 00 -80002818: f9 00 -8000281a: 00 00 -8000281c: 28 00 -8000281e: 00 00 -80002820: 3b 00 00 00 -80002824: 1f 00 00 00 -80002828: f8 00 -8000282a: 00 00 -8000282c: 97 00 00 00 auipc ra, 0 -80002830: ff 00 00 00 -80002834: de 00 -80002836: 00 00 -80002838: 05 00 -8000283a: 00 00 -8000283c: 98 00 -8000283e: 00 00 -80002840: 0f 00 00 00 fence 0, 0 -80002844: ef 00 00 00 jal 0x80002844 -80002848: 2f 00 00 00 -8000284c: 11 00 -8000284e: 00 00 -80002850: 8b 00 00 00 -80002854: 5a 00 -80002856: 00 00 -80002858: 0a 00 -8000285a: 00 00 -8000285c: 6d 00 -8000285e: 00 00 -80002860: 1f 00 00 00 -80002864: 6d 00 -80002866: 00 00 -80002868: 36 00 -8000286a: 00 00 -8000286c: 7e 00 -8000286e: 00 00 -80002870: cf 00 00 00 fnmadd.s ft1, ft0, ft0, ft0, rne -80002874: 27 00 00 00 -80002878: cb 00 00 00 fnmsub.s ft1, ft0, ft0, ft0, rne -8000287c: 09 00 -8000287e: 00 00 -80002880: b7 00 00 00 lui ra, 0 -80002884: 4f 00 00 00 fnmadd.s ft0, ft0, ft0, ft0, rne -80002888: 46 00 -8000288a: 00 00 -8000288c: 3f 00 00 00 -80002890: 66 00 -80002892: 00 00 -80002894: 9e 00 -80002896: 00 00 -80002898: 5f 00 00 00 -8000289c: ea 00 -8000289e: 00 00 -800028a0: 2d 00 -800028a2: 00 00 -800028a4: 75 00 -800028a6: 00 00 -800028a8: 27 00 00 00 -800028ac: ba 00 -800028ae: 00 00 -800028b0: c7 00 00 00 fmsub.s ft1, ft0, ft0, ft0, rne -800028b4: eb 00 00 00 -800028b8: e5 00 -800028ba: 00 00 -800028bc: f1 00 -800028be: 00 00 -800028c0: 7b 00 00 00 -800028c4: 3d 00 -800028c6: 00 00 -800028c8: 07 00 00 00 -800028cc: 39 00 -800028ce: 00 00 -800028d0: f7 00 00 00 -800028d4: 8a 00 -800028d6: 00 00 -800028d8: 52 00 -800028da: 00 00 -800028dc: 92 00 -800028de: 00 00 -800028e0: ea 00 -800028e2: 00 00 -800028e4: 6b 00 00 00 -800028e8: fb 00 00 00 -800028ec: 5f 00 00 00 -800028f0: b1 00 -800028f2: 00 00 -800028f4: 1f 00 00 00 -800028f8: 8d 00 -800028fa: 00 00 -800028fc: 5d 00 -800028fe: 00 00 -80002900: 08 00 -80002902: 00 00 -80002904: 56 00 -80002906: 00 00 -80002908: 03 00 00 00 lb zero, 0(zero) -8000290c: 30 00 -8000290e: 00 00 -80002910: 46 00 -80002912: 00 00 -80002914: fc 00 -80002916: 00 00 -80002918: 7b 00 00 00 -8000291c: 6b 00 00 00 -80002920: ab 00 00 00 vx_tex ra, 0, zero, zero, zero -80002924: f0 00 -80002926: 00 00 -80002928: cf 00 00 00 fnmadd.s ft1, ft0, ft0, ft0, rne -8000292c: bc 00 -8000292e: 00 00 -80002930: 20 00 -80002932: 00 00 -80002934: 9a 00 -80002936: 00 00 -80002938: f4 00 -8000293a: 00 00 -8000293c: 36 00 -8000293e: 00 00 -80002940: 1d 00 -80002942: 00 00 -80002944: a9 00 -80002946: 00 00 -80002948: e3 00 00 00 beqz zero, 0x80003148 <__clz_tab+0x734> -8000294c: 91 00 -8000294e: 00 00 -80002950: 61 00 -80002952: 00 00 -80002954: 5e 00 -80002956: 00 00 -80002958: e6 00 -8000295a: 00 00 -8000295c: 1b 00 00 00 -80002960: 08 00 -80002962: 00 00 -80002964: 65 00 -80002966: 00 00 -80002968: 99 00 -8000296a: 00 00 -8000296c: 85 00 -8000296e: 00 00 -80002970: 5f 00 00 00 -80002974: 14 00 -80002976: 00 00 -80002978: a0 00 -8000297a: 00 00 -8000297c: 68 00 -8000297e: 00 00 -80002980: 40 00 -80002982: 00 00 -80002984: 8d 00 -80002986: 00 00 -80002988: ff 00 00 00 -8000298c: d8 00 -8000298e: 00 00 -80002990: 80 00 -80002992: 00 00 -80002994: 4d 00 -80002996: 00 00 -80002998: 73 00 00 00 ecall -8000299c: 27 00 00 00 -800029a0: 31 00 -800029a2: 00 00 -800029a4: 06 00 -800029a6: 00 00 -800029a8: 06 00 -800029aa: 00 00 -800029ac: 15 00 -800029ae: 00 00 -800029b0: 56 00 -800029b2: 00 00 -800029b4: ca 00 -800029b6: 00 00 -800029b8: 73 00 00 00 ecall -800029bc: a8 00 -800029be: 00 00 -800029c0: c9 00 -800029c2: 00 00 -800029c4: 60 00 -800029c6: 00 00 -800029c8: e2 00 -800029ca: 00 00 -800029cc: 7b 00 00 00 -800029d0: c0 00 -800029d2: 00 00 -800029d4: 8c 00 -800029d6: 00 00 -800029d8: 6b 00 00 00 - -800029dc : -800029dc: 00 00 -800029de: c9 3f -800029e0: 00 00 -800029e2: f0 39 -800029e4: 00 00 -800029e6: da 37 -800029e8: 00 00 -800029ea: a2 33 -800029ec: 00 00 -800029ee: 84 2e -800029f0: 00 00 -800029f2: 50 2b -800029f4: 00 00 -800029f6: c2 27 -800029f8: 00 00 -800029fa: d0 22 -800029fc: 00 00 -800029fe: c4 1f -80002a00: 00 00 -80002a02: c6 1b -80002a04: 00 00 -80002a06: 44 17 - -80002a08 : -80002a08: 04 00 -80002a0a: 00 00 -80002a0c: 07 00 00 00 -80002a10: 09 00 -80002a12: 00 00 - -80002a14 <__clz_tab>: -80002a14: 00 01 -80002a16: 02 02 -80002a18: 03 03 03 03 lb t1, 48(t1) -80002a1c: 04 04 -80002a1e: 04 04 -80002a20: 04 04 -80002a22: 04 04 -80002a24: 05 05 -80002a26: 05 05 -80002a28: 05 05 -80002a2a: 05 05 -80002a2c: 05 05 -80002a2e: 05 05 -80002a30: 05 05 -80002a32: 05 05 -80002a34: 06 06 -80002a36: 06 06 -80002a38: 06 06 -80002a3a: 06 06 -80002a3c: 06 06 -80002a3e: 06 06 -80002a40: 06 06 -80002a42: 06 06 -80002a44: 06 06 -80002a46: 06 06 -80002a48: 06 06 -80002a4a: 06 06 -80002a4c: 06 06 -80002a4e: 06 06 -80002a50: 06 06 -80002a52: 06 06 -80002a54: 07 07 07 07 -80002a58: 07 07 07 07 -80002a5c: 07 07 07 07 -80002a60: 07 07 07 07 -80002a64: 07 07 07 07 -80002a68: 07 07 07 07 -80002a6c: 07 07 07 07 -80002a70: 07 07 07 07 -80002a74: 07 07 07 07 -80002a78: 07 07 07 07 -80002a7c: 07 07 07 07 -80002a80: 07 07 07 07 -80002a84: 07 07 07 07 -80002a88: 07 07 07 07 -80002a8c: 07 07 07 07 -80002a90: 07 07 07 07 -80002a94: 08 08 -80002a96: 08 08 -80002a98: 08 08 -80002a9a: 08 08 -80002a9c: 08 08 -80002a9e: 08 08 -80002aa0: 08 08 -80002aa2: 08 08 -80002aa4: 08 08 -80002aa6: 08 08 -80002aa8: 08 08 -80002aaa: 08 08 -80002aac: 08 08 -80002aae: 08 08 -80002ab0: 08 08 -80002ab2: 08 08 -80002ab4: 08 08 -80002ab6: 08 08 -80002ab8: 08 08 -80002aba: 08 08 -80002abc: 08 08 -80002abe: 08 08 -80002ac0: 08 08 -80002ac2: 08 08 -80002ac4: 08 08 -80002ac6: 08 08 -80002ac8: 08 08 -80002aca: 08 08 -80002acc: 08 08 -80002ace: 08 08 -80002ad0: 08 08 -80002ad2: 08 08 -80002ad4: 08 08 -80002ad6: 08 08 -80002ad8: 08 08 -80002ada: 08 08 -80002adc: 08 08 -80002ade: 08 08 -80002ae0: 08 08 -80002ae2: 08 08 -80002ae4: 08 08 -80002ae6: 08 08 -80002ae8: 08 08 -80002aea: 08 08 -80002aec: 08 08 -80002aee: 08 08 -80002af0: 08 08 -80002af2: 08 08 -80002af4: 08 08 -80002af6: 08 08 -80002af8: 08 08 -80002afa: 08 08 -80002afc: 08 08 -80002afe: 08 08 -80002b00: 08 08 -80002b02: 08 08 -80002b04: 08 08 -80002b06: 08 08 -80002b08: 08 08 -80002b0a: 08 08 -80002b0c: 08 08 -80002b0e: 08 08 -80002b10: 08 08 -80002b12: 08 08 - -Disassembly of section .init_array: - -80003b14 <__tdata_start>: -80003b14: b8 00 -80003b16: 00 80 - -Disassembly of section .data: - -80003b18 : -80003b18: 00 00 -80003b1a: 00 00 -80003b1c: 04 3e -80003b1e: 00 80 -80003b20: 6c 3e -80003b22: 00 80 -80003b24: d4 3e -80003b26: 00 80 - ... -80003bc0: 01 00 -80003bc2: 00 00 -80003bc4: 00 00 -80003bc6: 00 00 -80003bc8: 0e 33 -80003bca: cd ab -80003bcc: 34 12 -80003bce: 6d e6 -80003bd0: ec de -80003bd2: 05 00 -80003bd4: 0b 00 00 00 vx_tmc zero - ... - -Disassembly of section .sdata: - -80003f40 <__SDATA_BEGIN__>: -80003f40: 80 0f -80003f42: c9 3f -80003f44: 43 44 35 37 -80003f48: 00 44 -80003f4a: 35 37 -80003f4c: 08 a3 -80003f4e: 85 2e -80003f50: 84 f9 -80003f52: 22 3f -80003f54: 00 00 -80003f56: 00 3f -80003f58: 00 a3 -80003f5a: 85 2e -80003f5c: 32 31 -80003f5e: 8d 24 -80003f60: 00 00 -80003f62: 80 43 -80003f64: 00 00 -80003f66: 38 3f -80003f68: 00 00 -80003f6a: 90 3e -80003f6c: 00 00 -80003f6e: 80 3f -80003f70: 4e d7 -80003f72: 47 ad f6 74 -80003f76: 0f 31 7c f2 -80003f7a: 93 b4 01 0d sltiu s1, gp, 208 -80003f7e: d0 37 -80003f80: 61 0b -80003f82: b6 ba -80003f84: ab aa 2a 3d -80003f88: 00 00 -80003f8a: 80 3b -80003f8c: 00 00 -80003f8e: 00 3e -80003f90: 00 00 -80003f92: 00 41 -80003f94: 00 00 -80003f96: 00 80 -80003f98: d3 c9 2e 2f -80003f9c: 34 2f -80003f9e: d7 b2 1b ef -80003fa2: 38 36 -80003fa4: 01 0d -80003fa6: 50 b9 -80003fa8: 89 88 -80003faa: 08 3c -80003fac: ab aa 2a be -80003fb0: ab aa 2a 3e -80003fb4: 00 00 -80003fb6: 80 bf -80003fb8: ca f2 -80003fba: 49 71 -80003fbc: 00 00 -80003fbe: 00 4c -80003fc0: 60 42 -80003fc2: a2 0d -80003fc4: 00 00 -80003fc6: 00 33 - -80003fc8 <_global_impure_ptr>: -80003fc8: 18 3b -80003fca: 00 80 - -Disassembly of section .bss: - -80003fcc : -... - -Disassembly of section .comment: - -00000000 <.comment>: - 0: 63 6c 61 6e bltu sp, t1, 0x6f8 <.comment+0x6f8> - 4: 67 20 76 65 - 8: 72 73 - a: 69 6f - c: 6e 20 - e: 31 36 - 10: 2e 30 - 12: 2e 36 - 14: 20 28 - 16: 68 74 - 18: 74 70 - 1a: 73 3a 2f 2f csrrc s4, 754, t5 - 1e: 67 69 74 68 - 22: 75 62 - 24: 2e 63 - 26: 6f 6d 2f 76 jal s10, 0xf6788 <.comment+0xf6788> - 2a: 6f 72 74 65 jal tp, 0x47e80 <.comment+0x47e80> - 2e: 78 67 - 30: 70 67 - 32: 70 75 - 34: 2f 6c 6c 76 - 38: 6d 2e - 3a: 67 69 74 20 - 3e: 35 38 - 40: 38 31 - 42: 31 62 - 44: 66 61 - 46: 36 31 - 48: 61 35 - 4a: 30 33 - 4c: 66 64 - 4e: 34 61 - 50: 35 66 - 52: 30 64 - 54: 63 37 62 35 - 58: 37 38 30 32 lui a6, 205571 - 5c: 66 61 - 5e: 65 35 - 60: 31 63 - 62: 33 66 35 64 - 66: 29 00 - 68: 47 43 43 3a - 6c: 20 28 - 6e: 67 32 65 65 - 72: 35 65 - 74: 34 33 - 76: 30 30 - 78: 31 38 - 7a: 2d 64 - 7c: 69 72 - 7e: 74 79 - 80: 29 20 - 82: 31 32 - 84: 2e 32 - 86: 2e 30 - 88: 00 47 - 8a: 43 43 3a 20 fmadd.s ft6, fs4, ft3, ft4, rmm - 8e: 28 47 - 90: 4e 55 - 92: 29 20 - 94: 31 32 - 96: 2e 32 - 98: 2e 30 - 9a: 00 - -Disassembly of section .riscv.attributes: - -00000000 <.riscv.attributes>: - 0: 41 40 - 2: 00 00 - 4: 00 72 - 6: 69 73 - 8: 63 76 00 01 bgeu zero, a6, 0x14 <.comment+0x14> - c: 36 00 - e: 00 00 - 10: 04 10 - 12: 05 72 - 14: 76 33 - 16: 32 69 - 18: 32 70 - 1a: 31 5f - 1c: 6d 32 - 1e: 70 30 - 20: 5f 61 32 70 - 24: 31 5f - 26: 66 32 - 28: 70 32 - 2a: 5f 7a 69 63 - 2e: 73 72 32 70 csrrci tp, 1795, 4 - 32: 30 5f - 34: 7a 6d - 36: 6d 75 - 38: 6c 31 - 3a: 70 30 - 3c: 00 08 - 3e: 01 0a - 40: 0b - -Disassembly of section .debug_aranges: - -00000000 <.debug_aranges>: - 0: 1c 00 - 2: 00 00 - 4: 02 00 - 6: 00 00 - 8: 00 00 - a: 04 00 - c: 00 00 - e: 00 00 - 10: f0 25 - 12: 00 80 - 14: 4c 00 - ... - 1e: 00 00 - 20: 14 00 - 22: 00 00 - 24: 02 00 - 26: 42 01 - 28: 00 00 - 2a: 04 00 - ... - -Disassembly of section .debug_info: - -00000000 <.debug_info>: - 0: 3e 01 - 2: 00 00 - 4: 05 00 - 6: 01 04 - 8: 00 00 - a: 00 00 - c: 04 2b - e: 00 00 - 10: 00 1d - 12: 00 00 - 14: 00 00 - 16: 21 00 - 18: 00 00 - 1a: f0 25 - 1c: 00 80 - 1e: 4c 00 - 20: 00 00 - 22: 00 00 - 24: 00 00 - 26: 05 04 - 28: 05 69 - 2a: 6e 74 - 2c: 00 01 - 2e: 04 07 - 30: f2 00 - 32: 00 00 - 34: 01 08 - 36: 05 00 - 38: 00 00 - 3a: 00 01 - 3c: 10 04 - 3e: 1f 01 00 00 - 42: 01 01 - 44: 06 01 - 46: 01 00 - 48: 00 01 - 4a: 01 08 - 4c: ff 00 00 00 - 50: 01 02 - 52: 05 5c - 54: 01 00 - 56: 00 01 - 58: 02 07 - 5a: 2b 01 00 00 vx_tex sp, 0, zero, zero, zero - 5e: 01 04 - 60: 05 05 - 62: 00 00 - 64: 00 01 - 66: 04 07 - 68: ed 00 - 6a: 00 00 - 6c: 01 08 - 6e: 07 e8 00 00 - 72: 00 01 - 74: 01 08 - 76: 08 01 - 78: 00 00 - 7a: 02 4c - 7c: 01 00 - 7e: 00 7b - 80: 16 49 - 82: 00 00 - 84: 00 03 - 86: 7a 00 - 88: 00 00 - 8a: 02 55 - 8c: 01 00 - 8e: 00 80 - 90: 0f 26 00 00 - 94: 00 02 - 96: 54 01 - 98: 00 00 - 9a: 81 16 - 9c: 2d 00 - 9e: 00 00 - a0: 01 04 - a2: 04 46 - a4: 01 00 - a6: 00 01 - a8: 08 03 - aa: 3e 01 - ac: 00 00 - ae: 01 08 - b0: 04 24 - b2: 01 00 - b4: 00 01 - b6: 10 03 - b8: 17 00 00 00 auipc zero, 0 - bc: 01 20 - be: 03 17 01 00 lh a4, 0(sp) - c2: 00 06 - c4: 85 00 - c6: 00 00 - c8: d3 00 00 00 fadd.s ft1, ft0, ft0, rne - cc: 07 2d 00 00 flw fs10, 0(zero) - d0: 00 ff - d2: 00 03 - d4: c3 00 00 00 fmadd.s ft1, ft0, ft0, ft0, rne - d8: 08 0d - da: 01 00 - dc: 00 02 - de: 02 02 - e0: 16 d3 - e2: 00 00 - e4: 00 09 - e6: 0e 00 - e8: 00 00 - ea: 01 ae - ec: 02 01 - ee: 26 00 - f0: 00 00 - f2: f0 25 - f4: 00 80 - f6: 4c 00 - f8: 00 00 - fa: 01 9c - fc: 0a 78 - fe: 00 01 - 100: ae 02 - 102: 12 95 - 104: 00 00 - 106: 00 0c - 108: 00 00 - 10a: 00 0b - 10c: 72 65 - 10e: 74 00 - 110: 01 b0 - 112: 02 09 - 114: 8a 00 - 116: 00 00 - 118: 0c 0c - 11a: 00 00 - 11c: 00 0d - 11e: 26 00 - 120: 00 00 - 122: 01 b2 - 124: 02 03 - 126: 95 00 - 128: 00 00 - 12a: 31 00 - 12c: 00 00 - 12e: 0e 5f - 130: 5f 61 00 01 - 134: b2 02 - 136: 03 95 00 00 lh a0, 0(ra) - 13a: 00 56 - 13c: 00 00 - 13e: 00 00 - 140: 00 00 - 142: d4 00 - 144: 00 00 - 146: 05 00 - 148: 01 04 - 14a: ca 00 - 14c: 00 00 - 14e: 03 2b 00 00 lw s6, 0(zero) - 152: 00 1d - 154: 00 00 - 156: 00 00 - 158: 21 00 - 15a: 00 00 - 15c: cb 00 00 00 fnmsub.s ft1, ft0, ft0, ft0, rne - 160: 04 04 - 162: 05 69 - 164: 6e 74 - 166: 00 01 - 168: 04 07 - 16a: f2 00 - 16c: 00 00 - 16e: 01 08 - 170: 05 00 - 172: 00 00 - 174: 00 01 - 176: 10 04 - 178: 1f 01 00 00 - 17c: 01 01 - 17e: 06 01 - 180: 01 00 - 182: 00 01 - 184: 01 08 - 186: ff 00 00 00 - 18a: 01 02 - 18c: 05 5c - 18e: 01 00 - 190: 00 01 - 192: 02 07 - 194: 2b 01 00 00 vx_tex sp, 0, zero, zero, zero - 198: 01 04 - 19a: 05 05 - 19c: 00 00 - 19e: 00 01 - 1a0: 04 07 - 1a2: ed 00 - 1a4: 00 00 - 1a6: 01 08 - 1a8: 07 e8 00 00 - 1ac: 00 01 - 1ae: 01 08 - 1b0: 08 01 - 1b2: 00 00 - 1b4: 05 4c - 1b6: 01 00 - 1b8: 00 01 - 1ba: 7b 16 41 00 - 1be: 00 00 - 1c0: 02 72 - 1c2: 00 00 - 1c4: 00 01 - 1c6: 04 04 - 1c8: 46 01 - 1ca: 00 00 - 1cc: 01 08 - 1ce: 03 3e 01 00 - 1d2: 00 01 - 1d4: 08 04 - 1d6: 24 01 - 1d8: 00 00 - 1da: 01 10 - 1dc: 03 17 00 00 lh a4, 0(zero) - 1e0: 00 01 - 1e2: 20 03 - 1e4: 17 01 00 00 auipc sp, 0 - 1e8: 06 7e - 1ea: 00 00 - 1ec: 00 b6 - 1ee: 00 00 - 1f0: 00 07 - 1f2: 25 00 - 1f4: 00 00 - 1f6: ff 00 02 a6 - 1fa: 00 00 - 1fc: 00 08 - 1fe: 0d 01 - 200: 00 00 - 202: 01 02 - 204: 02 16 - 206: b6 00 - 208: 00 00 - 20a: 09 bb - 20c: 00 00 - 20e: 00 02 - 210: 9e 02 - 212: 0f 05 03 14 - 216: 2a 00 - 218: 80 00 - -Disassembly of section .debug_abbrev: - -00000000 <.debug_abbrev>: - 0: 01 24 - 2: 00 0b - 4: 0b 3e 0b 03 - 8: 0e 00 - a: 00 02 - c: 16 00 - e: 03 0e 3a 21 lb t3, 531(s4) - 12: 02 3b - 14: 0b 39 0b 49 - 18: 13 00 00 03 li zero, 48 - 1c: 26 00 - 1e: 49 13 - 20: 00 00 - 22: 04 11 - 24: 01 25 - 26: 0e 13 - 28: 0b 03 1f 1b - 2c: 1f 11 01 12 - 30: 06 10 - 32: 17 00 00 05 auipc zero, 20480 - 36: 24 00 - 38: 0b 0b 3e 0b - 3c: 03 08 00 00 lb a6, 0(zero) - 40: 06 01 - 42: 01 49 - 44: 13 01 13 00 addi sp, t1, 1 - 48: 00 07 - 4a: 21 00 - 4c: 49 13 - 4e: 2f 0b 00 00 - 52: 08 34 - 54: 00 03 - 56: 0e 3a - 58: 0b 3b 05 39 - 5c: 0b 49 13 3f - 60: 19 3c - 62: 19 00 - 64: 00 09 - 66: 2e 01 - 68: 3f 19 03 0e - 6c: 3a 0b - 6e: 3b 05 39 0b - 72: 27 19 49 13 - 76: 11 01 - 78: 12 06 - 7a: 40 18 - 7c: 7a 19 - 7e: 00 00 - 80: 0a 05 - 82: 00 03 - 84: 08 3a - 86: 0b 3b 05 39 - 8a: 0b 49 13 02 - 8e: 17 00 00 0b auipc zero, 45056 - 92: 34 00 - 94: 03 08 3a 0b lb a6, 179(s4) - 98: 3b 05 39 0b - 9c: 49 13 - 9e: 00 00 - a0: 0c 0b - a2: 01 55 - a4: 17 00 00 0d auipc zero, 53248 - a8: 34 00 - aa: 03 0e 3a 0b lb t3, 179(s4) - ae: 3b 05 39 0b - b2: 49 13 - b4: 02 17 - b6: 00 00 - b8: 0e 34 - ba: 00 03 - bc: 08 3a - be: 0b 3b 05 39 - c2: 0b 49 13 02 - c6: 17 00 00 00 auipc zero, 0 - ca: 01 24 - cc: 00 0b - ce: 0b 3e 0b 03 - d2: 0e 00 - d4: 00 02 - d6: 26 00 - d8: 49 13 - da: 00 00 - dc: 03 11 01 25 lh sp, 592(sp) - e0: 0e 13 - e2: 0b 03 1f 1b - e6: 1f 10 17 00 - ea: 00 04 - ec: 24 00 - ee: 0b 0b 3e 0b - f2: 03 08 00 00 lb a6, 0(zero) - f6: 05 16 - f8: 00 03 - fa: 0e 3a - fc: 0b 3b 0b 39 - 100: 0b 49 13 00 - 104: 00 06 - 106: 01 01 - 108: 49 13 - 10a: 01 13 - 10c: 00 00 - 10e: 07 21 00 49 flw ft2, 1168(zero) - 112: 13 2f 0b 00 slti t5, s6, 0 - 116: 00 08 - 118: 34 00 - 11a: 03 0e 3a 0b lb t3, 179(s4) - 11e: 3b 05 39 0b - 122: 49 13 - 124: 3f 19 3c 19 - 128: 00 00 - 12a: 09 34 - 12c: 00 47 - 12e: 13 3a 0b 3b sltiu s4, s6, 944 - 132: 05 39 - 134: 0b 02 18 00 - 138: 00 00 - -Disassembly of section .debug_line: - -00000000 <.debug_line>: - 0: c7 00 00 00 fmsub.s ft1, ft0, ft0, ft0, rne - 4: 05 00 - 6: 04 00 - 8: 33 00 00 00 add zero, zero, zero - c: 01 01 - e: 01 fb - 10: 0e 0d - 12: 00 01 - 14: 01 01 - 16: 01 00 - 18: 00 00 - 1a: 01 00 - 1c: 00 01 - 1e: 01 01 - 20: 1f 02 21 00 - 24: 00 00 - 26: 81 00 - 28: 00 00 - 2a: 02 01 - 2c: 1f 02 0f 03 - 30: 17 00 00 00 auipc zero, 0 - 34: 01 17 - 36: 00 00 - 38: 00 01 - 3a: 98 00 - 3c: 00 00 - 3e: 01 05 - 40: 01 00 - 42: 05 02 - 44: f0 25 - 46: 00 80 - 48: 03 ae 05 01 lw t3, 16(a1) - 4c: 05 03 - 4e: 03 01 09 00 lb sp, 0(s2) - 52: 00 01 - 54: 03 02 09 00 lb tp, 0(s2) - 58: 00 01 - 5a: 03 00 09 00 lb zero, 0(s2) - 5e: 00 01 - 60: 03 00 09 00 lb zero, 0(s2) - 64: 00 01 - 66: 03 00 09 00 lb zero, 0(s2) - 6a: 00 01 - 6c: 03 00 09 00 lb zero, 0(s2) - 70: 00 01 - 72: 00 02 - 74: 04 03 - 76: 06 03 - 78: 00 09 - 7a: 08 00 - 7c: 01 00 - 7e: 02 04 - 80: 0e 06 - 82: 03 00 09 0c lb zero, 192(s2) - 86: 00 01 - 88: 00 02 - 8a: 04 0e - 8c: 03 00 09 00 lb zero, 0(s2) - 90: 00 01 - 92: 00 02 - 94: 04 0e - 96: 03 02 09 00 lb tp, 0(s2) - 9a: 00 01 - 9c: 00 02 - 9e: 04 0e - a0: 06 03 - a2: 7e 09 - a4: 00 00 - a6: 01 05 - a8: 01 00 - aa: 02 04 - ac: 0e 03 - ae: 03 09 1c 00 lb s2, 1(s8) - b2: 01 05 - b4: 03 00 02 04 lb zero, 64(tp) - b8: 04 03 - ba: 7d 09 - bc: 08 00 - be: 01 03 - c0: 00 09 - c2: 0c 00 - c4: 01 09 - c6: 08 00 - c8: 00 01 - ca: 01 3b - cc: 00 00 - ce: 00 05 - d0: 00 04 - d2: 00 33 - d4: 00 00 - d6: 00 01 - d8: 01 01 - da: fb 0e 0d 00 - de: 01 01 - e0: 01 01 - e2: 00 00 - e4: 00 01 - e6: 00 00 - e8: 01 01 - ea: 01 1f - ec: 02 21 - ee: 00 00 - f0: 00 81 - f2: 00 00 - f4: 00 02 - f6: 01 1f - f8: 02 0f - fa: 03 17 00 00 lh a4, 0(zero) - fe: 00 01 - 100: 98 00 - 102: 00 00 - 104: 01 17 - 106: 00 00 - 108: 00 01 - -Disassembly of section .debug_frame: - -00000000 <.debug_frame>: - 0: 0c 00 - 2: 00 00 - 4: ff ff ff ff - 8: 03 00 01 7c lb zero, 1984(sp) - c: 01 0d - e: 02 00 - 10: 0c 00 - 12: 00 00 - 14: 00 00 - 16: 00 00 - 18: f0 25 - 1a: 00 80 - 1c: 4c 00 - 1e: 00 00 - -Disassembly of section .debug_str: - -00000000 <.debug_str>: - 0: 6c 6f - 2: 6e 67 - 4: 20 6c - 6: 6f 6e 67 20 jal t3, 0x7620c <.debug_info+0x7620c> - a: 69 6e - c: 74 00 - e: 5f 5f 63 6c - 12: 7a 73 - 14: 69 32 - 16: 00 63 - 18: 6f 6d 70 6c jal s10, 0x6ede <.debug_info+0x6ede> - 1c: 65 78 - 1e: 20 64 - 20: 6f 75 62 6c jal a0, 0x276e6 <.debug_info+0x276e6> - 24: 65 00 - 26: 5f 5f 78 72 - 2a: 00 47 - 2c: 4e 55 - 2e: 20 43 - 30: 31 37 - 32: 20 31 - 34: 32 2e - 36: 32 2e - 38: 30 20 - 3a: 2d 6d - 3c: 63 6d 6f 64 bltu t5, t1, 0x696 <.debug_info+0x696> - 40: 65 6c - 42: 3d 6d - 44: 65 64 - 46: 61 6e - 48: 79 20 - 4a: 2d 6d - 4c: 63 6d 6f 64 bltu t5, t1, 0x6a6 <.debug_info+0x6a6> - 50: 65 6c - 52: 3d 6d - 54: 65 64 - 56: 61 6e - 58: 79 20 - 5a: 2d 6d - 5c: 74 75 - 5e: 6e 65 - 60: 3d 72 - 62: 6f 63 6b 65 jal t1, 0xb66b8 <.debug_info+0xb66b8> - 66: 74 20 - 68: 2d 6d - 6a: 61 62 - 6c: 69 3d - 6e: 69 6c - 70: 70 33 - 72: 32 66 - 74: 20 2d - 76: 6d 69 - 78: 73 61 2d 73 csrrsi sp, mhpmevent18h, 26 - 7c: 70 65 - 7e: 63 3d 32 30 - 82: 31 39 - 84: 31 32 - 86: 31 33 - 88: 20 2d - 8a: 6d 61 - 8c: 72 63 - 8e: 68 3d - 90: 72 76 - 92: 33 32 69 6d - 96: 66 5f - 98: 7a 69 - 9a: 63 73 72 20 bgeu tp, t2, 0x2a0 <.debug_info+0x2a0> - 9e: 2d 67 - a0: 20 2d - a2: 4f 73 20 2d - a6: 4f 32 20 2d - aa: 4f 73 20 2d - ae: 66 62 - b0: 75 69 - b2: 6c 64 - b4: 69 6e - b6: 67 2d 6c 69 - ba: 62 67 - bc: 63 63 20 2d bltu zero, s2, 0x382 <.debug_info+0x382> - c0: 66 6e - c2: 6f 2d 73 74 jal s10, 0x33008 <.debug_info+0x33008> - c6: 61 63 - c8: 6b 2d 70 72 - cc: 6f 74 65 63 jal s0, 0x57702 <.debug_info+0x57702> - d0: 74 6f - d2: 72 20 - d4: 2d 66 - d6: 76 69 - d8: 73 69 62 69 csrrsi s2, 1686, 4 - dc: 6c 69 - de: 74 79 - e0: 3d 68 - e2: 69 64 - e4: 64 65 - e6: 6e 00 - e8: 6c 6f - ea: 6e 67 - ec: 20 6c - ee: 6f 6e 67 20 jal t3, 0x762f4 <.debug_info+0x762f4> - f2: 75 6e - f4: 73 69 67 6e csrrsi s2, 1766, 14 - f8: 65 64 - fa: 20 69 - fc: 6e 74 - fe: 00 75 - 100: 6e 73 - 102: 69 67 - 104: 6e 65 - 106: 64 20 - 108: 63 68 61 72 bltu sp, t1, 0x838 <.debug_info+0x838> - 10c: 00 5f - 10e: 5f 63 6c 7a - 112: 5f 74 61 62 - 116: 00 63 - 118: 6f 6d 70 6c jal s10, 0x6fde <.debug_info+0x6fde> - 11c: 65 78 - 11e: 20 6c - 120: 6f 6e 67 20 jal t3, 0x76326 <.debug_info+0x76326> - 124: 64 6f - 126: 75 62 - 128: 6c 65 - 12a: 00 73 - 12c: 68 6f - 12e: 72 74 - 130: 20 75 - 132: 6e 73 - 134: 69 67 - 136: 6e 65 - 138: 64 20 - 13a: 69 6e - 13c: 74 00 - 13e: 63 6f 6d 70 bltu s10, t1, 0x85c <.debug_info+0x85c> - 142: 6c 65 - 144: 78 20 - 146: 66 6c - 148: 6f 61 74 00 jal sp, 0x4694e <.debug_info+0x4694e> - 14c: 55 51 - 14e: 49 74 - 150: 79 70 - 152: 65 00 - 154: 55 53 - 156: 49 74 - 158: 79 70 - 15a: 65 00 - 15c: 73 68 6f 72 csrrsi a6, mhpmevent6h, 30 - 160: 74 20 - 162: 69 6e - 164: 74 00 - -Disassembly of section .debug_loclists: - -00000000 <.debug_loclists>: - 0: 5e 00 - 2: 00 00 - 4: 05 00 - 6: 04 00 - 8: 00 00 - a: 00 00 - c: 07 f0 25 00 - 10: 80 10 - 12: 26 00 - 14: 80 01 - 16: 5a 07 - 18: 10 26 - 1a: 00 80 - 1c: 28 26 - 1e: 00 80 - 20: 04 a3 - 22: 01 5a - 24: 9f 07 28 26 - 28: 00 80 - 2a: 3c 26 - 2c: 00 80 - 2e: 01 5a - 30: 00 07 - 32: f0 25 - 34: 00 80 - 36: 10 26 - 38: 00 80 - 3a: 01 5a - 3c: 07 10 26 00 - 40: 80 28 - 42: 26 00 - 44: 80 04 - 46: a3 01 5a 9f sb s5, -1565(s4) - 4a: 07 28 26 00 flw fa6, 2(a2) - 4e: 80 3c - 50: 26 00 - 52: 80 01 - 54: 5a 00 - 56: 07 04 26 00 - 5a: 80 18 - 5c: 26 00 - 5e: 80 01 - 60: 5f - 61: 00 - -Disassembly of section .debug_rnglists: - -00000000 <.debug_rnglists>: - 0: 24 00 - 2: 00 00 - 4: 05 00 - 6: 04 00 - 8: 00 00 - a: 00 00 - c: 06 f0 - e: 25 00 - 10: 80 04 - 12: 26 00 - 14: 80 06 - 16: 04 26 - 18: 00 80 - 1a: 20 26 - 1c: 00 80 - 1e: 06 28 - 20: 26 00 - 22: 80 3c - 24: 26 00 - 26: 80 00 - -Disassembly of section .debug_line_str: - -00000000 <.debug_line_str>: - 0: 2e 2e - 2: 2f 2e 2e 2f - 6: 2e 2e - 8: 2f 2e 2e 2f - c: 67 63 63 2f - 10: 6c 69 - 12: 62 67 - 14: 63 63 2f 6c bltu t5, sp, 0x6da <.debug_info+0x6da> - 18: 69 62 - 1a: 67 63 63 32 - 1e: 2e 63 - 20: 00 2f - 22: 68 6f - 24: 6d 65 - 26: 2f 62 6c 61 - 2a: 69 73 - 2c: 65 2f - 2e: 64 65 - 30: 76 2f - 32: 72 69 - 34: 73 63 76 2d csrrsi t1, 727, 12 - 38: 67 6e 75 2d - 3c: 74 6f - 3e: 6f 6c 63 68 jal s8, 0x366c4 <.debug_info+0x366c4> - 42: 61 69 - 44: 6e 2f - 46: 62 75 - 48: 69 6c - 4a: 64 33 - 4c: 32 2f - 4e: 62 75 - 50: 69 6c - 52: 64 2d - 54: 67 63 63 2d - 58: 6e 65 - 5a: 77 6c 69 62 - 5e: 2d 73 - 60: 74 61 - 62: 67 65 32 2f - 66: 72 69 - 68: 73 63 76 33 csrrsi t1, mhpmevent23, 12 - 6c: 32 2d - 6e: 75 6e - 70: 6b 6e 6f 77 - 74: 6e 2d - 76: 65 6c - 78: 66 2f - 7a: 6c 69 - 7c: 62 67 - 7e: 63 63 00 2e bltu zero, zero, 0x364 <.debug_info+0x364> - 82: 2e 2f - 84: 2e 2e - 86: 2f 2e 2e 2f - 8a: 2e 2e - 8c: 2f 67 63 63 - 90: 2f 6c 69 62 - 94: 67 63 63 00 - 98: 6c 69 - 9a: 62 67 - 9c: 63 63 32 2e bltu tp, gp, 0x382 <.debug_info+0x382> - a0: 68 00 - -Disassembly of section .symtab: - -00000000 <.symtab>: - ... - 14: 00 00 - 16: 00 80 - 18: 00 00 - 1a: 00 00 - 1c: 03 00 01 00 lb zero, 0(sp) - 20: 00 00 - 22: 00 00 - 24: 84 00 - 26: 00 80 - 28: 00 00 - 2a: 00 00 - 2c: 03 00 02 00 lb zero, 0(tp) - 30: 00 00 - 32: 00 00 - 34: 3c 26 - 36: 00 80 - 38: 00 00 - 3a: 00 00 - 3c: 03 00 03 00 lb zero, 0(t1) - 40: 00 00 - 42: 00 00 - 44: 14 3b - 46: 00 80 - 48: 00 00 - 4a: 00 00 - 4c: 03 00 04 00 lb zero, 0(s0) - 50: 00 00 - 52: 00 00 - 54: 18 3b - 56: 00 80 - 58: 00 00 - 5a: 00 00 - 5c: 03 00 05 00 lb zero, 0(a0) - 60: 00 00 - 62: 00 00 - 64: 40 3f - 66: 00 80 - 68: 00 00 - 6a: 00 00 - 6c: 03 00 06 00 lb zero, 0(a2) - 70: 00 00 - 72: 00 00 - 74: cc 3f - 76: 00 80 - 78: 00 00 - 7a: 00 00 - 7c: 03 00 07 00 lb zero, 0(a4) - ... - 8c: 03 00 08 00 lb zero, 0(a6) - ... - 9c: 03 00 09 00 lb zero, 0(s2) - ... - ac: 03 00 0a 00 lb zero, 0(s4) - ... - bc: 03 00 0b 00 lb zero, 0(s6) - ... - cc: 03 00 0c 00 lb zero, 0(s8) - ... - dc: 03 00 0d 00 lb zero, 0(s10) - ... - ec: 03 00 0e 00 lb zero, 0(t3) - ... - fc: 03 00 0f 00 lb zero, 0(t5) - ... - 10c: 03 00 10 00 lb zero, 1(zero) - ... - 11c: 03 00 11 00 lb zero, 1(sp) - ... - 12c: 03 00 12 00 lb zero, 1(tp) - 130: 01 00 - ... - 13a: 00 00 - 13c: 04 00 - 13e: f1 ff - 140: 0e 00 - 142: 00 00 - 144: 00 00 - 146: 00 80 - 148: 00 00 - 14a: 00 00 - 14c: 00 00 - 14e: 01 00 - 150: 3a 00 - 152: 00 00 - 154: d8 08 - 156: 00 80 - 158: 00 00 - 15a: 00 00 - 15c: 02 00 - 15e: 02 00 - 160: 48 00 - 162: 00 00 - 164: a4 08 - 166: 00 80 - 168: 00 00 - 16a: 00 00 - 16c: 02 00 - 16e: 02 00 - 170: 52 00 - 172: 00 00 - 174: ec 08 - 176: 00 80 - 178: 00 00 - 17a: 00 00 - 17c: 02 00 - 17e: 02 00 - 180: 0e 00 - 182: 00 00 - 184: 94 08 - 186: 00 80 - 188: 00 00 - 18a: 00 00 - 18c: 00 00 - 18e: 02 00 - 190: e6 01 - ... - 19a: 00 00 - 19c: 04 00 - 19e: f1 ff - 1a0: 5f 00 00 00 - 1a4: 84 00 - 1a6: 00 80 - 1a8: 00 00 - 1aa: 00 00 - 1ac: 00 00 - 1ae: 02 00 - 1b0: 86 00 - ... - 1ba: 00 00 - 1bc: 04 00 - 1be: f1 ff - 1c0: 96 00 - 1c2: 00 00 - 1c4: b8 00 - 1c6: 00 80 - 1c8: 18 00 - 1ca: 00 00 - 1cc: 02 00 - 1ce: 02 00 - 1d0: 5f 00 00 00 - 1d4: b8 00 - 1d6: 00 80 - 1d8: 00 00 - 1da: 00 00 - 1dc: 00 00 - 1de: 02 00 - 1e0: 5f 00 00 00 - 1e4: cc 24 - 1e6: 00 80 - 1e8: 00 00 - 1ea: 00 00 - 1ec: 00 00 - 1ee: 02 00 - 1f0: a4 00 - ... - 1fa: 00 00 - 1fc: 04 00 - 1fe: f1 ff - 200: c0 00 - ... - 20a: 00 00 - 20c: 04 00 - 20e: f1 ff - 210: cc 00 - 212: 00 00 - 214: fc 00 - 216: 00 80 - 218: 24 00 - 21a: 00 00 - 21c: 02 00 - 21e: 02 00 - 220: d8 00 - 222: 00 00 - 224: 20 01 - 226: 00 80 - 228: 24 00 - 22a: 00 00 - 22c: 02 00 - 22e: 02 00 - 230: e4 00 - ... - 23a: 00 00 - 23c: 04 00 - 23e: f1 ff - 240: 0e 00 - 242: 00 00 - 244: 10 09 - 246: 00 80 - 248: 00 00 - 24a: 00 00 - 24c: 00 00 - 24e: 02 00 - 250: 0e 00 - 252: 00 00 - 254: 54 09 - 256: 00 80 - 258: 00 00 - 25a: 00 00 - 25c: 00 00 - 25e: 02 00 - 260: 0e 00 - 262: 00 00 - 264: e8 09 - 266: 00 80 - 268: 00 00 - 26a: 00 00 - 26c: 00 00 - 26e: 02 00 - 270: f2 00 - ... - 27a: 00 00 - 27c: 04 00 - 27e: f1 ff - 280: fd 00 - 282: 00 00 - 284: 44 0a - 286: 00 80 - 288: 5c 01 - 28a: 00 00 - 28c: 02 00 - 28e: 02 00 - 290: 0e 00 - 292: 00 00 - 294: 44 0a - 296: 00 80 - 298: 00 00 - 29a: 00 00 - 29c: 00 00 - 29e: 02 00 - 2a0: 13 01 00 00 li sp, 0 - 2a4: a0 0b - 2a6: 00 80 - 2a8: 84 00 - 2aa: 00 00 - 2ac: 02 00 - 2ae: 02 00 - 2b0: 0e 00 - 2b2: 00 00 - 2b4: a0 0b - 2b6: 00 80 - 2b8: 00 00 - 2ba: 00 00 - 2bc: 00 00 - 2be: 02 00 - 2c0: 29 01 - 2c2: 00 00 - 2c4: 24 0c - 2c6: 00 80 - 2c8: 24 00 - 2ca: 00 00 - 2cc: 02 00 - 2ce: 02 00 - 2d0: 0e 00 - 2d2: 00 00 - 2d4: 24 0c - 2d6: 00 80 - 2d8: 00 00 - 2da: 00 00 - 2dc: 00 00 - 2de: 02 00 - 2e0: 0e 00 - 2e2: 00 00 - 2e4: 48 0c - 2e6: 00 80 - 2e8: 00 00 - 2ea: 00 00 - 2ec: 00 00 - 2ee: 02 00 - 2f0: 3d 01 - ... - 2fa: 00 00 - 2fc: 04 00 - 2fe: f1 ff - 300: 0e 00 - 302: 00 00 - 304: 40 0e - 306: 00 80 - 308: 00 00 - 30a: 00 00 - 30c: 00 00 - 30e: 02 00 - 310: 47 01 00 00 fmsub.s ft2, ft0, ft0, ft0, rne - ... - 31c: 04 00 - 31e: f1 ff - 320: 5f 00 00 00 - 324: 58 10 - 326: 00 80 - 328: 00 00 - 32a: 00 00 - 32c: 00 00 - 32e: 02 00 - 330: 50 01 - ... - 33a: 00 00 - 33c: 04 00 - 33e: f1 ff - 340: 5f 00 00 00 - 344: f8 10 - 346: 00 80 - 348: 00 00 - 34a: 00 00 - 34c: 00 00 - 34e: 02 00 - 350: 59 01 - ... - 35a: 00 00 - 35c: 04 00 - 35e: f1 ff - 360: 5f 00 00 00 - 364: 9c 11 - 366: 00 80 - 368: 00 00 - 36a: 00 00 - 36c: 00 00 - 36e: 02 00 - 370: 67 01 00 00 jalr sp, zero - 374: c4 26 - 376: 00 80 - 378: 18 03 - 37a: 00 00 - 37c: 01 00 - 37e: 03 00 73 01 lb zero, 23(t1) - 382: 00 00 - 384: 44 26 - 386: 00 80 - 388: 80 00 - 38a: 00 00 - 38c: 01 00 - 38e: 03 00 7c 01 lb zero, 23(s8) - ... - 39a: 00 00 - 39c: 04 00 - 39e: f1 ff - 3a0: 5f 00 00 00 - 3a4: b8 14 - 3a6: 00 80 - 3a8: 00 00 - 3aa: 00 00 - 3ac: 00 00 - 3ae: 02 00 - 3b0: 85 01 - ... - 3ba: 00 00 - 3bc: 04 00 - 3be: f1 ff - 3c0: 5f 00 00 00 - 3c4: 04 16 - 3c6: 00 80 - 3c8: 00 00 - 3ca: 00 00 - 3cc: 00 00 - 3ce: 02 00 - 3d0: 93 01 00 00 li gp, 0 - 3d4: 08 2a - 3d6: 00 80 - 3d8: 0c 00 - 3da: 00 00 - 3dc: 01 00 - 3de: 03 00 9b 01 lb zero, 25(s6) - 3e2: 00 00 - 3e4: dc 29 - 3e6: 00 80 - 3e8: 2c 00 - 3ea: 00 00 - 3ec: 01 00 - 3ee: 03 00 a0 01 lb zero, 26(zero) - ... - 3fa: 00 00 - 3fc: 04 00 - 3fe: f1 ff - 400: 5f 00 00 00 - 404: f4 1e - 406: 00 80 - 408: 00 00 - 40a: 00 00 - 40c: 00 00 - 40e: 02 00 - 410: a9 01 - ... - 41a: 00 00 - 41c: 04 00 - 41e: f1 ff - 420: 5f 00 00 00 - 424: a0 1f - 426: 00 80 - 428: 00 00 - 42a: 00 00 - 42c: 00 00 - 42e: 02 00 - 430: b3 01 00 00 add gp, zero, zero - ... - 43c: 04 00 - 43e: f1 ff - 440: 5f 00 00 00 - 444: a8 1f - 446: 00 80 - 448: 00 00 - 44a: 00 00 - 44c: 00 00 - 44e: 02 00 - 450: be 01 - ... - 45a: 00 00 - 45c: 04 00 - 45e: f1 ff - 460: 5f 00 00 00 - 464: 74 20 - 466: 00 80 - 468: 00 00 - 46a: 00 00 - 46c: 00 00 - 46e: 02 00 - 470: e4 01 - ... - 47a: 00 00 - 47c: 04 00 - 47e: f1 ff - 480: 5f 00 00 00 - 484: 9c 21 - 486: 00 80 - 488: 00 00 - 48a: 00 00 - 48c: 00 00 - 48e: 02 00 - 490: ca 01 - ... - 49a: 00 00 - 49c: 04 00 - 49e: f1 ff - 4a0: 5f 00 00 00 - 4a4: b0 21 - 4a6: 00 80 - 4a8: 00 00 - 4aa: 00 00 - 4ac: 00 00 - 4ae: 02 00 - 4b0: d3 01 00 00 fadd.s ft3, ft0, ft0, rne - ... - 4bc: 04 00 - 4be: f1 ff - 4c0: 5f 00 00 00 - 4c4: 54 23 - 4c6: 00 80 - 4c8: 00 00 - 4ca: 00 00 - 4cc: 00 00 - 4ce: 02 00 - 4d0: e2 01 - ... - 4da: 00 00 - 4dc: 04 00 - 4de: f1 ff - 4e0: 5f 00 00 00 - 4e4: 30 24 - 4e6: 00 80 - 4e8: 00 00 - 4ea: 00 00 - 4ec: 00 00 - 4ee: 02 00 - 4f0: ed 01 - ... - 4fa: 00 00 - 4fc: 04 00 - 4fe: f1 ff - 500: 5f 00 00 00 - 504: f0 25 - 506: 00 80 - 508: 00 00 - 50a: 00 00 - 50c: 00 00 - 50e: 02 00 - 510: ed 01 - ... - 51a: 00 00 - 51c: 04 00 - 51e: f1 ff - 520: f7 01 00 00 - ... - 52c: 04 00 - 52e: f1 ff - 530: 00 02 - 532: 00 00 - 534: 18 3b - 536: 00 80 - 538: 28 04 - 53a: 00 00 - 53c: 01 00 - 53e: 05 00 - ... - 54c: 04 00 - 54e: f1 ff - 550: 0c 02 - 552: 00 00 - 554: 18 3b - 556: 00 80 - 558: 00 00 - 55a: 00 00 - 55c: 00 00 - 55e: 05 00 - 560: 1d 02 - 562: 00 00 - 564: 14 3b - 566: 00 80 - 568: 00 00 - 56a: 00 00 - 56c: 00 00 - 56e: 04 00 - 570: 2a 02 - 572: 00 00 - 574: 18 3b - 576: 00 80 - 578: 00 00 - 57a: 00 00 - 57c: 00 00 - 57e: 05 00 - 580: 3d 02 - 582: 00 00 - 584: 14 3b - 586: 00 80 - 588: 00 00 - 58a: 00 00 - 58c: 00 00 - 58e: 04 00 - 590: 4b 02 00 00 fnmsub.s ft4, ft0, ft0, ft0, rne - 594: 18 3b - 596: 00 80 - 598: 00 00 - 59a: 00 00 - 59c: 00 00 - 59e: 04 00 - 5a0: 5c 02 - ... - 5ae: f1 ff - 5b0: 6a 02 - 5b2: 00 00 - 5b4: 14 3b - 5b6: 00 80 - 5b8: 00 00 - 5ba: 00 00 - 5bc: 00 00 - 5be: 04 00 - 5c0: 7e 02 - 5c2: 00 00 - 5c4: 14 3b - 5c6: 00 80 - 5c8: 00 00 - 5ca: 00 00 - 5cc: 00 00 - 5ce: 04 00 - 5d0: 89 02 - 5d2: 00 00 - 5d4: 14 3b - 5d6: 00 80 - 5d8: 00 00 - 5da: 00 00 - 5dc: 00 00 - 5de: 04 00 - 5e0: 9c 02 - 5e2: 00 00 - 5e4: 14 3b - 5e6: 00 80 - 5e8: 00 00 - 5ea: 00 00 - 5ec: 00 00 - 5ee: 04 00 - 5f0: b2 02 - 5f2: 00 00 - 5f4: 9c 11 - 5f6: 00 80 - 5f8: 1c 03 - 5fa: 00 00 - 5fc: 12 00 - 5fe: 02 00 - 600: c6 02 - 602: 00 00 - 604: cc 3f - 606: 00 80 - 608: 00 10 - 60a: 00 00 - 60c: 11 00 - 60e: 07 00 d4 02 - 612: 00 00 - 614: 40 3f - 616: 00 80 - 618: 00 00 - 61a: 00 00 - 61c: 10 00 - 61e: 06 00 - 620: e4 02 - 622: 00 00 - 624: 00 09 - 626: 00 80 - 628: 00 00 - 62a: 00 00 - 62c: 12 00 - 62e: 02 00 - 630: f3 02 00 00 - 634: b0 21 - 636: 00 80 - 638: a4 01 - 63a: 00 00 - 63c: 12 00 - 63e: 02 00 - 640: fa 02 - 642: 00 00 - 644: 40 47 - 646: 00 80 - 648: 00 00 - 64a: 00 00 - 64c: 10 00 - 64e: f1 ff - 650: 0b 03 00 00 - 654: 44 01 - 656: 00 80 - 658: 50 07 - 65a: 00 00 - 65c: 12 00 - 65e: 02 00 - 660: 2d 03 - 662: 00 00 - 664: a0 1f - 666: 00 80 - 668: 08 00 - 66a: 00 00 - 66c: 12 00 - 66e: 02 00 - 670: 33 03 00 00 add t1, zero, zero - 674: c8 3f - 676: 00 80 - 678: 04 00 - 67a: 00 00 - 67c: 11 00 - 67e: 06 00 - 680: 46 03 - 682: 00 00 - 684: 54 09 - 686: 00 80 - 688: 94 00 - 68a: 00 00 - 68c: 12 00 - 68e: 02 00 - 690: 58 03 - 692: 00 00 - 694: f4 1e - 696: 00 80 - 698: ac 00 - 69a: 00 00 - 69c: 12 00 - 69e: 02 00 - 6a0: 66 03 - 6a2: 00 00 - 6a4: 10 09 - 6a6: 00 80 - 6a8: 44 00 - 6aa: 00 00 - 6ac: 12 00 - 6ae: 02 00 - 6b0: d3 00 00 00 fadd.s ft1, ft0, ft0, rne - 6b4: 58 10 - 6b6: 00 80 - 6b8: a0 00 - 6ba: 00 00 - 6bc: 12 00 - 6be: 02 00 - 6c0: 71 03 - 6c2: 00 00 - 6c4: e8 09 - 6c6: 00 80 - 6c8: 5c 00 - 6ca: 00 00 - 6cc: 12 00 - 6ce: 02 00 - 6d0: 83 03 00 00 lb t2, 0(zero) - 6d4: b8 14 - 6d6: 00 80 - 6d8: 4c 01 - 6da: 00 00 - 6dc: 12 00 - 6de: 02 00 - 6e0: 91 03 - ... - 6ea: 00 00 - 6ec: 10 00 - 6ee: f1 ff - 6f0: 9e 03 - ... - 6fa: 00 00 - 6fc: 10 00 - 6fe: f1 ff - 700: aa 03 - 702: 00 00 - 704: f0 25 - 706: 00 80 - 708: 4c 00 - 70a: 00 00 - 70c: 12 02 - 70e: 02 00 - 710: b3 03 00 00 add t2, zero, zero - 714: cc 24 - 716: 00 80 - 718: 24 01 - 71a: 00 00 - 71c: 12 00 - 71e: 02 00 - 720: 44 02 - 722: 00 00 - 724: 00 00 - 726: 00 80 - 728: 84 00 - 72a: 00 00 - 72c: 12 00 - 72e: 01 00 - 730: c4 03 - 732: 00 00 - 734: 30 24 - 736: 00 80 - 738: 9c 00 - 73a: 00 00 - 73c: 12 00 - 73e: 02 00 - 740: d8 03 - 742: 00 00 - 744: cc 4f - 746: 00 80 - 748: 00 00 - 74a: 00 00 - 74c: 10 00 - 74e: 07 00 e4 03 - 752: 00 00 - 754: 74 20 - 756: 00 80 - 758: 28 01 - 75a: 00 00 - 75c: 12 00 - 75e: 02 00 - 760: ec 03 - 762: 00 00 - 764: cc 3f - 766: 00 80 - 768: 00 00 - 76a: 00 00 - 76c: 10 00 - 76e: 07 00 f8 03 - 772: 00 00 - 774: 54 23 - 776: 00 80 - 778: dc 00 - 77a: 00 00 - 77c: 12 00 - 77e: 02 00 - 780: ff 03 00 00 - 784: d0 00 - 786: 00 80 - 788: 2c 00 - 78a: 00 00 - 78c: 12 00 - 78e: 02 00 - 790: 04 04 - 792: 00 00 - 794: 14 2a - 796: 00 80 - 798: 00 01 - 79a: 00 00 - 79c: 11 02 - 79e: 03 00 0e 04 lb zero, 64(t3) - 7a2: 00 00 - 7a4: 9c 21 - 7a6: 00 80 - 7a8: 14 00 - 7aa: 00 00 - 7ac: 12 00 - 7ae: 02 00 - 7b0: 15 04 - ... - 7ba: 00 00 - 7bc: 10 00 - 7be: f1 ff - 7c0: 28 04 - 7c2: 00 00 - 7c4: 00 00 - 7c6: 00 80 - 7c8: 00 00 - 7ca: 00 00 - 7cc: 10 00 - 7ce: f1 ff - 7d0: df 00 00 00 - 7d4: f8 10 - 7d6: 00 80 - 7d8: a4 00 - 7da: 00 00 - 7dc: 12 00 - 7de: 02 00 - 7e0: 35 04 - 7e2: 00 00 - 7e4: 18 3b - 7e6: 00 80 - 7e8: 00 00 - 7ea: 00 00 - 7ec: 10 00 - 7ee: 05 00 - 7f0: 44 04 - 7f2: 00 00 - 7f4: cc 3f - 7f6: 00 80 - 7f8: 00 00 - 7fa: 00 00 - 7fc: 10 00 - 7fe: 06 00 - 800: 84 02 - 802: 00 00 - 804: cc 4f - 806: 00 80 - 808: 00 00 - 80a: 00 00 - 80c: 10 00 - 80e: 07 00 59 04 - 812: 00 00 - 814: 84 00 - 816: 00 80 - 818: 34 00 - 81a: 00 00 - 81c: 12 00 - 81e: 02 00 - 820: 4b 04 00 00 fnmsub.s fs0, ft0, ft0, ft0, rne - 824: 40 0e - 826: 00 80 - 828: 18 02 - 82a: 00 00 - 82c: 12 00 - 82e: 02 00 - 830: 58 04 - 832: 00 00 - 834: 94 08 - 836: 00 80 - 838: 00 00 - 83a: 00 00 - 83c: 12 00 - 83e: 02 00 - 840: 5e 04 - 842: 00 00 - 844: 04 16 - 846: 00 80 - 848: f0 08 - 84a: 00 00 - 84c: 12 00 - 84e: 02 00 - 850: 71 04 - 852: 00 00 - 854: a8 1f - 856: 00 80 - 858: cc 00 - 85a: 00 00 - 85c: 12 00 - 85e: 02 00 - 860: 78 04 - 862: 00 00 - 864: 48 0c - 866: 00 80 - 868: f8 01 - 86a: 00 00 - 86c: 12 00 - 86e: 02 00 - -Disassembly of section .strtab: - -00000000 <.strtab>: - 0: 00 76 - 2: 78 5f - 4: 73 74 61 72 csrrci s0, mhpmevent6h, 2 - 8: 74 2e - a: 53 2e 6f 00 fadd.s ft8, ft10, ft6, rdn - e: 24 78 - 10: 72 76 - 12: 33 32 69 32 - 16: 70 31 - 18: 5f 6d 32 70 - 1c: 30 5f - 1e: 61 32 - 20: 70 31 - 22: 5f 66 32 70 - 26: 32 5f - 28: 7a 69 - 2a: 63 73 72 32 bgeu tp, t2, 0x350 <.symtab+0x350> - 2e: 70 30 - 30: 5f 7a 6d 6d - 34: 75 6c - 36: 31 70 - 38: 30 00 - 3a: 69 6e - 3c: 69 74 - 3e: 5f 72 65 67 - 42: 73 5f 61 6c csrrwi t5, 1734, 2 - 46: 6c 00 - 48: 69 6e - 4a: 69 74 - 4c: 5f 72 65 67 - 50: 73 00 69 6e - 54: 69 74 - 56: 5f 74 6c 73 - 5a: 5f 61 6c 6c - 5e: 00 24 - 60: 78 72 - 62: 76 33 - 64: 32 69 - 66: 32 70 - 68: 31 5f - 6a: 6d 32 - 6c: 70 30 - 6e: 5f 66 32 70 - 72: 32 5f - 74: 7a 69 - 76: 63 73 72 32 bgeu tp, t2, 0x39c <.symtab+0x39c> - 7a: 70 30 - 7c: 5f 7a 6d 6d - 80: 75 6c - 82: 31 70 - 84: 30 00 - 86: 5f 5f 63 61 - 8a: 6c 6c - 8c: 5f 61 74 65 - 90: 78 69 - 92: 74 2e - 94: 63 00 72 65 beq tp, s7, 0x6d4 <.symtab+0x6d4> - 98: 67 69 73 74 - 9c: 65 72 - 9e: 5f 66 69 6e - a2: 69 00 - a4: 70 6f - a6: 63 6c 5f 76 bltu t5, t0, 0x81e <.symtab+0x81e> - aa: 6f 72 74 65 jal tp, 0x47f00 <.symtab+0x47f00> - ae: 78 5f - b0: 6b 65 72 6e - b4: 65 6c - b6: 5f 33 69 37 - ba: 4d 30 - bc: 62 2e - be: 63 00 70 61 beq zero, s7, 0x6be <.symtab+0x6be> - c2: 72 61 - c4: 6c 6c - c6: 65 6c - c8: 5f 62 63 00 - cc: 5f 5a 37 5f - d0: 63 6c 5f 63 bltu t5, s5, 0x708 <.symtab+0x708> - d4: 6f 73 66 00 jal t1, 0x670da <.symtab+0x670da> - d8: 5f 5a 37 5f - dc: 63 6c 5f 73 bltu t5, s5, 0x814 <.symtab+0x814> - e0: 69 6e - e2: 66 00 - e4: 76 78 - e6: 5f 73 79 73 - ea: 63 61 6c 6c bltu s8, t1, 0x7ac <.symtab+0x7ac> - ee: 73 2e 63 00 csrrs t3, 6, t1 - f2: 76 78 - f4: 5f 73 70 61 - f8: 77 6e 2e 63 - fc: 00 73 - fe: 70 61 - 100: 77 6e 5f 6b - 104: 65 72 - 106: 6e 65 - 108: 6c 5f - 10a: 61 6c - 10c: 6c 5f - 10e: 73 74 75 62 csrrci s0, 1575, 10 - 112: 00 73 - 114: 70 61 - 116: 77 6e 5f 6b - 11a: 65 72 - 11c: 6e 65 - 11e: 6c 5f - 120: 72 65 - 122: 6d 5f - 124: 73 74 75 62 csrrci s0, 1575, 10 - 128: 00 73 - 12a: 70 61 - 12c: 77 6e 5f 6b - 130: 65 72 - 132: 6e 65 - 134: 6c 5f - 136: 61 6c - 138: 6c 5f - 13a: 63 62 00 76 bltu zero, zero, 0x89e <.symtab+0x89e> - 13e: 78 5f - 140: 70 65 - 142: 72 66 - 144: 2e 63 - 146: 00 73 - 148: 66 5f - 14a: 63 6f 73 2e bltu t1, t2, 0x448 <.symtab+0x448> - 14e: 63 00 73 66 beq t1, t2, 0x7ae <.symtab+0x7ae> - 152: 5f 73 69 6e - 156: 2e 63 - 158: 00 65 - 15a: 66 5f - 15c: 72 65 - 15e: 6d 5f - 160: 70 69 - 162: 6f 32 2e 63 jal tp, 0xe3794 <.symtab+0xe3794> - 166: 00 74 - 168: 77 6f 5f 6f - 16c: 76 65 - 16e: 72 5f - 170: 70 69 - 172: 00 6e - 174: 70 69 - 176: 6f 32 5f 68 jal tp, 0xf3ffa <.symtab+0xf3ffa> - 17a: 77 00 6b 66 - 17e: 5f 63 6f 73 - 182: 2e 63 - 184: 00 6b - 186: 66 5f - 188: 72 65 - 18a: 6d 5f - 18c: 70 69 - 18e: 6f 32 2e 63 jal tp, 0xe37c0 <.symtab+0xe37c0> - 192: 00 69 - 194: 6e 69 - 196: 74 5f - 198: 6a 6b - 19a: 00 50 - 19c: 49 6f - 19e: 32 00 - 1a0: 6b 66 5f 73 - 1a4: 69 6e - 1a6: 2e 63 - 1a8: 00 73 - 1aa: 66 5f - 1ac: 66 61 - 1ae: 62 73 - 1b0: 2e 63 - 1b2: 00 73 - 1b4: 66 5f - 1b6: 66 6c - 1b8: 6f 6f 72 2e jal t5, 0x26c9e <.symtab+0x26c9e> - 1bc: 63 00 73 66 beq t1, t2, 0x81c <.symtab+0x81c> - 1c0: 5f 73 63 61 - 1c4: 6c 62 - 1c6: 6e 2e - 1c8: 63 00 6d 65 beq s10, s6, 0x808 <.symtab+0x808> - 1cc: 6d 63 - 1ce: 70 79 - 1d0: 2e 63 - 1d2: 00 6c - 1d4: 69 62 - 1d6: 5f 61 2d 6d - 1da: 65 6d - 1dc: 73 65 74 2e csrrsi a0, 743, 8 - 1e0: 6f 00 5f 5f j 0xf0fd4 <.symtab+0xf0fd4> - 1e4: 61 74 - 1e6: 65 78 - 1e8: 69 74 - 1ea: 2e 63 - 1ec: 00 6c - 1ee: 69 62 - 1f0: 67 63 63 32 - 1f4: 2e 63 - 1f6: 00 69 - 1f8: 6d 70 - 1fa: 75 72 - 1fc: 65 2e - 1fe: 63 00 69 6d beq s2, s6, 0x8be <.symtab+0x8be> - 202: 70 75 - 204: 72 65 - 206: 5f 64 61 74 - 20a: 61 00 - 20c: 5f 5f 66 69 - 210: 6e 69 - 212: 5f 61 72 72 - 216: 61 79 - 218: 5f 65 6e 64 - 21c: 00 5f - 21e: 5f 74 62 73 - 222: 73 5f 73 74 csrrwi t5, mseccfg, 6 - 226: 61 72 - 228: 74 00 - 22a: 5f 5f 66 69 - 22e: 6e 69 - 230: 5f 61 72 72 - 234: 61 79 - 236: 5f 73 74 61 - 23a: 72 74 - 23c: 00 5f - 23e: 5f 74 64 61 - 242: 74 61 - 244: 5f 73 74 61 - 248: 72 74 - 24a: 00 5f - 24c: 5f 69 6e 69 - 250: 74 5f - 252: 61 72 - 254: 72 61 - 256: 79 5f - 258: 65 6e - 25a: 64 00 - 25c: 5f 5f 74 62 - 260: 73 73 5f 6f csrrci t1, 1781, 30 - 264: 66 66 - 266: 73 65 74 00 csrrsi a0, 7, 8 - 26a: 5f 5f 70 72 - 26e: 65 69 - 270: 6e 69 - 272: 74 5f - 274: 61 72 - 276: 72 61 - 278: 79 5f - 27a: 65 6e - 27c: 64 00 - 27e: 5f 5f 74 62 - 282: 73 73 5f 65 csrrci t1, 1621, 30 - 286: 6e 64 - 288: 00 5f - 28a: 5f 69 6e 69 - 28e: 74 5f - 290: 61 72 - 292: 72 61 - 294: 79 5f - 296: 73 74 61 72 csrrci s0, mhpmevent6h, 2 - 29a: 74 00 - 29c: 5f 5f 70 72 - 2a0: 65 69 - 2a2: 6e 69 - 2a4: 74 5f - 2a6: 61 72 - 2a8: 72 61 - 2aa: 79 5f - 2ac: 73 74 61 72 csrrci s0, mhpmevent6h, 2 - 2b0: 74 00 - 2b2: 5f 5f 69 65 - 2b6: 65 65 - 2b8: 37 35 34 5f lui a0, 389955 - 2bc: 72 65 - 2be: 6d 5f - 2c0: 70 69 - 2c2: 6f 32 66 00 jal tp, 0x632c8 <.symtab+0x632c8> - 2c6: 67 5f 77 73 - 2ca: 70 61 - 2cc: 77 6e 5f 61 - 2d0: 72 67 - 2d2: 73 00 5f 5f - 2d6: 53 44 41 54 - 2da: 41 5f - 2dc: 42 45 - 2de: 47 49 4e 5f - 2e2: 5f 00 76 78 - 2e6: 5f 77 73 70 - 2ea: 61 77 - 2ec: 6e 5f - 2ee: 77 61 69 74 - 2f2: 00 6d - 2f4: 65 6d - 2f6: 63 70 79 00 bgeu s2, t2, 0x2f6 <.symtab+0x2f6> - 2fa: 5f 5f 67 6c - 2fe: 6f 62 61 6c jal tp, 0x169c4 <.symtab+0x169c4> - 302: 5f 70 6f 69 - 306: 6e 74 - 308: 65 72 - 30a: 00 5f - 30c: 70 6f - 30e: 63 6c 5f 6b bltu t5, s5, 0x9c6 <.symtab+0x9c6> - 312: 65 72 - 314: 6e 65 - 316: 6c 5f - 318: 66 66 - 31a: 74 5f - 31c: 72 61 - 31e: 64 69 - 320: 78 34 - 322: 5f 77 6f 72 - 326: 6b 67 72 6f - 32a: 75 70 - 32c: 00 66 - 32e: 61 62 - 330: 73 66 00 5f csrrsi a2, 1520, 0 - 334: 67 6c 6f 62 - 338: 61 6c - 33a: 5f 69 6d 70 - 33e: 75 72 - 340: 65 5f - 342: 70 74 - 344: 72 00 - 346: 5f 5f 6c 69 - 34a: 62 63 - 34c: 5f 69 6e 69 - 350: 74 5f - 352: 61 72 - 354: 72 61 - 356: 79 00 - 358: 5f 5f 6b 65 - 35c: 72 6e - 35e: 65 6c - 360: 5f 73 69 6e - 364: 66 00 - 366: 5f 5f 69 6e - 36a: 69 74 - 36c: 5f 74 6c 73 - 370: 00 5f - 372: 5f 6c 69 62 - 376: 63 5f 66 69 bge a2, s6, 0xa14 <.symtab+0xa14> - 37a: 6e 69 - 37c: 5f 61 72 72 - 380: 61 79 - 382: 00 5f - 384: 5f 6b 65 72 - 388: 6e 65 - 38a: 6c 5f - 38c: 63 6f 73 66 bltu t1, t2, 0xa0a <.symtab+0xa0a> - 390: 00 5f - 392: 5f 74 64 61 - 396: 74 61 - 398: 5f 73 69 7a - 39c: 65 00 - 39e: 5f 5f 74 62 - 3a2: 73 73 5f 73 csrrci t1, mhpmevent21h, 30 - 3a6: 69 7a - 3a8: 65 00 - 3aa: 5f 5f 63 6c - 3ae: 7a 73 - 3b0: 69 32 - 3b2: 00 5f - 3b4: 5f 63 61 6c - 3b8: 6c 5f - 3ba: 65 78 - 3bc: 69 74 - 3be: 70 72 - 3c0: 6f 63 73 00 jal t1, 0x36bc6 <.symtab+0x36bc6> - 3c4: 5f 5f 72 65 - 3c8: 67 69 73 74 - 3cc: 65 72 - 3ce: 5f 65 78 69 - 3d2: 74 70 - 3d4: 72 6f - 3d6: 63 00 5f 5f beq t5, s5, 0x9b6 <.symtab+0x9b6> - 3da: 42 53 - 3dc: 53 5f 45 4e - 3e0: 44 5f - 3e2: 5f 00 73 63 - 3e6: 61 6c - 3e8: 62 6e - 3ea: 66 00 - 3ec: 5f 5f 62 73 - 3f0: 73 5f 73 74 csrrwi t5, mseccfg, 6 - 3f4: 61 72 - 3f6: 74 00 - 3f8: 6d 65 - 3fa: 6d 73 - 3fc: 65 74 - 3fe: 00 6d - 400: 61 69 - 402: 6e 00 - 404: 5f 5f 63 6c - 408: 7a 5f - 40a: 74 61 - 40c: 62 00 - 40e: 61 74 - 410: 65 78 - 412: 69 74 - 414: 00 5f - 416: 5f 74 63 62 - 41a: 5f 61 6c 69 - 41e: 67 6e 65 64 - 422: 5f 73 69 7a - 426: 65 00 - 428: 53 54 41 52 - 42c: 54 55 - 42e: 50 5f - 430: 41 44 - 432: 44 52 - 434: 00 5f - 436: 5f 44 41 54 - 43a: 41 5f - 43c: 42 45 - 43e: 47 49 4e 5f - 442: 5f 00 5f 65 - 446: 64 61 - 448: 74 61 - 44a: 00 76 - 44c: 78 5f - 44e: 70 65 - 450: 72 66 - 452: 5f 64 75 6d - 456: 70 00 - 458: 5f 65 78 69 - 45c: 74 00 - 45e: 5f 5f 6b 65 - 462: 72 6e - 464: 65 6c - 466: 5f 72 65 6d - 46a: 5f 70 69 6f - 46e: 32 66 - 470: 00 66 - 472: 6c 6f - 474: 6f 72 66 00 jal tp, 0x6747a <.symtab+0x6747a> - 478: 76 78 - 47a: 5f 73 70 61 - 47e: 77 6e 5f 6b - 482: 65 72 - 484: 6e 65 - 486: 6c 00 - -Disassembly of section .shstrtab: - -00000000 <.shstrtab>: - 0: 00 2e - 2: 73 79 6d 74 csrrci s2, 1862, 26 - 6: 61 62 - 8: 00 2e - a: 73 74 72 74 csrrci s0, mseccfg, 4 - e: 61 62 - 10: 00 2e - 12: 73 68 73 74 csrrsi a6, mseccfg, 6 - 16: 72 74 - 18: 61 62 - 1a: 00 2e - 1c: 69 6e - 1e: 69 74 - 20: 00 2e - 22: 74 65 - 24: 78 74 - 26: 00 2e - 28: 72 6f - 2a: 64 61 - 2c: 74 61 - 2e: 00 2e - 30: 69 6e - 32: 69 74 - 34: 5f 61 72 72 - 38: 61 79 - 3a: 00 2e - 3c: 64 61 - 3e: 74 61 - 40: 00 2e - 42: 73 64 61 74 csrrsi s0, 1862, 2 - 46: 61 00 - 48: 2e 62 - 4a: 73 73 00 2e csrrci t1, 736, 0 - 4e: 63 6f 6d 6d bltu s10, s6, 0x72c <.symtab+0x72c> - 52: 65 6e - 54: 74 00 - 56: 2e 72 - 58: 69 73 - 5a: 63 76 2e 61 bgeu t3, s2, 0x666 <.symtab+0x666> - 5e: 74 74 - 60: 72 69 - 62: 62 75 - 64: 74 65 - 66: 73 00 2e 64 - 6a: 65 62 - 6c: 75 67 - 6e: 5f 61 72 61 - 72: 6e 67 - 74: 65 73 - 76: 00 2e - 78: 64 65 - 7a: 62 75 - 7c: 67 5f 69 6e - 80: 66 6f - 82: 00 2e - 84: 64 65 - 86: 62 75 - 88: 67 5f 61 62 - 8c: 62 72 - 8e: 65 76 - 90: 00 2e - 92: 64 65 - 94: 62 75 - 96: 67 5f 6c 69 - 9a: 6e 65 - 9c: 00 2e - 9e: 64 65 - a0: 62 75 - a2: 67 5f 66 72 - a6: 61 6d - a8: 65 00 - aa: 2e 64 - ac: 65 62 - ae: 75 67 - b0: 5f 73 74 72 - b4: 00 2e - b6: 64 65 - b8: 62 75 - ba: 67 5f 6c 6f - be: 63 6c 69 73 bltu s2, s6, 0x7f6 <.symtab+0x7f6> - c2: 74 73 - c4: 00 2e - c6: 64 65 - c8: 62 75 - ca: 67 5f 72 6e - ce: 67 6c 69 73 - d2: 74 73 - d4: 00 2e - d6: 64 65 - d8: 62 75 - da: 67 5f 6c 69 - de: 6e 65 - e0: 5f 73 74 72 - e4: 00 diff --git a/tests/opencl/fft/kernel.pocl b/tests/opencl/fft/kernel.pocl deleted file mode 100644 index 0923f2cd6835a2c775e4c5fdb2d8d384415153fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74401 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 H05JRy;4_00 From bd18b03cc33e97a060eef4bdd23493c2608c6e35 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 31 Dec 2023 15:29:04 -0800 Subject: [PATCH 40/57] minor update --- tests/opencl/fft/Makefile | 7 -- tests/opencl/fft/common.h | 3 - tests/opencl/fft/kernel.cl | 63 ---------- tests/opencl/fft/main.cc | 240 ------------------------------------- tests/opencl/fft/main.cc.o | Bin 15368 -> 0 bytes 5 files changed, 313 deletions(-) delete mode 100644 tests/opencl/fft/Makefile delete mode 100644 tests/opencl/fft/common.h delete mode 100644 tests/opencl/fft/kernel.cl delete mode 100644 tests/opencl/fft/main.cc delete mode 100644 tests/opencl/fft/main.cc.o diff --git a/tests/opencl/fft/Makefile b/tests/opencl/fft/Makefile deleted file mode 100644 index fd039b0e..00000000 --- a/tests/opencl/fft/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -PROJECT = fft4 - -SRCS = main.cc - -OPTS ?= -n32 - -include ../common.mk diff --git a/tests/opencl/fft/common.h b/tests/opencl/fft/common.h deleted file mode 100644 index 8c8e3344..00000000 --- a/tests/opencl/fft/common.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#define LOCAL_SIZE 16 \ No newline at end of file diff --git a/tests/opencl/fft/kernel.cl b/tests/opencl/fft/kernel.cl deleted file mode 100644 index 3e47282c..00000000 --- a/tests/opencl/fft/kernel.cl +++ /dev/null @@ -1,63 +0,0 @@ -#include "common.h" - -__kernel void fft_radix4(__global float2* input, __global float2* output, const unsigned int N) { - int globalId = get_global_id(0); - int localId = get_local_id(0); - int groupId = get_group_id(0); - - // Allocate local memory to store intermediate results and twiddle factors - __local float2 localData[LOCAL_SIZE]; - __local float2 twiddleFactors[LOCAL_SIZE / 4]; - - // Calculate twiddle factors for this FFT stage and store in local memory - if (localId < LOCAL_SIZE / 4) { - float angle = -2 * M_PI * localId / LOCAL_SIZE; - twiddleFactors[localId] = (float2)(cos(angle), sin(angle)); - } - barrier(CLK_LOCAL_MEM_FENCE); - - // Calculate the offset for the data this work-group will process - int offset = groupId * LOCAL_SIZE; - - // Load a chunk of input into local memory for faster access - if (globalId < N) { - localData[localId] = input[globalId]; - } - barrier(CLK_LOCAL_MEM_FENCE); - - // Perform the Radix-4 FFT on the data chunk in local memory - for (unsigned int stride = 1; stride < LOCAL_SIZE; stride *= 4) { - int twiddleIndex = (localId / stride) % 4; - float2 twiddle = twiddleFactors[twiddleIndex * (LOCAL_SIZE / (4 * stride))]; - - // Load data - float2 data0 = localData[localId]; - float2 data1 = localData[localId + stride]; - float2 data2 = localData[localId + 2 * stride]; - float2 data3 = localData[localId + 3 * stride]; - - // Apply twiddle factors - data1 *= twiddle; - data2 *= twiddle * twiddle; - data3 *= twiddle * twiddle * twiddle; - - // Radix-4 butterfly operations - float2 t0 = data0 + data2; - float2 t1 = data0 - data2; - float2 t2 = data1 + data3; - float2 t3 = (data1 - data3) * (float2)(0, -1); - - // Store results - localData[localId] = t0 + t2; - localData[localId + stride] = t1 + t3; - localData[localId + 2 * stride] = t0 - t2; - localData[localId + 3 * stride] = t1 - t3; - - barrier(CLK_LOCAL_MEM_FENCE); - } - - // Write the results back to global memory - if (globalId < N) { - output[globalId] = localData[localId]; - } -} diff --git a/tests/opencl/fft/main.cc b/tests/opencl/fft/main.cc deleted file mode 100644 index b10b225a..00000000 --- a/tests/opencl/fft/main.cc +++ /dev/null @@ -1,240 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" - -#define KERNEL_NAME "fft_radix4" - -#define FLOAT_ULP 6 - -struct float2 { - float x; - float y; - - float2(float real = 0.0f, float imag = 0.0f) : x(real), y(imag) {} - - float2 operator+(const float2& other) const { - return {x + other.x, y + other.y}; - } - - float2 operator-(const float2& other) const { - return {x - other.x, y - other.y}; - } - - float2 operator*(const float2& other) const { - return {x * other.x - y * other.y, x * other.y + y * other.x}; - } -}; - -#define CL_CHECK(_expr) \ - do { \ - cl_int _err = _expr; \ - if (_err == CL_SUCCESS) \ - break; \ - printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ - cleanup(); \ - exit(-1); \ - } while (0) - -#define CL_CHECK2(_expr) \ - ({ \ - cl_int _err = CL_INVALID_VALUE; \ - decltype(_expr) _ret = _expr; \ - if (_err != CL_SUCCESS) { \ - printf("OpenCL Error: '%s' returned %d!\n", #_expr, (int)_err); \ - cleanup(); \ - exit(-1); \ - } \ - _ret; \ - }) - -static int read_kernel_file(const char* filename, uint8_t** data, size_t* size) { - if (nullptr == filename || nullptr == data || 0 == size) - return -1; - - FILE* fp = fopen(filename, "r"); - if (NULL == fp) { - fprintf(stderr, "Failed to load kernel."); - return -1; - } - fseek(fp , 0 , SEEK_END); - long fsize = ftell(fp); - rewind(fp); - - *data = (uint8_t*)malloc(fsize); - *size = fread(*data, 1, fsize, fp); - - fclose(fp); - - return 0; -} - -static std::vector referenceDFT(const std::vector& input) { - std::vector output(input.size()); - for (unsigned int k = 0; k < input.size(); ++k) { // For each output element - output[k] = {0, 0}; // Initialize to zero - for (unsigned int n = 0; n < input.size(); ++n) { // For each input element - float angle = -2 * M_PI * k * n / input.size(); - float2 twiddle = {cos(angle), sin(angle)}; - output[k].x += input[n].x * twiddle.x - input[n].y * twiddle.y; - output[k].y += input[n].x * twiddle.y + input[n].y * twiddle.x; - } - } - return output; -} - -static int verifyOutput(const std::vector& output, - const std::vector& reference, - unsigned int N) { - int errors = 0; - for (unsigned int i = 0; i < N; ++i) { - float2 diff = {output[i].x - reference[i].x, output[i].y - reference[i].y}; - float error = sqrt(diff.x * diff.x + diff.y * diff.y); - if (error > 1e-5) { - printf("*** error: [%d] expected=(%f,%f), actual=(%f,%f)\n", i, reference[i].x, reference[i].y, output[i].x, output[i].y); - ++errors; - } - } - return errors; -} - -cl_device_id device_id = NULL; -cl_context context = NULL; -cl_command_queue commandQueue = NULL; -cl_program program = NULL; -cl_kernel kernel = NULL; -cl_mem i_memobj = NULL; -cl_mem o_memobj = NULL; -uint8_t *kernel_bin = NULL; - -static void cleanup() { - if (commandQueue) clReleaseCommandQueue(commandQueue); - if (kernel) clReleaseKernel(kernel); - if (program) clReleaseProgram(program); - if (i_memobj) clReleaseMemObject(i_memobj); - if (o_memobj) clReleaseMemObject(o_memobj); - if (context) clReleaseContext(context); - if (device_id) clReleaseDevice(device_id); - if (kernel_bin) free(kernel_bin); -} - -int size = 64; - -static void show_usage() { - printf("Usage: [-n size] [-h: help]\n"); -} - -static void parse_args(int argc, char **argv) { - int c; - while ((c = getopt(argc, argv, "n:h?")) != -1) { - switch (c) { - case 'n': - size = atoi(optarg); - break; - case 'h': - case '?': { - show_usage(); - exit(0); - } break; - default: - show_usage(); - exit(-1); - } - } - - printf("Workload size=%d\n", size); -} - -int main (int argc, char **argv) { - // parse command arguments - parse_args(argc, argv); - - cl_platform_id platform_id; - size_t kernel_size; - - // Getting platform and device information - CL_CHECK(clGetPlatformIDs(1, &platform_id, NULL)); - CL_CHECK(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL)); - - printf("Create context\n"); - context = CL_CHECK2(clCreateContext(NULL, 1, &device_id, NULL, NULL, &_err)); - - printf("Allocate device buffers\n"); - size_t nbytes = size * sizeof(float2); - i_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_READ_ONLY, nbytes, NULL, &_err)); - o_memobj = CL_CHECK2(clCreateBuffer(context, CL_MEM_WRITE_ONLY, nbytes, NULL, &_err)); - - printf("Create program from kernel source\n"); -#ifdef HOSTGPU - if (0 != read_kernel_file("kernel.cl", &kernel_bin, &kernel_size)) - return -1; - program = CL_CHECK2(clCreateProgramWithSource( - context, 1, (const char**)&kernel_bin, &kernel_size, &_err)); -#else - if (0 != read_kernel_file("kernel.pocl", &kernel_bin, &kernel_size)) - return -1; - program = CL_CHECK2(clCreateProgramWithBinary( - context, 1, &device_id, &kernel_size, (const uint8_t**)&kernel_bin, NULL, &_err)); -#endif - - // Build program - CL_CHECK(clBuildProgram(program, 1, &device_id, NULL, NULL, NULL)); - - // Create kernel - kernel = CL_CHECK2(clCreateKernel(program, KERNEL_NAME, &_err)); - - // Set kernel arguments - CL_CHECK(clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&i_memobj)); - CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&o_memobj)); - CL_CHECK(clSetKernelArg(kernel, 2, sizeof(int), (void *)&size)); - - // Allocate memories for input arrays and output arrays. - std::vector h_i(size); - std::vector h_o(size); - - // Generate input values - for (int i = 0; i < size; ++i) { - h_i[i].x = sin(2 * M_PI * i / size); // Sine wave as an example - h_i[i].y = 0.0f; // Zero imaginary part - } - - // Creating command queue - commandQueue = CL_CHECK2(clCreateCommandQueue(context, device_id, 0, &_err)); - - printf("Upload source buffers\n"); - CL_CHECK(clEnqueueWriteBuffer(commandQueue, i_memobj, CL_TRUE, 0, nbytes, h_i.data(), 0, NULL, NULL)); - - printf("Execute the kernel\n"); - size_t global_work_size[1] = {size}; - size_t local_work_size[1] = {LOCAL_SIZE}; - auto time_start = std::chrono::high_resolution_clock::now(); - CL_CHECK(clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL, global_work_size, local_work_size, 0, NULL, NULL)); - CL_CHECK(clFinish(commandQueue)); - auto time_end = std::chrono::high_resolution_clock::now(); - double elapsed = std::chrono::duration_cast(time_end - time_start).count(); - printf("Elapsed time: %lg ms\n", elapsed); - - printf("Download destination buffer\n"); - CL_CHECK(clEnqueueReadBuffer(commandQueue, o_memobj, CL_TRUE, 0, nbytes, h_o.data(), 0, NULL, NULL)); - - printf("Verify result\n"); - std::vector reference = referenceDFT(h_i); - auto errors = verifyOutput(h_o, reference, size); - if (0 == errors) { - printf("PASSED!\n"); - } else { - printf("FAILED! - %d errors\n", errors); - } - - // Clean up - cleanup(); - - return errors; -} diff --git a/tests/opencl/fft/main.cc.o b/tests/opencl/fft/main.cc.o deleted file mode 100644 index e3f30c90822ce9fddb7745f61c868737af43a331..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15368 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 Date: Wed, 3 Jan 2024 10:23:38 -0800 Subject: [PATCH 41/57] updated documentation --- docs/assets/img/cache_hierarchy.png | Bin 60885 -> 0 bytes docs/assets/img/cache_microarchitecture.png | Bin 0 -> 211805 bytes docs/assets/img/vortex_bank.png | Bin 79299 -> 0 bytes docs/assets/img/vortex_cache_top_module.png | Bin 68415 -> 0 bytes .../img/vortex_microarchitecture_v2.png | Bin 529641 -> 0 bytes docs/cache_subsystem.md | 77 ++++------------ docs/microarchitecture.md | 86 ++++++++---------- 7 files changed, 53 insertions(+), 110 deletions(-) delete mode 100644 docs/assets/img/cache_hierarchy.png create mode 100644 docs/assets/img/cache_microarchitecture.png delete mode 100644 docs/assets/img/vortex_bank.png delete mode 100644 docs/assets/img/vortex_cache_top_module.png delete mode 100644 docs/assets/img/vortex_microarchitecture_v2.png diff --git a/docs/assets/img/cache_hierarchy.png b/docs/assets/img/cache_hierarchy.png deleted file mode 100644 index 876f5fe28fc6e6a4bf327c275798eaf28ecb587a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60885 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 diff --git a/docs/assets/img/vortex_cache_top_module.png b/docs/assets/img/vortex_cache_top_module.png deleted file mode 100644 index ecb8be985bcd16488bea588019f5c9a40059c507..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68415 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 mPtferpKxBmtiPx@~F diff --git a/docs/assets/img/vortex_microarchitecture_v2.png b/docs/assets/img/vortex_microarchitecture_v2.png deleted file mode 100644 index c0e85891867a3e5dbe28a16ed913d54f6efe17f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 529641 zcmagFdHB;*`aX<`f*^_;I1Y$9f}()wnifG#(j-mOv`v$?Nl~#)lQd1*bV<{+EaHkY zIIbWr2%-a{3k)jisL011P!z=l7X}q%6PNcy=R2dne_pO!{Uj$RXL-)E+|PXu ze@-RHA%jjF)URK^AyhPy?$>X?-hTZKy>j4TpyUUcU)8T4#9O#vRUJh$2?>#Y;?j|C-2 zy>7@kxkziEcOu|}C-{P(_zXJAGx5=04BQ)y*d#du+WEwz$z=RM7H1s~Ti$K#ZsX$?beKS~m1*hb@BjLJ@y3 z3#JFIEQ@muJ2ggH+(GfZM!;@0 z!5!mI2D9ES5Bp1A!jplz0^iBS>!bjb3r&aGSq&(w+X@QQf)IjoujTD^9XKAgOR`by z7HpU>wo>u;pzl zUM?lZ4Sze^$l{heSw4pklaH;KSDm|ZM2^wsBB6?c0Tdr6v zMX%;E0dEtImMU<7E>=suj=$pzDo(Lo4tuPS9ZSP$sN}eeTffk_B`IZF)KdrPLA{a@_0V!r&{~6>dJIG?)-?MjCo4 z)2k_p-S#_P-#{VJ8YT) zZ;~mFWsyh>DaRu$&{8znF{D_ui?b3=)X{bnDO2GZ2~L~Xg(=` z4}xYZth9>`TmvOlUoPg@zIH(f$K4eHGAt+4WxI$td=b1)d1@h71#OQlb#0_%g-c2T zJeOo8m8gIZx<#O-ga^o*=+?n=2HdEYD;!r@J-womciXA8s?m5gMWROJ}RLymgXbx!yQlWg@ zUF)Llq?BBy%Xbo z(P69vMq$C_cvL8RjX*pAr5fh{z(5?_#tl{BrX4UZv2 z#1`ST6R?>JXuU>TmgG*PTgXLY7$$Wyp#rJ1IjL1W(BF(d8RZPcU1 z{Dz(<)NF?8m=&Yj_VaPFUK8U1!k0^OB96xCX3S`^)kKl2R!i}At)<#J&{VVvoE}D+*f!lOo_+Gak2;JPHgP1vmiB1^HORpRU)8 zE-+Ok7D(EjfGQF#@D9|^1{y81+l>|_JC&^}WRwmYWEzWPjl5AwbJa>z;!xG@^$<8! z3b}3}B2|c3HfR%F2CL-@i0*ME8^D`^vZm8Po3(QipDWse&#!vmUcJ*CN-s)+_Mt#M45j^iAuPx}IVkHrQ%Q7FIEXiX3rU5m z>7pdSt>rB`$rjv9xO}l}YU{y^mpnj~Jj$EZP=~4-wQ@yd z!1x%ANRpsuDoWRdUe>`_9&g|jmBSkeKSo!HIMtx_W(X4$j_Q!fnw)oxifFkCi(45T z5zU@MRqEksMre!@EXORZXR$X2^q=Bhh>~$&ghmXlFaYP`=PMA#bak z-~w2}{VX1dpk}ob<5MaQYdsK^E0K;=@qjf!$v8!ZC7}>%C3BLPG}Ts#tI{4$4TU?Q zTDw?@6rVu^ZZgrAYjx<>%p|+s9Kja~h469PORum(pP(gF}wnkB? zi@BT_mMK)in5<=>KvtAeL51P6FpGnAN3*V_hlnIiK|G2@D%l89)npdxwQB9If#{~> z6m%aN>u{-bxd9t`2cd%gdOHyghq;&pPyxXkjBRBahy><}!ucG6<%{8X!PcBcn`St- z5I_;vGl5?Tv%4u?bAfZlbT)xLwLmki;@9I!5+=-ygkg6u|OoS??QK}Z~1@)2{O(ope zU~8NdEF=|4B_hoRmC0%0G-#+;=e+G2CF)rsQl+YDQRJ9JGTQd#vs9D^oj^vy

id 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�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

  • TvdpjVnv15QvP5O6=_SaWQO+BS;&sFGY1v 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%0ABdp4L;W-M%5;)sH$TaEbs>a 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 z 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
      UD6i=kwZ&RmSTtyno6J|^Tc%-!;K}PV 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

      7c^E-Nm{auTqx%^KmqY_8X4%O-<+X}ZtrHLP?5 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 f!@OkY@ZdkA?DS<5b~9@pX8;0ES3j3^P6 Date: Wed, 10 Jan 2024 15:56:22 -0500 Subject: [PATCH 43/57] Docs update --- README.md | 1 + docs/environment_setup.md | 90 ++++++++++----------------- docs/index.md | 5 +- docs/install_vortex.md | 124 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 160 insertions(+), 60 deletions(-) create mode 100644 docs/install_vortex.md diff --git a/README.md b/README.md index 34343a28..0db8e2ea 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Vortex is a full-stack open-source RISC-V GPGPU. - `miscs`: Miscellaneous resources. ## Build Instructions +More detailed build instructions can be found [here](docs/install_vortex.md). ### Supported OS Platforms - Ubuntu 18.04 - Centos 7 diff --git a/docs/environment_setup.md b/docs/environment_setup.md index 1c15495f..a55060ee 100644 --- a/docs/environment_setup.md +++ b/docs/environment_setup.md @@ -1,71 +1,45 @@ -# Environment Setup# Vortex Dev Environment Setup -These instructions apply to the development vortex repo using the *updated toolchain*. The updated toolchain is considered to be any commit of `master` pulled from *July 2, 2023* onwards. The toolchain update in question can be viewed in this [commit](https://github.com/vortexgpgpu/vortex-dev/commit/0048496ba28d7b9a209a0e569d52d60f2b68fc04). Therefore, if you are unsure whether you are using the new toolchain or not, then you should check the `ci` folder for the existence of the `toolchain_prebuilt.sh` script. Furthermore, you should notice that the `toolchain_install.sh` script has the legacy `llvm()` split into `llvm-vortex()` and `llvm-pocl()`. +# Environment Setup +These instructions apply to the development vortex repo using the updated toolchain. The updated toolchain is considered to be any commit of `master` pulled from July 2, 2023 onwards. The toolchain update in question can be viewed in this [commit](https://github.com/vortexgpgpu/vortex-dev/commit/0048496ba28d7b9a209a0e569d52d60f2b68fc04). Therefore, if you are unsure whether you are using the new toolchain or not, then you should check the `ci` folder for the existence of the `toolchain_prebuilt.sh` script. Furthermore, you should notice that the `toolchain_install.sh` script has the legacy `llvm()` split into `llvm-vortex()` and `llvm-pocl()`. -> Note: As it stands right now, there a few test suites which are not working due to this toolchain migration. We are working to determine an exact list of which ones are working and which ones are not. For now, if the repo builds at a minimum, then you can consider all these steps to have worked successfully. -## Choosing an Development Environment -There are three primary environments you can use. Each has its own pros and cons. Refer to this section to help you determine which environment best suits your needs. -1. Volvo -2. Docker -3. Local +## Set Up on Your Own System +The toolchain binaries provided with Vortex are built on Ubuntu-based systems. To install Vortex on your own system, [follow these instructions](install_vortex.md). + +## Servers for Georgia Tech Students and Collaborators ### Volvo -Volvo is a server provided by Georgia Tech. As such, it provides high performance compute, but you need valid credentials to access it. If you don't already have credentials, you can get in contact with your mentor to ask about setting your account up. +Volvo is a 64-core server provided by HPArch. You need valid credentials to access it. If you don't already have access, you can get in contact with your mentor to ask about setting your account up. -Pros: +Setup on Volvo: +1. Connect to Georgia Tech's VPN or ssh into another machine on campus +2. `ssh volvo.cc.gatech.edu` +3. Clone Vortex to your home directory: `git clone --recursive https://github.com/vortexgpgpu/vortex.git` +4. `source /nethome/software/set_vortex_env.sh` to set up the necessary environment variables. +5. `make -s` in the `vortex` root directory +6. Run a test program: `./ci/blackbox.sh --cores=2 --app=dogfood` -1. Native x86_64 architecture, AMD EPYC 7702P 64-Core Processor (*fast*) -2. Packages and difficult configurations are already done for you -3. Consistent environment as others, allowing for easier troubleshooting -4. Just need to SSH into Volvo, minimal impact on local computer resources -5. VScode remote development tools are phenomenal over SSH +### Nio +Nio is a 20-core desktop server provided by HPArch. If you have access to Volvo, you also have access to Nio. -Cons: -1. Volvo is accessed via gatech vpn, external contributors might encounter issues with it -- especially from other university networks -2. Account creation is not immediate and is subject to processing time -3. Volvo might have outtages (*pretty uncommon*) -5. SSH development requires internet and other remote development tools (*vscode works!*) - -### Docker - -Docker allows for isolated pre-built environments to be created, shared and used. They are much more resource efficient than a Virtual Machine, and have great tooling and support available. The main motivation for Docker is bringing a consistent development environment to your local computer, across all platforms. - -Pros: - -1. If you are native to x86_64, the container will also run natively, yielding better performance. However, if you have aarch64 (arm) processor, you can still run the Docker container without configuration changes. -2. Consistent environment as others, allowing for easier troubleshooting -3. Works out of the box, just have a working installation of Docker -4. Vortex uses a build system, so once you build the repo once, only new code changes need to be recompiled -5. Docker offers helpful tools and extensions to monitor the performance of your container - -Cons: - -1. If you are using an arm processor, the container will be run in emulation mode, so it will inherently run slower, as it needs to translate all the x86_64 instructions. It's still usable on Apple Silicon, however. -2. Limited to your computer's performance, and Vortex is a large repo to build -3. Will utilize a few gigabytes of storage on your computer for saving binaries to run the container +Setup on Nio: +1. Connect to Georgia Tech's VPN or ssh into another machine on campus +2. `ssh nio.cc.gatech.edu` +3. Clone Vortex to your home directory: `git clone --recursive https://github.com/vortexgpgpu/vortex.git` +4. `source /opt/set_vortex_env_dev.sh` to set up the necessary environment variables. +5. `make -s` in the `vortex` root directory +6. Run a test program: `./ci/blackbox.sh --cores=2 --app=dogfood` -### Local -You can reverse engineer the Dockerfile and scripts above to get a working environment setup locally. This option is for experienced users, who have already considered the pros and cons of Volvo and Docker. +## Docker (Experimental) +Docker allows for isolated pre-built environments to be created, shared and used. The emulation mode required for ARM-based processors will incur a decrease in performance. Currently, the dockerfile is not included with the official vortex repository and is not actively maintained or supported. -## Setup on Volvo -1. Clone Repo Recursively: `git clone --recursive https://github.com/vortexgpgpu/vortex-dev.git` -2. Source `/opt/set_vortex_env_dev.sh` to initialize pre-installed toolchain -3. `make -s` in `vortex-dev` root directory -4. Run a test program: `./ci/blackbox.sh --cores=2 --app=dogfood` - -## Setup with Docker -Currently the Dockerfile is not included with the official vortex-dev repository, however you can quickly add it to repo and get started. -1. Clone repo recursively onto your local machine: `git clone --recursive https://github.com/vortexgpgpu/vortex-dev.git` -2. Download a copy of `Dockerfile.dev` and place it in the root of the repo. -3. Build the Dockerfile into an image: `docker build --platform=linux/amd64 -t vortex-dev -f Dockerfile.dev .` -4. Run a container based on the image: `docker run --rm -v ./:/root/vortex-dev/ -it --name vtx-dev --privileged=true --platform=linux/amd64 vortex-dev` +### Setup with Docker +1. Clone repo recursively onto your local machine: `git clone --recursive https://github.com/vortexgpgpu/vortex.git` +2. Download the dockerfile from [here](https://github.gatech.edu/gist/usubramanya3/f1bf3e953faa38a6372e1292ffd0b65c) and place it in the root of the repo. +3. Build the Dockerfile into an image: `docker build --platform=linux/amd64 -t vortex -f dockerfile .` +4. Run a container based on the image: `docker run --rm -v ./:/root/vortex/ -it --name vtx-dev --privileged=true --platform=linux/amd64 vortex` 5. Install the toolchain `./ci/toolchain_install.sh --all` (once per container) -6. `make -s` in `vortex-dev` root directory +6. `make -s` in `vortex` root directory 7. Run a test program: `./ci/blackbox.sh --cores=2 --app=dogfood` - -### Additional Docker Commands -- Exit from a container (does not stop or remove it) -- Resume a container you have exited or start a second terminal session `docker exec -it bash` - +You may exit from a container and resume a container you have exited or start a second terminal session `docker exec -it bash` diff --git a/docs/index.md b/docs/index.md index 19bbfa4d..07faa292 100644 --- a/docs/index.md +++ b/docs/index.md @@ -13,7 +13,8 @@ ## Installation -- Refer to the build instructions in [README](../README.md). +- For the different environments Vortex supports, [read this document](environment_setup.md). +- To install on your own system, [follow this document](install_vortex.md). ## Quick Start Scenarios @@ -28,4 +29,4 @@ Running Vortex simulators with different configurations: - Run dogfood driver test with simx driver and Vortex config of 4 cluster, 4 cores, 8 warps, 6 threads - $ ./ci/blackbox.sh --driver=simx --clusters=4 --cores=4 --warps=8 --threads=6 --app=dogfood \ No newline at end of file + $ ./ci/blackbox.sh --driver=simx --clusters=4 --cores=4 --warps=8 --threads=6 --app=dogfood diff --git a/docs/install_vortex.md b/docs/install_vortex.md new file mode 100644 index 00000000..80cdc426 --- /dev/null +++ b/docs/install_vortex.md @@ -0,0 +1,124 @@ +# Installing and Setting Up the Vortex Environment + +## Ubuntu 18.04, 20.04 + +1. Install the following dependencies: + + ``` + sudo apt-get install build-essential zlib1g-dev libtinfo-dev libncurses5 uuid-dev libboost-serialization-dev libpng-dev libhwloc-dev + ``` + +2. Upgrade gcc to 11: + + ``` + sudo apt-get install gcc-11 g++-11 + ``` + + Multiple gcc versions on Ubuntu can be managed with update-alternatives, e.g.: + + ``` + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 9 + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 9 + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 11 + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-11 11 + ``` + +3. Download the Vortex codebase: + + ``` + git clone --recursive https://github.com/vortexgpgpu/vortex.git + ``` + +4. Install Vortex's prebuilt toolchain: + + ``` + cd vortex + sudo ./ci/toolchain_install.sh -all + + # By default, the toolchain will install to /opt folder. This is recommended, but you can install the toolchain to a different directory by setting DESTDIR. + DESTDIR=$TOOLDIR ./ci/toolchain_install.sh -all + ``` + +5. Set up environment: + + ``` + export VORTEX_HOME=$TOOLDIR/vortex + export LLVM_VORTEX=$TOOLDIR/llvm-vortex + export LLVM_POCL=$TOOLDIR/llvm-pocl + export POCL_CC_PATH=$TOOLDIR/pocl/compiler + export POCL_RT_PATH=$TOOLDIR/pocl/runtime + export RISCV_TOOLCHAIN_PATH=$TOOLDIR/riscv-gnu-toolchain + export VERILATOR_ROOT=$TOOLDIR/verilator + export SV2V_PATH=$TOOLDIR/sv2v + export YOSYS_PATH=$TOOLDIR/yosys + + export PATH=$YOSYS_PATH/bin:$SV2V_PATH/bin:$VERILATOR_ROOT/bin:$PATH + ``` + +6. Build Vortex + + ``` + make + ``` + + +## RHEL 8 +Note: depending on the system, some of the toolchain may need to be recompiled for non-Ubuntu Linux. The source for the tools can be found [here](https://github.com/vortexgpgpu/). + +1. Install the following dependencies: + + ``` + sudo yum install libpng-devel boost boost-devel boost-serialization libuuid-devel opencl-headers hwloc hwloc-devel gmp-devel compat-hwloc1 + ``` + +2. Upgrade gcc to 11: + + ``` + sudo yum install gcc-toolset-11 + ``` + + Multiple gcc versions on Red Hat can be managed with scl + +3. Install MPFR 4.2.0: + + Download [the source](https://ftp.gnu.org/gnu/mpfr/) and follow [the installation documentation](https://www.mpfr.org/mpfr-current/mpfr.html#How-to-Install). + +4. Download the Vortex codebase: + + ``` + git clone --recursive https://github.com/vortexgpgpu/vortex.git + ``` + +5. Install Vortex's prebuilt toolchain: + + ``` + cd vortex + sudo ./ci/toolchain_install.sh -all + + # By default, the toolchain will install to /opt folder. This is recommended, but you can install the toolchain to a different directory by setting DESTDIR. + DESTDIR=$TOOLDIR ./ci/toolchain_install.sh -all + ``` + +6. Set up environment: + + ``` + export VORTEX_HOME=$TOOLDIR/vortex + export LLVM_VORTEX=$TOOLDIR/llvm-vortex + export LLVM_POCL=$TOOLDIR/llvm-pocl + export POCL_CC_PATH=$TOOLDIR/pocl/compiler + export POCL_RT_PATH=$TOOLDIR/pocl/runtime + export RISCV_TOOLCHAIN_PATH=$TOOLDIR/riscv-gnu-toolchain + export VERILATOR_ROOT=$TOOLDIR/verilator + export SV2V_PATH=$TOOLDIR/sv2v + export YOSYS_PATH=$TOOLDIR/yosys + + export PATH=$YOSYS_PATH/bin:$SV2V_PATH/bin:$VERILATOR_ROOT/bin:$PATH + + export LD_LIBRARY_PATH=/src/.libs:$LD_LIBRARY_PATH + ``` + +7. Build Vortex + + ``` + make + ``` From 38b92ad592555437c43848f071378c3cf48f94a3 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 28 Jan 2024 00:22:21 -0800 Subject: [PATCH 44/57] - using SV_DPI defines to disable DPI in synthesis-based simulations - fixed Intel ASE run script: run_ase.sh --- hw/rtl/VX_config.vh | 4 ++++ hw/rtl/VX_platform.vh | 2 +- hw/rtl/core/VX_dispatch.sv | 1 + hw/rtl/core/VX_schedule.sv | 9 ++++++++- hw/rtl/core/VX_trace.vh | 4 +--- hw/rtl/fpu/VX_fpu_define.vh | 2 +- hw/syn/altera/NOTEBOOK | 16 ++++++++-------- hw/syn/altera/opae/run_ase.sh | 23 ++++++++++++++--------- sim/opaesim/Makefile | 2 +- sim/rtlsim/Makefile | 2 +- 10 files changed, 40 insertions(+), 25 deletions(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 80ac5fef..23805dcf 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -191,6 +191,10 @@ `define STALL_TIMEOUT (100000 * (1 ** (`L2_ENABLED + `L3_ENABLED))) `endif +`ifndef SV_DPI +`define DPI_DISABLE +`endif + `ifndef FPU_FPNEW `ifndef FPU_DSP `ifndef FPU_DPI diff --git a/hw/rtl/VX_platform.vh b/hw/rtl/VX_platform.vh index 923ffa12..590b2b04 100644 --- a/hw/rtl/VX_platform.vh +++ b/hw/rtl/VX_platform.vh @@ -14,7 +14,7 @@ `ifndef VX_PLATFORM_VH `define VX_PLATFORM_VH -`ifndef SYNTHESIS +`ifdef SV_DPI `include "util_dpi.vh" `endif diff --git a/hw/rtl/core/VX_dispatch.sv b/hw/rtl/core/VX_dispatch.sv index 087c4080..61d857c5 100644 --- a/hw/rtl/core/VX_dispatch.sv +++ b/hw/rtl/core/VX_dispatch.sv @@ -12,6 +12,7 @@ // limitations under the License. `include "VX_define.vh" +`include "VX_trace.vh" module VX_dispatch import VX_gpu_pkg::*; #( parameter CORE_ID = 0 diff --git a/hw/rtl/core/VX_schedule.sv b/hw/rtl/core/VX_schedule.sv index 4f74af36..36bdf9e0 100644 --- a/hw/rtl/core/VX_schedule.sv +++ b/hw/rtl/core/VX_schedule.sv @@ -308,13 +308,20 @@ module VX_schedule import VX_gpu_pkg::*; #( localparam GNW_WIDTH = `LOG2UP(`NUM_CLUSTERS * `NUM_CORES * `NUM_WARPS); reg [`UUID_WIDTH-1:0] instr_uuid; wire [GNW_WIDTH-1:0] g_wid = (GNW_WIDTH'(CORE_ID) << `NW_BITS) + GNW_WIDTH'(schedule_wid); +`ifdef SV_DPI always @(posedge clk) begin if (reset) begin instr_uuid <= `UUID_WIDTH'(dpi_uuid_gen(1, 0, 0)); end else if (schedule_fire) begin instr_uuid <= `UUID_WIDTH'(dpi_uuid_gen(0, 32'(g_wid), 64'(schedule_pc))); - end + end end +`else + wire [GNW_WIDTH+16-1:0] w_uuid = {g_wid, 16'(schedule_pc)}; + always @(*) begin + instr_uuid = `UUID_WIDTH'(w_uuid); + end +`endif `else wire [`UUID_WIDTH-1:0] instr_uuid = '0; `endif diff --git a/hw/rtl/core/VX_trace.vh b/hw/rtl/core/VX_trace.vh index 1dea3347..ff2b3bb9 100644 --- a/hw/rtl/core/VX_trace.vh +++ b/hw/rtl/core/VX_trace.vh @@ -14,9 +14,7 @@ `ifndef VX_TRACE_VH `define VX_TRACE_VH -`ifndef SYNTHESIS - -`include "VX_define.vh" +`ifdef SIMULATION task trace_ex_type(input int level, input [`EX_BITS-1:0] ex_type); case (ex_type) diff --git a/hw/rtl/fpu/VX_fpu_define.vh b/hw/rtl/fpu/VX_fpu_define.vh index a72914ef..596db920 100644 --- a/hw/rtl/fpu/VX_fpu_define.vh +++ b/hw/rtl/fpu/VX_fpu_define.vh @@ -16,7 +16,7 @@ `include "VX_define.vh" -`ifndef SYNTHESIS +`ifdef SV_DPI `include "float_dpi.vh" `endif diff --git a/hw/syn/altera/NOTEBOOK b/hw/syn/altera/NOTEBOOK index 9b871546..7929e593 100644 --- a/hw/syn/altera/NOTEBOOK +++ b/hw/syn/altera/NOTEBOOK @@ -56,17 +56,17 @@ TARGET=asesim make -C runtime/opae PREFIX=build_base CONFIGS="-DEXT_F_DISABLE -DL1_DISABLE -DSM_DISABLE -DNUM_WARPS=2 -DNUM_THREADS=2" TARGET=asesim make # ASE test runs -./run_ase.sh build_base_arria10_asesim_1c/synth ../../../../tests/regression/basic/basic -n1 -t0 -./run_ase.sh build_base_arria10_asesim_1c/synth ../../../../tests/regression/basic/basic -n1 -t1 -./run_ase.sh build_base_arria10_asesim_1c/synth ../../../../tests/regression/basic/basic -n16 -./run_ase.sh build_base_arria10_asesim_1c/synth ../../../../tests/regression/demo/demo -n16 -./run_ase.sh build_base_arria10_asesim_1c/synth ../../../../tests/regression/dogfood/dogfood -n16 -./run_ase.sh build_base_arria10_asesim_1c/synth ../../../../tests/opencl/vecadd/vecadd -./run_ase.sh build_base_arria10_asesim_1c/synth ../../../../tests/opencl/sgemm/sgemm -n4 +./run_ase.sh build_base_arria10_asesim_1c ../../../../tests/regression/basic/basic -n1 -t0 +./run_ase.sh build_base_arria10_asesim_1c ../../../../tests/regression/basic/basic -n1 -t1 +./run_ase.sh build_base_arria10_asesim_1c ../../../../tests/regression/basic/basic -n16 +./run_ase.sh build_base_arria10_asesim_1c ../../../../tests/regression/demo/demo -n16 +./run_ase.sh build_base_arria10_asesim_1c ../../../../tests/regression/dogfood/dogfood -n16 +./run_ase.sh build_base_arria10_asesim_1c ../../../../tests/opencl/vecadd/vecadd +./run_ase.sh build_base_arria10_asesim_1c ../../../../tests/opencl/sgemm/sgemm -n4 # modify "vsim_run.tcl" to dump VCD trace vcd file trace.vcd -vcd add -r /*/Vortex/hw/rtl/* +vcd add -r /*/afu/* run -all # compress FPGA output files diff --git a/hw/syn/altera/opae/run_ase.sh b/hw/syn/altera/opae/run_ase.sh index ba30d209..16c92f45 100755 --- a/hw/syn/altera/opae/run_ase.sh +++ b/hw/syn/altera/opae/run_ase.sh @@ -15,27 +15,27 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -BUILD_DIR=$1 +BUILD_DIR=$(realpath $1) PROGRAM=$(basename "$2") PROGRAM_DIR=`dirname $2` +POCL_RT_PATH=$TOOLDIR/pocl/runtime VORTEX_RT_PATH=$SCRIPT_DIR/../../../../runtime # Export ASE_WORKDIR variable -export ASE_WORKDIR=$SCRIPT_DIR/$BUILD_DIR/work - -shift 2 +export ASE_WORKDIR=$BUILD_DIR/synth/work # cleanup incomplete runs rm -f $ASE_WORKDIR/.app_lock.pid rm -f $ASE_WORKDIR/.ase_ready.pid -rm -f $SCRIPT_DIR/$BUILD_DIR/nohup.out +rm -f $BUILD_DIR/synth/nohup.out -# Start Simulator in background -pushd $SCRIPT_DIR/$BUILD_DIR -echo " [DBG] starting ASE simnulator (stdout saved to '$SCRIPT_DIR/$BUILD_DIR/nohup.out')" -nohup make sim & +# Start Simulator in background (capture processs group pid) +pushd $BUILD_DIR/synth +echo " [DBG] starting ASE simnulator (stdout saved to '$BUILD_DIR/synth/nohup.out')" +setsid make sim &> /dev/null & +SIM_PID=$! popd # Wait for simulator readiness @@ -47,6 +47,11 @@ done # run application pushd $PROGRAM_DIR +shift 2 echo " [DBG] running ./$PROGRAM $*" ASE_LOG=0 LD_LIBRARY_PATH=$POCL_RT_PATH/lib:$VORTEX_RT_PATH/opae:$LD_LIBRARY_PATH ./$PROGRAM $* popd + +# stop the simulator (kill process group) +kill -- -$(ps -o pgid= $SIM_PID | grep -o '[0-9]*') +wait $SIM_PID 2> /dev/null \ No newline at end of file diff --git a/sim/opaesim/Makefile b/sim/opaesim/Makefile index 97c8aaf7..2b014711 100644 --- a/sim/opaesim/Makefile +++ b/sim/opaesim/Makefile @@ -75,7 +75,7 @@ TOP = vortex_afu_shim VL_FLAGS += --language 1800-2009 --assert -Wall -Wpedantic VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO VL_FLAGS += --x-initial unique --x-assign unique -VL_FLAGS += -DSIMULATION +VL_FLAGS += -DSIMULATION -DSV_DPI VL_FLAGS += -DXLEN_$(XLEN) VL_FLAGS += $(CONFIGS) VL_FLAGS += verilator.vlt diff --git a/sim/rtlsim/Makefile b/sim/rtlsim/Makefile index 3734a03b..d3a49fbb 100644 --- a/sim/rtlsim/Makefile +++ b/sim/rtlsim/Makefile @@ -56,7 +56,7 @@ VL_FLAGS += --language 1800-2009 --assert -Wall -Wpedantic VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO VL_FLAGS += --x-initial unique --x-assign unique VL_FLAGS += verilator.vlt -VL_FLAGS += -DSIMULATION +VL_FLAGS += -DSIMULATION -DSV_DPI VL_FLAGS += -DXLEN_$(XLEN) VL_FLAGS += $(CONFIGS) VL_FLAGS += $(RTL_INCLUDE) From b6919d19a71df112279dbb42a9e2a5294eb93f6b Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 28 Jan 2024 17:34:07 -0800 Subject: [PATCH 45/57] minor update --- hw/unittest/cache/Makefile | 2 +- hw/unittest/generic_queue/Makefile | 2 +- hw/unittest/mem_streamer/Makefile | 2 +- hw/unittest/top_modules/Makefile | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/unittest/cache/Makefile b/hw/unittest/cache/Makefile index e3737c3c..0d5da094 100644 --- a/hw/unittest/cache/Makefile +++ b/hw/unittest/cache/Makefile @@ -33,7 +33,7 @@ VL_FLAGS = --exe VL_FLAGS += --language 1800-2009 --assert -Wall -Wpedantic VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO VL_FLAGS += --x-initial unique --x-assign unique -VL_FLAGS += -DSIMULATION +VL_FLAGS += -DSIMULATION -DSV_DPI VL_FLAGS += $(CONFIGS) VL_FLAGS += $(PARAMS) VL_FLAGS += $(RTL_INCLUDE) diff --git a/hw/unittest/generic_queue/Makefile b/hw/unittest/generic_queue/Makefile index 9ec4baa1..c25bc006 100644 --- a/hw/unittest/generic_queue/Makefile +++ b/hw/unittest/generic_queue/Makefile @@ -27,7 +27,7 @@ VL_FLAGS = --exe VL_FLAGS += --language 1800-2009 --assert -Wall -Wpedantic VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO VL_FLAGS += --x-initial unique --x-assign unique -VL_FLAGS += -DSIMULATION +VL_FLAGS += -DSIMULATION -DSV_DPI VL_FLAGS += $(CONFIGS) VL_FLAGS += $(PARAMS) VL_FLAGS += $(RTL_INCLUDE) diff --git a/hw/unittest/mem_streamer/Makefile b/hw/unittest/mem_streamer/Makefile index 9ff5e81c..aa4b517a 100644 --- a/hw/unittest/mem_streamer/Makefile +++ b/hw/unittest/mem_streamer/Makefile @@ -27,7 +27,7 @@ VL_FLAGS = --exe VL_FLAGS += --language 1800-2009 --assert -Wall -Wpedantic VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO VL_FLAGS += --x-initial unique --x-assign unique -VL_FLAGS += -DSIMULATION +VL_FLAGS += -DSIMULATION -DSV_DPI VL_FLAGS += $(CONFIGS) VL_FLAGS += $(PARAMS) VL_FLAGS += $(RTL_INCLUDE) diff --git a/hw/unittest/top_modules/Makefile b/hw/unittest/top_modules/Makefile index 7445381e..72a403c5 100644 --- a/hw/unittest/top_modules/Makefile +++ b/hw/unittest/top_modules/Makefile @@ -25,7 +25,7 @@ VL_FLAGS = --exe VL_FLAGS += --language 1800-2009 --assert -Wall -Wpedantic VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO VL_FLAGS += --x-initial unique --x-assign unique -VL_FLAGS += -DSIMULATION +VL_FLAGS += -DSIMULATION -DSV_DPI VL_FLAGS += $(CONFIGS) VL_FLAGS += $(PARAMS) VL_FLAGS += $(RTL_INCLUDE) From fd65ed95eb38196c5b1f06f7db92447a985aff51 Mon Sep 17 00:00:00 2001 From: Shinnung Jeong Date: Tue, 30 Jan 2024 20:45:47 -0500 Subject: [PATCH 46/57] fix bug to access memory address in simx --- sim/simx/exe_unit.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sim/simx/exe_unit.cpp b/sim/simx/exe_unit.cpp index 4b5cb356..67834939 100644 --- a/sim/simx/exe_unit.cpp +++ b/sim/simx/exe_unit.cpp @@ -207,7 +207,7 @@ void LsuUnit::tick() { for (uint32_t t = 1; t < num_lanes_; ++t) { if (!trace->tmask.test(t0 + t)) continue; - auto mem_addr = trace_data->mem_addrs.at(t).addr & ~addr_mask; + auto mem_addr = trace_data->mem_addrs.at(t + t0).addr & ~addr_mask; matches += (addr0 == mem_addr); } #ifdef LSU_DUP_ENABLE @@ -229,7 +229,7 @@ void LsuUnit::tick() { continue; auto& dcache_req_port = core_->smem_demuxs_.at(t)->ReqIn; - auto mem_addr = trace_data->mem_addrs.at(t); + auto mem_addr = trace_data->mem_addrs.at(t + t0); auto type = core_->get_addr_type(mem_addr.addr); MemReq mem_req; @@ -324,4 +324,4 @@ void SfuUnit::tick() { break; // single block } ++input_idx_; -} \ No newline at end of file +} From e2d1387df805d6a0bcfdfe7f4983b39d51b7429f Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 31 Jan 2024 00:39:37 -0800 Subject: [PATCH 47/57] elastic buffers classification --- hw/rtl/libs/VX_bypass_buffer.sv | 31 +++++--- hw/rtl/libs/VX_elastic_buffer.sv | 35 ++++----- hw/rtl/libs/VX_pipe_buffer.sv | 63 +++++++++++++++ hw/rtl/libs/VX_skid_buffer.sv | 131 +++++++------------------------ hw/rtl/libs/VX_stream_buffer | 128 ++++++++++++++++++++++++++++++ hw/rtl/libs/VX_toggle_buffer.sv | 70 +++++++++++++++++ 6 files changed, 323 insertions(+), 135 deletions(-) create mode 100644 hw/rtl/libs/VX_pipe_buffer.sv create mode 100644 hw/rtl/libs/VX_stream_buffer create mode 100644 hw/rtl/libs/VX_toggle_buffer.sv diff --git a/hw/rtl/libs/VX_bypass_buffer.sv b/hw/rtl/libs/VX_bypass_buffer.sv index 7e723a45..4eefce44 100644 --- a/hw/rtl/libs/VX_bypass_buffer.sv +++ b/hw/rtl/libs/VX_bypass_buffer.sv @@ -11,6 +11,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +// A bypass elastic buffer operates at full bandwidth where pop can happen if the buffer is empty but is going full +// It has the following benefits: +// + Full-bandwidth throughput +// + use only one register for storage +// It has the following limitations: +// + data_out is not registered +// + ready_in and ready_out are coupled + `include "VX_platform.vh" `TRACING_OFF @@ -35,30 +43,27 @@ module VX_bypass_buffer #( assign data_out = data_in; end else begin reg [DATAW-1:0] buffer; - reg buffer_valid; + reg has_data; always @(posedge clk) begin if (reset) begin - buffer_valid <= 0; + has_data <= 0; end else begin if (ready_out) begin - buffer_valid <= 0; - end - if (valid_in && ~ready_out) begin - `ASSERT(!buffer_valid, ("runtime error")); - buffer_valid <= 1; + has_data <= 0; + end else if (~has_data) begin + has_data <= valid_in; end end - - if (valid_in && ~ready_out) begin + if (~has_data) begin buffer <= data_in; end end - assign ready_in = ready_out || !buffer_valid; - assign data_out = buffer_valid ? buffer : data_in; - assign valid_out = valid_in || buffer_valid; + assign ready_in = ready_out || ~has_data; + assign data_out = has_data ? buffer : data_in; + assign valid_out = valid_in || has_data; end endmodule -`TRACING_ON \ No newline at end of file +`TRACING_ON diff --git a/hw/rtl/libs/VX_elastic_buffer.sv b/hw/rtl/libs/VX_elastic_buffer.sv index 8cd8a3ab..c6af5197 100644 --- a/hw/rtl/libs/VX_elastic_buffer.sv +++ b/hw/rtl/libs/VX_elastic_buffer.sv @@ -42,34 +42,33 @@ module VX_elastic_buffer #( end else if (SIZE == 1) begin - wire stall = valid_out && ~ready_out; - - VX_pipe_register #( - .DATAW (1 + DATAW), - .RESETW (1) - ) pipe_register ( - .clk (clk), - .reset (reset), - .enable (~stall), - .data_in ({valid_in, data_in}), - .data_out ({valid_out, data_out}) + VX_pipe_buffer #( + .DATAW (DATAW) + ) pipe_buffer ( + .clk (clk), + .reset (reset), + .valid_in (valid_in), + .data_in (data_in), + .ready_in (ready_in), + .valid_out (valid_out), + .data_out (data_out), + .ready_out (ready_out) ); - assign ready_in = ~stall; - end else if (SIZE == 2) begin VX_skid_buffer #( .DATAW (DATAW), + .FULL_BW (OUT_REG != 2), .OUT_REG (OUT_REG) ) skid_buffer ( .clk (clk), .reset (reset), - .valid_in (valid_in), + .valid_in (valid_in), + .data_in (data_in), .ready_in (ready_in), - .data_in (data_in), - .data_out (data_out), .valid_out (valid_out), + .data_out (data_out), .ready_out (ready_out) ); @@ -111,10 +110,10 @@ module VX_elastic_buffer #( .clk (clk), .reset (reset), .valid_in (~empty), - .ready_in (ready_out_t), .data_in (data_out_t), - .data_out (data_out), + .ready_in (ready_out_t), .valid_out (valid_out), + .data_out (data_out), .ready_out (ready_out) ); diff --git a/hw/rtl/libs/VX_pipe_buffer.sv b/hw/rtl/libs/VX_pipe_buffer.sv new file mode 100644 index 00000000..dfdbc43c --- /dev/null +++ b/hw/rtl/libs/VX_pipe_buffer.sv @@ -0,0 +1,63 @@ +// Copyright 2024 blaise +// +// Licensed 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. + +// A pipelined elastic buffer operates at full bandwidth where push can happen if the buffer is not empty but is going empty +// It has the following benefits: +// + Full-bandwidth throughput +// + use only one register for storage +// + data_out is fully registered +// It has the following limitations: +// + ready_in and ready_out are coupled + +`include "VX_platform.vh" + +`TRACING_OFF +module VX_pipe_buffer #( + parameter DATAW = 1, + parameter PASSTHRU = 0 +) ( + input wire clk, + input wire reset, + input wire valid_in, + output wire ready_in, + input wire [DATAW-1:0] data_in, + output wire [DATAW-1:0] data_out, + input wire ready_out, + output wire valid_out +); + if (PASSTHRU != 0) begin + `UNUSED_VAR (clk) + `UNUSED_VAR (reset) + assign ready_in = ready_out; + assign valid_out = valid_in; + assign data_out = data_in; + end else begin + wire stall = valid_out && ~ready_out; + + VX_pipe_register #( + .DATAW (1 + DATAW), + .RESETW (1) + ) pipe_register ( + .clk (clk), + .reset (reset), + .enable (~stall), + .data_in ({valid_in, data_in}), + .data_out ({valid_out, data_out}) + ); + + assign ready_in = ~stall; + end + +endmodule +`TRACING_ON diff --git a/hw/rtl/libs/VX_skid_buffer.sv b/hw/rtl/libs/VX_skid_buffer.sv index a6876f5c..4816c1c2 100644 --- a/hw/rtl/libs/VX_skid_buffer.sv +++ b/hw/rtl/libs/VX_skid_buffer.sv @@ -17,6 +17,7 @@ module VX_skid_buffer #( parameter DATAW = 32, parameter PASSTHRU = 0, + parameter FULL_BW = 0, parameter OUT_REG = 0 ) ( input wire clk, @@ -30,8 +31,6 @@ module VX_skid_buffer #( input wire ready_out, output wire valid_out ); - `STATIC_ASSERT ((OUT_REG <= 2), ("invalid parameter")) - if (PASSTHRU != 0) begin `UNUSED_VAR (clk) @@ -41,112 +40,36 @@ module VX_skid_buffer #( assign data_out = data_in; assign ready_in = ready_out; - end else if (OUT_REG == 0) begin + end else if (FULL_BW != 0) begin - reg [1:0][DATAW-1:0] shift_reg; - reg valid_out_r, ready_in_r, rd_ptr_r; - - wire push = valid_in && ready_in; - wire pop = valid_out_r && ready_out; - - always @(posedge clk) begin - if (reset) begin - valid_out_r <= 0; - ready_in_r <= 1; - rd_ptr_r <= 1; - end else begin - if (push) begin - if (!pop) begin - ready_in_r <= rd_ptr_r; - valid_out_r <= 1; - end - end else if (pop) begin - ready_in_r <= 1; - valid_out_r <= rd_ptr_r; - end - rd_ptr_r <= rd_ptr_r ^ (push ^ pop); - end - end - - always @(posedge clk) begin - if (push) begin - shift_reg[1] <= shift_reg[0]; - shift_reg[0] <= data_in; - end - end - - assign ready_in = ready_in_r; - assign valid_out = valid_out_r; - assign data_out = shift_reg[rd_ptr_r]; - - end else if (OUT_REG == 1) begin - - // Full-bandwidth operation: input is consummed every cycle. - // However, data_out register has an additional multiplexer. - - reg [DATAW-1:0] data_out_r; - reg [DATAW-1:0] buffer; - reg valid_out_r; - reg use_buffer; - - wire push = valid_in && ready_in; - wire stall_out = valid_out_r && ~ready_out; - - always @(posedge clk) begin - if (reset) begin - valid_out_r <= 0; - use_buffer <= 0; - end else begin - if (ready_out) begin - use_buffer <= 0; - end else if (valid_in && valid_out) begin - use_buffer <= 1; - end - if (~stall_out) begin - valid_out_r <= valid_in || use_buffer; - end - end - end - - always @(posedge clk) begin - if (push) begin - buffer <= data_in; - end - if (~stall_out) begin - data_out_r <= use_buffer ? buffer : data_in; - end - end - - assign ready_in = ~use_buffer; - assign valid_out = valid_out_r; - assign data_out = data_out_r; + VX_stream_buffer #( + .DATAW (DATAW), + .OUT_REG (OUT_REG) + ) stream_buffer ( + .clk (clk), + .reset (reset), + .valid_in (valid_in), + .data_in (data_in), + .ready_in (ready_in), + .valid_out (valid_out), + .data_out (data_out), + .ready_out (ready_out) + ); end else begin - // Half-bandwidth operation: input is consummed every other cycle. - // However, data_out register has no additional multiplexer. - - reg [DATAW-1:0] data_out_r; - reg has_data; - - always @(posedge clk) begin - if (reset) begin - has_data <= 0; - end else begin - if (~has_data) begin - has_data <= valid_in; - end else if (ready_out) begin - has_data <= 0; - end - end - if (~has_data) begin - data_out_r <= data_in; - end - end - - assign ready_in = ~has_data; - assign valid_out = has_data; - assign data_out = data_out_r; + VX_toggle_buffer #( + .DATAW (DATAW) + ) toggle_buffer ( + .clk (clk), + .reset (reset), + .valid_in (valid_in), + .data_in (data_in), + .ready_in (ready_in), + .valid_out (valid_out), + .data_out (data_out), + .ready_out (ready_out) + ); end diff --git a/hw/rtl/libs/VX_stream_buffer b/hw/rtl/libs/VX_stream_buffer new file mode 100644 index 00000000..3bcc5d39 --- /dev/null +++ b/hw/rtl/libs/VX_stream_buffer @@ -0,0 +1,128 @@ +// Copyright 2024 blaise +// +// Licensed 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. + +// A stream elastic buffer operates at full-bandwidth where push and pop can happen simultaneously +// It has the following benefits: +// + full-bandwidth throughput +// + ready_in and ready_out are decoupled +// + data_out can be fully registered +// It has the following limitations: +// - requires two registers for storage + +`include "VX_platform.vh" + +`TRACING_OFF +module VX_stream_buffer #( + parameter DATAW = 1, + parameter OUT_REG = 0, + parameter PASSTHRU = 0 +) ( + input wire clk, + input wire reset, + input wire valid_in, + output wire ready_in, + input wire [DATAW-1:0] data_in, + output wire [DATAW-1:0] data_out, + input wire ready_out, + output wire valid_out +); + if (PASSTHRU != 0) begin + `UNUSED_VAR (clk) + `UNUSED_VAR (reset) + assign ready_in = ready_out; + assign valid_out = valid_in; + assign data_out = data_in; + end else begin + if (OUT_REG != 0) begin + + reg [DATAW-1:0] data_out_r; + reg [DATAW-1:0] buffer; + reg valid_out_r; + reg use_buffer; + + wire push = valid_in && ready_in; + wire stall_out = valid_out_r && ~ready_out; + + always @(posedge clk) begin + if (reset) begin + valid_out_r <= 0; + use_buffer <= 0; + end else begin + if (ready_out) begin + use_buffer <= 0; + end else if (valid_in && valid_out) begin + use_buffer <= 1; + end + if (~stall_out) begin + valid_out_r <= valid_in || use_buffer; + end + end + end + + always @(posedge clk) begin + if (push) begin + buffer <= data_in; + end + if (~stall_out) begin + data_out_r <= use_buffer ? buffer : data_in; + end + end + + assign ready_in = ~use_buffer; + assign valid_out = valid_out_r; + assign data_out = data_out_r; + + end else begin + + reg [1:0][DATAW-1:0] shift_reg; + reg valid_out_r, ready_in_r, rd_ptr_r; + + wire push = valid_in && ready_in; + wire pop = valid_out_r && ready_out; + + always @(posedge clk) begin + if (reset) begin + valid_out_r <= 0; + ready_in_r <= 1; + rd_ptr_r <= 1; + end else begin + if (push) begin + if (!pop) begin + ready_in_r <= rd_ptr_r; + valid_out_r <= 1; + end + end else if (pop) begin + ready_in_r <= 1; + valid_out_r <= rd_ptr_r; + end + rd_ptr_r <= rd_ptr_r ^ (push ^ pop); + end + end + + always @(posedge clk) begin + if (push) begin + shift_reg[1] <= shift_reg[0]; + shift_reg[0] <= data_in; + end + end + + assign ready_in = ready_in_r; + assign valid_out = valid_out_r; + assign data_out = shift_reg[rd_ptr_r]; + end + end + +endmodule +`TRACING_ON + diff --git a/hw/rtl/libs/VX_toggle_buffer.sv b/hw/rtl/libs/VX_toggle_buffer.sv new file mode 100644 index 00000000..e67a7d74 --- /dev/null +++ b/hw/rtl/libs/VX_toggle_buffer.sv @@ -0,0 +1,70 @@ +// Copyright 2024 blaise +// +// Licensed 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. + +// A toggle elastic buffer operates at half-bandwidth where push can only trigger after pop +// It has the following benefits: +// + use only one register for storage +// + ready_in and ready_out are decoupled +// + data_out is fully registered +// It has the following limitations: +// - Half-bandwidth throughput + +`include "VX_platform.vh" + +`TRACING_OFF +module VX_toggle_buffer #( + parameter DATAW = 1, + parameter PASSTHRU = 0 +) ( + input wire clk, + input wire reset, + input wire valid_in, + output wire ready_in, + input wire [DATAW-1:0] data_in, + output wire [DATAW-1:0] data_out, + input wire ready_out, + output wire valid_out +); + if (PASSTHRU != 0) begin + `UNUSED_VAR (clk) + `UNUSED_VAR (reset) + assign ready_in = ready_out; + assign valid_out = valid_in; + assign data_out = data_in; + end else begin + reg [DATAW-1:0] buffer; + reg has_data; + + always @(posedge clk) begin + if (reset) begin + has_data <= 0; + end else begin + if (~has_data) begin + has_data <= valid_in; + end else if (ready_out) begin + has_data <= 0; + end + end + if (~has_data) begin + buffer <= data_in; + end + end + + assign ready_in = ~has_data; + assign valid_out = has_data; + assign data_out = buffer; + end + +endmodule +`TRACING_ON From 8ab7c590fd2c48d7929cd0a486b34886571767ac Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 31 Jan 2024 06:16:54 -0800 Subject: [PATCH 48/57] disabling fetch's deadlock check when L1 caches are present --- hw/rtl/VX_define.vh | 7 +++++++ hw/rtl/core/VX_decode.sv | 3 ++- hw/rtl/core/VX_fetch.sv | 11 +++++++---- hw/rtl/core/VX_ibuffer.sv | 3 ++- hw/rtl/interfaces/VX_decode_if.sv | 13 +++++++++---- hw/rtl/interfaces/VX_fetch_if.sv | 11 ++++++++--- 6 files changed, 35 insertions(+), 13 deletions(-) diff --git a/hw/rtl/VX_define.vh b/hw/rtl/VX_define.vh index 63f2d42d..093a5fd2 100644 --- a/hw/rtl/VX_define.vh +++ b/hw/rtl/VX_define.vh @@ -291,6 +291,13 @@ /////////////////////////////////////////////////////////////////////////////// +`ifdef ICACHE_ENABLE +`define L1_ENABLE +`endif +`ifdef DCACHE_ENABLE +`define L1_ENABLE +`endif + `ifdef L2_ENABLE `define L2_LINE_SIZE `MEM_BLOCK_SIZE `else diff --git a/hw/rtl/core/VX_decode.sv b/hw/rtl/core/VX_decode.sv index 0032fe7b..0a6b00ec 100644 --- a/hw/rtl/core/VX_decode.sv +++ b/hw/rtl/core/VX_decode.sv @@ -533,8 +533,9 @@ module VX_decode #( assign decode_sched_if.valid = fetch_fire; assign decode_sched_if.wid = fetch_if.data.wid; assign decode_sched_if.is_wstall = is_wstall; - +`ifndef L1_ENABLE assign fetch_if.ibuf_pop = decode_if.ibuf_pop; +`endif `ifdef DBG_TRACE_CORE_PIPELINE always @(posedge clk) begin diff --git a/hw/rtl/core/VX_fetch.sv b/hw/rtl/core/VX_fetch.sv index ef52ef65..db5a1d73 100644 --- a/hw/rtl/core/VX_fetch.sv +++ b/hw/rtl/core/VX_fetch.sv @@ -32,7 +32,6 @@ module VX_fetch import VX_gpu_pkg::*; #( ); `UNUSED_PARAM (CORE_ID) `UNUSED_VAR (reset) - localparam ISW_WIDTH = `LOG2UP(`ISSUE_WIDTH); wire icache_req_valid; wire [ICACHE_ADDR_WIDTH-1:0] icache_req_addr; @@ -44,8 +43,6 @@ module VX_fetch import VX_gpu_pkg::*; #( wire icache_req_fire = icache_req_valid && icache_req_ready; - wire [ISW_WIDTH-1:0] schedule_isw = wid_to_isw(schedule_if.data.wid); - assign req_tag = schedule_if.data.wid; assign {rsp_uuid, rsp_tag} = icache_bus_if.rsp_data.tag; @@ -68,9 +65,12 @@ module VX_fetch import VX_gpu_pkg::*; #( .rdata ({rsp_PC, rsp_tmask}) ); +`ifndef L1_ENABLE // Ensure that the ibuffer doesn't fill up. // This resolves potential deadlock if ibuffer fills and the LSU stalls the execute stage due to pending dcache request. // This issue is particularly prevalent when the icache and dcache is disabled and both requests share the same bus. + wire [ISSUE_ISW-1:0] schedule_isw = wid_to_isw(schedule_if.data.wid); + wire [`ISSUE_WIDTH-1:0] pending_ibuf_full; for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin VX_pending_size #( @@ -85,13 +85,16 @@ module VX_fetch import VX_gpu_pkg::*; #( `UNUSED_PIN (empty) ); end + wire ibuf_ready = ~pending_ibuf_full[schedule_isw]; +`else + wire ibuf_ready = 1'b1; +`endif `RUNTIME_ASSERT((!schedule_if.valid || schedule_if.data.PC != 0), ("%t: *** invalid PC=0x%0h, wid=%0d, tmask=%b (#%0d)", $time, schedule_if.data.PC, schedule_if.data.wid, schedule_if.data.tmask, schedule_if.data.uuid)) // Icache Request - wire ibuf_ready = ~pending_ibuf_full[schedule_isw]; assign icache_req_valid = schedule_if.valid && ibuf_ready; assign icache_req_addr = schedule_if.data.PC[`MEM_ADDR_WIDTH-1:2]; assign icache_req_tag = {schedule_if.data.uuid, req_tag}; diff --git a/hw/rtl/core/VX_ibuffer.sv b/hw/rtl/core/VX_ibuffer.sv index b6847edc..b465c195 100644 --- a/hw/rtl/core/VX_ibuffer.sv +++ b/hw/rtl/core/VX_ibuffer.sv @@ -66,8 +66,9 @@ module VX_ibuffer import VX_gpu_pkg::*; #( .valid_out (ibuffer_if[i].valid), .ready_out(ibuffer_if[i].ready) ); - + `ifndef L1_ENABLE assign decode_if.ibuf_pop[i] = ibuffer_if[i].valid && ibuffer_if[i].ready; + `endif end endmodule diff --git a/hw/rtl/interfaces/VX_decode_if.sv b/hw/rtl/interfaces/VX_decode_if.sv index d433ca47..2a357abd 100644 --- a/hw/rtl/interfaces/VX_decode_if.sv +++ b/hw/rtl/interfaces/VX_decode_if.sv @@ -36,21 +36,26 @@ interface VX_decode_if (); logic valid; data_t data; logic ready; - - wire [`ISSUE_WIDTH-1:0] ibuf_pop; +`ifndef L1_ENABLE + logic [`ISSUE_WIDTH-1:0] ibuf_pop; +`endif modport master ( output valid, output data, - input ibuf_pop, input ready + `ifndef L1_ENABLE + , input ibuf_pop + `endif ); modport slave ( input valid, input data, - output ibuf_pop, output ready + `ifndef L1_ENABLE + , output ibuf_pop + `endif ); endinterface diff --git a/hw/rtl/interfaces/VX_fetch_if.sv b/hw/rtl/interfaces/VX_fetch_if.sv index 06b27d90..cbfecdd2 100644 --- a/hw/rtl/interfaces/VX_fetch_if.sv +++ b/hw/rtl/interfaces/VX_fetch_if.sv @@ -26,21 +26,26 @@ interface VX_fetch_if (); logic valid; data_t data; logic ready; - +`ifndef L1_ENABLE logic [`ISSUE_WIDTH-1:0] ibuf_pop; +`endif modport master ( output valid, output data, - input ibuf_pop, input ready + `ifndef L1_ENABLE + , input ibuf_pop + `endif ); modport slave ( input valid, input data, - output ibuf_pop, output ready + `ifndef L1_ENABLE + , output ibuf_pop + `endif ); endinterface From f9cd8be19efd72255870743f12e434e3fe3d5f4c Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 31 Jan 2024 13:35:43 -0800 Subject: [PATCH 49/57] minor update --- hw/rtl/libs/{VX_stream_buffer => VX_stream_buffer.sv} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename hw/rtl/libs/{VX_stream_buffer => VX_stream_buffer.sv} (100%) diff --git a/hw/rtl/libs/VX_stream_buffer b/hw/rtl/libs/VX_stream_buffer.sv similarity index 100% rename from hw/rtl/libs/VX_stream_buffer rename to hw/rtl/libs/VX_stream_buffer.sv From b0b7cd2b1e311858f8b7d8d5228efb35e5eeb5a4 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sat, 3 Feb 2024 19:09:53 -0800 Subject: [PATCH 50/57] minor updates --- README.md | 6 +++--- hw/rtl/VX_config.vh | 12 ++++++++++++ hw/rtl/VX_define.vh | 12 ------------ sim/simx/cluster.cpp | 8 ++++---- sim/simx/core.cpp | 2 +- sim/simx/execute.cpp | 6 +++--- sim/simx/main.cpp | 2 +- sim/simx/processor.cpp | 6 +++--- sim/simx/socket.cpp | 2 +- 9 files changed, 28 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 0db8e2ea..bca70da0 100644 --- a/README.md +++ b/README.md @@ -54,9 +54,9 @@ More detailed build instructions can be found [here](docs/install_vortex.md). $ git clone --recursive https://github.com/vortexgpgpu/vortex.git $ cd Vortex ### Install prebuilt toolchain - By default, the toolchain will install to /opt folder. - You can install the toolchain to a different directory by overriding TOOLDIR (e.g. export TOOLDIR=$HOME/tools). - + By default, the toolchain will install to /opt folder which requires sudo access. + You can install the toolchain to a different location of your choice by setting TOOLDIR (e.g. export TOOLDIR=$HOME/tools). + $ export TOOLDIR=/opt $ ./ci/toolchain_install.sh --all $ source ./ci/toolchain_env.sh ### Build Vortex sources diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 23805dcf..eed3cf54 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -136,6 +136,18 @@ `endif `endif +`ifdef L2_ENABLE +`define L2_LINE_SIZE `MEM_BLOCK_SIZE +`else +`define L2_LINE_SIZE `L1_LINE_SIZE +`endif + +`ifdef L3_ENABLE +`define L3_LINE_SIZE `MEM_BLOCK_SIZE +`else +`define L3_LINE_SIZE `L2_LINE_SIZE +`endif + `ifdef XLEN_64 `ifndef STARTUP_ADDR diff --git a/hw/rtl/VX_define.vh b/hw/rtl/VX_define.vh index 093a5fd2..996c769d 100644 --- a/hw/rtl/VX_define.vh +++ b/hw/rtl/VX_define.vh @@ -298,18 +298,6 @@ `define L1_ENABLE `endif -`ifdef L2_ENABLE -`define L2_LINE_SIZE `MEM_BLOCK_SIZE -`else -`define L2_LINE_SIZE `L1_LINE_SIZE -`endif - -`ifdef L3_ENABLE -`define L3_LINE_SIZE `MEM_BLOCK_SIZE -`else -`define L3_LINE_SIZE `L2_LINE_SIZE -`endif - `define VX_MEM_BYTEEN_WIDTH `L3_LINE_SIZE `define VX_MEM_ADDR_WIDTH (`MEM_ADDR_WIDTH - `CLOG2(`L3_LINE_SIZE)) `define VX_MEM_DATA_WIDTH (`L3_LINE_SIZE * 8) diff --git a/sim/simx/cluster.cpp b/sim/simx/cluster.cpp index 3ac80cb6..c632165a 100644 --- a/sim/simx/cluster.cpp +++ b/sim/simx/cluster.cpp @@ -62,10 +62,10 @@ Cluster::Cluster(const SimContext& ctx, snprintf(sname, 100, "cluster%d-l2cache", cluster_id); l2cache_ = CacheSim::Create(sname, CacheSim::Config{ !L2_ENABLED, - log2ceil(L2_CACHE_SIZE), // C - log2ceil(MEM_BLOCK_SIZE), // L - log2ceil(L2_NUM_WAYS), // W - 0, // A + log2ceil(L2_CACHE_SIZE),// C + log2ceil(MEM_BLOCK_SIZE),// L + log2ceil(L1_LINE_SIZE), // W + log2ceil(L2_NUM_WAYS), // A log2ceil(L2_NUM_BANKS), // B XLEN, // address bits 1, // number of ports diff --git a/sim/simx/core.cpp b/sim/simx/core.cpp index 1c155011..50137a9c 100644 --- a/sim/simx/core.cpp +++ b/sim/simx/core.cpp @@ -210,7 +210,7 @@ void Core::schedule() { void Core::fetch() { perf_stats_.ifetch_latency += pending_ifetches_; - // handle icache reponse + // handle icache response auto& icache_rsp_port = icache_rsp_ports.at(0); if (!icache_rsp_port.empty()){ auto& mem_rsp = icache_rsp_port.front(); diff --git a/sim/simx/execute.cpp b/sim/simx/execute.cpp index 52a95de1..4a8033d0 100644 --- a/sim/simx/execute.cpp +++ b/sim/simx/execute.cpp @@ -339,7 +339,7 @@ void Warp::execute(const Instr &instr, pipeline_trace_t *trace) { break; } case 1: { - // RV64I: SLLI + // RV32I: SLLI rddata[t].i = rsdata[t][0].i << immsrc; break; } @@ -360,11 +360,11 @@ void Warp::execute(const Instr &instr, pipeline_trace_t *trace) { } case 5: { if (func7) { - // RV64I: SRAI + // RV32I: SRAI Word result = rsdata[t][0].i >> immsrc; rddata[t].i = result; } else { - // RV64I: SRLI + // RV32I: SRLI Word result = rsdata[t][0].u >> immsrc; rddata[t].i = result; } diff --git a/sim/simx/main.cpp b/sim/simx/main.cpp index 64031bb8..b4dcf4ed 100644 --- a/sim/simx/main.cpp +++ b/sim/simx/main.cpp @@ -34,7 +34,7 @@ static void show_usage() { uint32_t num_threads = NUM_THREADS; uint32_t num_warps = NUM_WARPS; uint32_t num_cores = NUM_CORES; -bool showStats = false;; +bool showStats = false; bool riscv_test = false; const char* program = nullptr; diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index 8e8c1062..5382263e 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -33,8 +33,8 @@ ProcessorImpl::ProcessorImpl(const Arch& arch) !L3_ENABLED, log2ceil(L3_CACHE_SIZE), // C log2ceil(MEM_BLOCK_SIZE), // L - log2ceil(L3_NUM_WAYS), // W - 0, // A + log2ceil(L2_LINE_SIZE), // W + log2ceil(L3_NUM_WAYS), // A log2ceil(L3_NUM_BANKS), // B XLEN, // address bits 1, // number of ports @@ -58,7 +58,7 @@ ProcessorImpl::ProcessorImpl(const Arch& arch) l3cache_->CoreRspPorts.at(i).bind(&clusters_.at(i)->mem_rsp_port); } - // set up memory perf recording + // set up memory profiling memsim_->MemReqPort.tx_callback([&](const MemReq& req, uint64_t cycle){ __unused (cycle); perf_mem_reads_ += !req.write; diff --git a/sim/simx/socket.cpp b/sim/simx/socket.cpp index dd9f9697..092e89d0 100644 --- a/sim/simx/socket.cpp +++ b/sim/simx/socket.cpp @@ -44,7 +44,7 @@ Socket::Socket(const SimContext& ctx, XLEN, // address bits 1, // number of ports 1, // number of inputs - true, // write-through + false, // write-through false, // write response (uint8_t)arch.num_warps(), // mshr 2, // pipeline latency From fe15647f98d4fab96a38a07316a26cbfc4bfa82d Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 4 Feb 2024 02:11:53 -0800 Subject: [PATCH 51/57] minor update --- hw/rtl/core/VX_operands.sv | 71 +++++++++++++++++++----------------- hw/rtl/core/VX_scoreboard.sv | 62 +++++++++++++++---------------- 2 files changed, 66 insertions(+), 67 deletions(-) diff --git a/hw/rtl/core/VX_operands.sv b/hw/rtl/core/VX_operands.sv index ee0c493b..3747502f 100644 --- a/hw/rtl/core/VX_operands.sv +++ b/hw/rtl/core/VX_operands.sv @@ -47,8 +47,6 @@ module VX_operands import VX_gpu_pkg::*; #( reg [`NUM_THREADS-1:0] cache_tmask_n [ISSUE_RATIO-1:0]; reg [ISSUE_RATIO-1:0] cache_eop, cache_eop_n; - reg valid_out_r; - reg [DATAW-1:0] data_out_r; reg [`NUM_THREADS-1:0][`XLEN-1:0] rs1_data, rs1_data_n; reg [`NUM_THREADS-1:0][`XLEN-1:0] rs2_data, rs2_data_n; reg [`NUM_THREADS-1:0][`XLEN-1:0] rs3_data, rs3_data_n; @@ -60,7 +58,7 @@ module VX_operands import VX_gpu_pkg::*; #( reg rs3_ready, rs3_ready_n; reg data_ready, data_ready_n; - wire ready_out = operands_if[i].ready; + wire stg_valid_in, stg_ready_in; wire is_rs1_zero = (scoreboard_if[i].data.rs1 == 0); wire is_rs2_zero = (scoreboard_if[i].data.rs2 == 0); @@ -85,7 +83,7 @@ module VX_operands import VX_gpu_pkg::*; #( case (state) STATE_IDLE: begin - if (valid_out_r && ready_out) begin + if (operands_if[i].valid && operands_if[i].ready) begin data_ready_n = 0; end if (scoreboard_if[i].valid && data_ready_n == 0) begin @@ -173,37 +171,15 @@ module VX_operands import VX_gpu_pkg::*; #( end always @(posedge clk) begin - if (reset) begin + if (reset) begin state <= STATE_IDLE; cache_eop <= {ISSUE_RATIO{1'b1}}; data_ready <= 0; - valid_out_r <= 0; end else begin state <= state_n; cache_eop <= cache_eop_n; - data_ready <= data_ready_n; - if (~valid_out_r) begin - valid_out_r <= scoreboard_if[i].valid && data_ready; - end else if (ready_out) begin - valid_out_r <= 0; - end + data_ready <= data_ready_n; end - - if (~valid_out_r) begin - data_out_r <= {scoreboard_if[i].data.uuid, - scoreboard_if[i].data.wis, - scoreboard_if[i].data.tmask, - scoreboard_if[i].data.PC, - scoreboard_if[i].data.wb, - scoreboard_if[i].data.ex_type, - scoreboard_if[i].data.op_type, - scoreboard_if[i].data.op_mod, - scoreboard_if[i].data.use_PC, - scoreboard_if[i].data.use_imm, - scoreboard_if[i].data.imm, - scoreboard_if[i].data.rd}; - end - gpr_rd_rid <= gpr_rd_rid_n; gpr_rd_wis <= gpr_rd_wis_n; rs2_ready <= rs2_ready_n; @@ -216,10 +192,35 @@ module VX_operands import VX_gpu_pkg::*; #( cache_data <= cache_data_n; cache_reg <= cache_reg_n; cache_tmask <= cache_tmask_n; - end + end - assign operands_if[i].valid = valid_out_r; - assign {operands_if[i].data.uuid, + assign stg_valid_in = scoreboard_if[i].valid && data_ready; + assign scoreboard_if[i].ready = stg_ready_in && data_ready; + + VX_toggle_buffer #( + .DATAW (DATAW) + ) staging_buffer ( + .clk (clk), + .reset (reset), + .valid_in (stg_valid_in), + .data_in ({ + scoreboard_if[i].data.uuid, + scoreboard_if[i].data.wis, + scoreboard_if[i].data.tmask, + scoreboard_if[i].data.PC, + scoreboard_if[i].data.wb, + scoreboard_if[i].data.ex_type, + scoreboard_if[i].data.op_type, + scoreboard_if[i].data.op_mod, + scoreboard_if[i].data.use_PC, + scoreboard_if[i].data.use_imm, + scoreboard_if[i].data.imm, + scoreboard_if[i].data.rd + }), + .ready_in (stg_ready_in), + .valid_out (operands_if[i].valid), + .data_out ({ + operands_if[i].data.uuid, operands_if[i].data.wis, operands_if[i].data.tmask, operands_if[i].data.PC, @@ -230,13 +231,15 @@ module VX_operands import VX_gpu_pkg::*; #( operands_if[i].data.use_PC, operands_if[i].data.use_imm, operands_if[i].data.imm, - operands_if[i].data.rd} = data_out_r; + operands_if[i].data.rd + }), + .ready_out (operands_if[i].ready) + ); + assign operands_if[i].data.rs1_data = rs1_data; assign operands_if[i].data.rs2_data = rs2_data; assign operands_if[i].data.rs3_data = rs3_data; - assign scoreboard_if[i].ready = ~valid_out_r && data_ready; - // GPR banks reg [RAM_ADDRW-1:0] gpr_rd_addr; diff --git a/hw/rtl/core/VX_scoreboard.sv b/hw/rtl/core/VX_scoreboard.sv index a4792c8d..6b806dd0 100644 --- a/hw/rtl/core/VX_scoreboard.sv +++ b/hw/rtl/core/VX_scoreboard.sv @@ -152,51 +152,47 @@ module VX_scoreboard import VX_gpu_pkg::*; #( assign perf_issue_stalls_per_cycle[i] = ibuffer_if[i].valid && ~ibuffer_if[i].ready; `endif - reg [DATAW-1:0] data_out_r; - reg valid_out_r; - wire ready_out; + wire [3:0] operands_busy = {inuse_rd, inuse_rs1, inuse_rs2, inuse_rs3}; + wire operands_ready = ~(| operands_busy); + + wire stg_valid_in, stg_ready_in; + assign stg_valid_in = ibuffer_if[i].valid && operands_ready; + assign ibuffer_if[i].ready = stg_ready_in && operands_ready; - wire [3:0] ready_masks = ~{inuse_rd, inuse_rs1, inuse_rs2, inuse_rs3}; - wire deps_ready = (& ready_masks); - - wire valid_in = ibuffer_if[i].valid && deps_ready; - wire ready_in = ~valid_out_r && deps_ready; - wire [DATAW-1:0] data_in = ibuffer_if[i].data; - - assign ready_out = scoreboard_if[i].ready; + VX_stream_buffer #( + .DATAW (DATAW) + ) staging_buffer ( + .clk (clk), + .reset (reset), + .valid_in (stg_valid_in), + .data_in (ibuffer_if[i].data), + .ready_in (stg_ready_in), + .valid_out (scoreboard_if[i].valid), + .data_out (scoreboard_if[i].data), + .ready_out (scoreboard_if[i].ready) + ); always @(posedge clk) begin if (reset) begin - valid_out_r <= 0; inuse_regs <= '0; end else begin if (writeback_fire) begin inuse_regs[writeback_if[i].data.wis][writeback_if[i].data.rd] <= 0; end - if (~valid_out_r) begin - valid_out_r <= valid_in; - end else if (ready_out) begin - if (scoreboard_if[i].data.wb) begin - inuse_regs[scoreboard_if[i].data.wis][scoreboard_if[i].data.rd] <= 1; - `ifdef PERF_ENABLE - inuse_units[scoreboard_if[i].data.wis][scoreboard_if[i].data.rd] <= scoreboard_if[i].data.ex_type; - if (scoreboard_if[i].data.ex_type == `EX_SFU) begin - inuse_sfu[scoreboard_if[i].data.wis][scoreboard_if[i].data.rd] <= sfu_type; - end - `endif - end - valid_out_r <= 0; + if (stg_valid_in && stg_ready_in && ibuffer_if[i].data.wb) begin + inuse_regs[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd] <= 1; end end - if (~valid_out_r) begin - data_out_r <= data_in; + `ifdef PERF_ENABLE + if (stg_valid_in && stg_ready_in && ibuffer_if[i].data.wb) begin + inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd] <= ibuffer_if[i].data.ex_type; + if (ibuffer_if[i].data.ex_type == `EX_SFU) begin + inuse_sfu[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd] <= sfu_type; + end end + `endif end - assign ibuffer_if[i].ready = ready_in; - assign scoreboard_if[i].valid = valid_out_r; - assign scoreboard_if[i].data = data_out_r; - `ifdef SIMULATION reg [31:0] timeout_ctr; @@ -208,7 +204,7 @@ module VX_scoreboard import VX_gpu_pkg::*; #( `ifdef DBG_TRACE_CORE_PIPELINE `TRACE(3, ("%d: *** core%0d-scoreboard-stall: wid=%0d, PC=0x%0h, tmask=%b, cycles=%0d, inuse=%b (#%0d)\n", $time, CORE_ID, wis_to_wid(ibuffer_if[i].data.wis, i), ibuffer_if[i].data.PC, ibuffer_if[i].data.tmask, timeout_ctr, - ~ready_masks, ibuffer_if[i].data.uuid)); + operands_busy, ibuffer_if[i].data.uuid)); `endif timeout_ctr <= timeout_ctr + 1; end else if (ibuffer_if[i].valid && ibuffer_if[i].ready) begin @@ -220,7 +216,7 @@ module VX_scoreboard import VX_gpu_pkg::*; #( `RUNTIME_ASSERT((timeout_ctr < `STALL_TIMEOUT), ("%t: *** core%0d-scoreboard-timeout: wid=%0d, PC=0x%0h, tmask=%b, cycles=%0d, inuse=%b (#%0d)", $time, CORE_ID, wis_to_wid(ibuffer_if[i].data.wis, i), ibuffer_if[i].data.PC, ibuffer_if[i].data.tmask, timeout_ctr, - ~ready_masks, ibuffer_if[i].data.uuid)); + operands_busy, ibuffer_if[i].data.uuid)); `RUNTIME_ASSERT(~writeback_fire || inuse_regs[writeback_if[i].data.wis][writeback_if[i].data.rd] != 0, ("%t: *** core%0d: invalid writeback register: wid=%0d, PC=0x%0h, tmask=%b, rd=%0d (#%0d)", From 6f7a389a1f642ec205401c3f54c1a4c4bdfc798e Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 4 Feb 2024 20:16:18 -0800 Subject: [PATCH 52/57] arbiters unlock refactoring --- hw/rtl/cache/VX_cache_bypass.sv | 12 +++++----- hw/rtl/libs/VX_cyclic_arbiter.sv | 11 ++++------ hw/rtl/libs/VX_fair_arbiter.sv | 12 ++++------ hw/rtl/libs/VX_generic_arbiter.sv | 35 +++++++++++++++--------------- hw/rtl/libs/VX_matrix_arbiter.sv | 14 ++++++------ hw/rtl/libs/VX_mem_rsp_sel.sv | 16 ++++++++------ hw/rtl/libs/VX_priority_arbiter.sv | 13 ++--------- hw/rtl/libs/VX_rr_arbiter.sv | 26 +++++++++++----------- hw/rtl/libs/VX_stream_arb.sv | 27 +++++++++-------------- hw/rtl/libs/VX_stream_xbar.sv | 5 +---- 10 files changed, 74 insertions(+), 97 deletions(-) diff --git a/hw/rtl/cache/VX_cache_bypass.sv b/hw/rtl/cache/VX_cache_bypass.sv index 4a281f19..d10f47e0 100644 --- a/hw/rtl/cache/VX_cache_bypass.sv +++ b/hw/rtl/cache/VX_cache_bypass.sv @@ -130,20 +130,20 @@ module VX_cache_bypass #( assign core_req_valid_in_nc = core_req_valid_in & core_req_nc_idxs; - wire core_req_in_fire = | (core_req_valid_in & core_req_ready_in); + wire core_req_nc_ready = ~mem_req_valid_in && mem_req_ready_out; VX_generic_arbiter #( .NUM_REQS (NUM_REQS), .TYPE (PASSTHRU ? "R" : "P"), .LOCK_ENABLE (1) - ) req_arb ( + ) core_req_nc_arb ( .clk (clk), - .reset (reset), - .unlock (core_req_in_fire), + .reset (reset), .requests (core_req_valid_in_nc), .grant_index (core_req_nc_idx), .grant_onehot (core_req_nc_sel), - .grant_valid (core_req_nc_valid) + .grant_valid (core_req_nc_valid), + .grant_unlock (core_req_nc_ready) ); assign core_req_valid_out = core_req_valid_in & ~core_req_nc_idxs; @@ -164,7 +164,7 @@ module VX_cache_bypass #( end for (genvar i = 0; i < NUM_REQS; ++i) begin - assign core_req_ready_in[i] = core_req_valid_in_nc[i] ? (~mem_req_valid_in && mem_req_ready_out && core_req_nc_sel[i]) + assign core_req_ready_in[i] = core_req_valid_in_nc[i] ? (core_req_nc_ready && core_req_nc_sel[i]) : core_req_ready_out[i]; end diff --git a/hw/rtl/libs/VX_cyclic_arbiter.sv b/hw/rtl/libs/VX_cyclic_arbiter.sv index cd7d91f9..63b62136 100644 --- a/hw/rtl/libs/VX_cyclic_arbiter.sv +++ b/hw/rtl/libs/VX_cyclic_arbiter.sv @@ -21,15 +21,12 @@ module VX_cyclic_arbiter #( ) ( input wire clk, input wire reset, - input wire [NUM_REQS-1:0] requests, - input wire unlock, + input wire [NUM_REQS-1:0] requests, output wire [LOG_NUM_REQS-1:0] grant_index, output wire [NUM_REQS-1:0] grant_onehot, - output wire grant_valid + output wire grant_valid, + input wire grant_unlock ); - `UNUSED_PARAM (LOCK_ENABLE) - `UNUSED_VAR (unlock) - if (NUM_REQS == 1) begin `UNUSED_VAR (clk) @@ -51,7 +48,7 @@ module VX_cyclic_arbiter #( end else begin if (!IS_POW2 && grant_index_r == LOG_NUM_REQS'(NUM_REQS-1)) begin grant_index_r <= '0; - end else begin + end else if (!LOCK_ENABLE || ~grant_valid || grant_unlock) begin grant_index_r <= grant_index_r + LOG_NUM_REQS'(1); end end diff --git a/hw/rtl/libs/VX_fair_arbiter.sv b/hw/rtl/libs/VX_fair_arbiter.sv index c1b1a4b7..acc01971 100644 --- a/hw/rtl/libs/VX_fair_arbiter.sv +++ b/hw/rtl/libs/VX_fair_arbiter.sv @@ -21,17 +21,17 @@ module VX_fair_arbiter #( ) ( input wire clk, input wire reset, - input wire unlock, input wire [NUM_REQS-1:0] requests, output wire [LOG_NUM_REQS-1:0] grant_index, output wire [NUM_REQS-1:0] grant_onehot, - output wire grant_valid + output wire grant_valid, + input wire grant_unlock ); if (NUM_REQS == 1) begin `UNUSED_VAR (clk) `UNUSED_VAR (reset) - `UNUSED_VAR (unlock) + `UNUSED_VAR (grant_unlock) assign grant_index = '0; assign grant_onehot = requests; @@ -48,18 +48,14 @@ module VX_fair_arbiter #( always @(posedge clk) begin if (reset) begin buffer <= '0; - end else if (!LOCK_ENABLE || unlock) begin + end else if (!LOCK_ENABLE || grant_unlock) begin buffer <= buffer_n; end end VX_priority_arbiter #( .NUM_REQS (NUM_REQS), - .LOCK_ENABLE (LOCK_ENABLE) ) priority_arbiter ( - .clk (clk), - .reset (reset), - .unlock (unlock), .requests (requests_qual), .grant_index (grant_index), .grant_onehot (grant_onehot), diff --git a/hw/rtl/libs/VX_generic_arbiter.sv b/hw/rtl/libs/VX_generic_arbiter.sv index adeefc7d..2b7922d9 100644 --- a/hw/rtl/libs/VX_generic_arbiter.sv +++ b/hw/rtl/libs/VX_generic_arbiter.sv @@ -21,22 +21,23 @@ module VX_generic_arbiter #( parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS) ) ( input wire clk, - input wire reset, - input wire unlock, + input wire reset, input wire [NUM_REQS-1:0] requests, output wire [LOG_NUM_REQS-1:0] grant_index, output wire [NUM_REQS-1:0] grant_onehot, - output wire grant_valid + output wire grant_valid, + input wire grant_unlock ); if (TYPE == "P") begin + `UNUSED_PARAM (LOCK_ENABLE) + `UNUSED_VAR (clk) + `UNUSED_VAR (reset) + `UNUSED_VAR (grant_unlock) + VX_priority_arbiter #( - .NUM_REQS (NUM_REQS), - .LOCK_ENABLE (LOCK_ENABLE) + .NUM_REQS (NUM_REQS), ) priority_arbiter ( - .clk (clk), - .reset (reset), - .unlock (unlock), .requests (requests), .grant_valid (grant_valid), .grant_index (grant_index), @@ -50,12 +51,12 @@ module VX_generic_arbiter #( .LOCK_ENABLE (LOCK_ENABLE) ) rr_arbiter ( .clk (clk), - .reset (reset), - .unlock (unlock), + .reset (reset), .requests (requests), .grant_valid (grant_valid), .grant_index (grant_index), - .grant_onehot (grant_onehot) + .grant_onehot (grant_onehot), + .grant_unlock (grant_unlock) ); end else if (TYPE == "F") begin @@ -66,11 +67,11 @@ module VX_generic_arbiter #( ) fair_arbiter ( .clk (clk), .reset (reset), - .unlock (unlock), .requests (requests), .grant_valid (grant_valid), .grant_index (grant_index), - .grant_onehot (grant_onehot) + .grant_onehot (grant_onehot), + .grant_unlock (grant_unlock) ); end else if (TYPE == "M") begin @@ -81,11 +82,11 @@ module VX_generic_arbiter #( ) matrix_arbiter ( .clk (clk), .reset (reset), - .unlock (unlock), .requests (requests), .grant_valid (grant_valid), .grant_index (grant_index), - .grant_onehot (grant_onehot) + .grant_onehot (grant_onehot), + .grant_unlock (grant_unlock) ); end else if (TYPE == "C") begin @@ -96,11 +97,11 @@ module VX_generic_arbiter #( ) cyclic_arbiter ( .clk (clk), .reset (reset), - .unlock (unlock), .requests (requests), .grant_valid (grant_valid), .grant_index (grant_index), - .grant_onehot (grant_onehot) + .grant_onehot (grant_onehot), + .grant_unlock (grant_unlock) ); end else begin diff --git a/hw/rtl/libs/VX_matrix_arbiter.sv b/hw/rtl/libs/VX_matrix_arbiter.sv index e076e06e..9333c1ac 100644 --- a/hw/rtl/libs/VX_matrix_arbiter.sv +++ b/hw/rtl/libs/VX_matrix_arbiter.sv @@ -20,18 +20,18 @@ module VX_matrix_arbiter #( parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS) ) ( input wire clk, - input wire reset, - input wire unlock, + input wire reset, input wire [NUM_REQS-1:0] requests, output wire [LOG_NUM_REQS-1:0] grant_index, output wire [NUM_REQS-1:0] grant_onehot, - output wire grant_valid + output wire grant_valid, + input wire grant_unlock ); if (NUM_REQS == 1) begin `UNUSED_VAR (clk) `UNUSED_VAR (reset) - `UNUSED_VAR (unlock) + `UNUSED_VAR (grant_unlock) assign grant_index = '0; assign grant_onehot = requests; @@ -71,18 +71,18 @@ module VX_matrix_arbiter #( end if (LOCK_ENABLE == 0) begin - `UNUSED_VAR (unlock) + `UNUSED_VAR (grant_unlock) assign grant_onehot = grant_unqual; end else begin reg [NUM_REQS-1:0] grant_unqual_prev; always @(posedge clk) begin if (reset) begin grant_unqual_prev <= '0; - end else if (unlock) begin + end else if (grant_unlock) begin grant_unqual_prev <= grant_unqual; end end - assign grant_onehot = unlock ? grant_unqual : grant_unqual_prev; + assign grant_onehot = grant_unlock ? grant_unqual : grant_unqual_prev; end VX_onehot_encoder #( diff --git a/hw/rtl/libs/VX_mem_rsp_sel.sv b/hw/rtl/libs/VX_mem_rsp_sel.sv index 120bc80d..8366bfef 100644 --- a/hw/rtl/libs/VX_mem_rsp_sel.sv +++ b/hw/rtl/libs/VX_mem_rsp_sel.sv @@ -21,7 +21,7 @@ module VX_mem_rsp_sel #( parameter TAG_SEL_BITS = 0, parameter OUT_REG = 0 ) ( -input wire clk, + input wire clk, input wire reset, // input response @@ -46,18 +46,20 @@ input wire clk, wire [LOG_NUM_REQS-1:0] grant_index; wire grant_valid; - wire rsp_fire; + wire grant_ready; - VX_priority_arbiter #( - .NUM_REQS (NUM_REQS) + VX_generic_arbiter #( + .NUM_REQS (NUM_REQS), + .LOCK_ENABLE (1), + .TYPE ("P") ) arbiter ( .clk (clk), .reset (reset), - .unlock (rsp_fire), .requests (rsp_valid_in), .grant_valid (grant_valid), .grant_index (grant_index), - `UNUSED_PIN (grant_onehot) + `UNUSED_PIN (grant_onehot), + .grant_unlock(grant_ready) ); reg [NUM_REQS-1:0] rsp_valid_sel; @@ -78,7 +80,7 @@ input wire clk, end end - assign rsp_fire = grant_valid && rsp_ready_unqual; + assign grant_ready = rsp_ready_unqual; VX_elastic_buffer #( .DATAW (NUM_REQS + TAG_WIDTH + (NUM_REQS * DATA_WIDTH)), diff --git a/hw/rtl/libs/VX_priority_arbiter.sv b/hw/rtl/libs/VX_priority_arbiter.sv index c47bc63a..e807d860 100644 --- a/hw/rtl/libs/VX_priority_arbiter.sv +++ b/hw/rtl/libs/VX_priority_arbiter.sv @@ -16,22 +16,13 @@ `TRACING_OFF module VX_priority_arbiter #( parameter NUM_REQS = 1, - parameter LOCK_ENABLE = 0, parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS) ) ( - input wire clk, - input wire reset, - input wire [NUM_REQS-1:0] requests, - input wire unlock, + input wire [NUM_REQS-1:0] requests, output wire [LOG_NUM_REQS-1:0] grant_index, - output wire [NUM_REQS-1:0] grant_onehot, + output wire [NUM_REQS-1:0] grant_onehot, output wire grant_valid ); - `UNUSED_PARAM (LOCK_ENABLE) - `UNUSED_VAR (clk) - `UNUSED_VAR (reset) - `UNUSED_VAR (unlock) - if (NUM_REQS == 1) begin assign grant_index = '0; diff --git a/hw/rtl/libs/VX_rr_arbiter.sv b/hw/rtl/libs/VX_rr_arbiter.sv index d4d6fb1a..c1ee4d77 100644 --- a/hw/rtl/libs/VX_rr_arbiter.sv +++ b/hw/rtl/libs/VX_rr_arbiter.sv @@ -21,18 +21,18 @@ module VX_rr_arbiter #( parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS) ) ( input wire clk, - input wire reset, - input wire unlock, + input wire reset, input wire [NUM_REQS-1:0] requests, output wire [LOG_NUM_REQS-1:0] grant_index, output wire [NUM_REQS-1:0] grant_onehot, - output wire grant_valid + output wire grant_valid, + input wire grant_unlock ); if (NUM_REQS == 1) begin `UNUSED_VAR (clk) `UNUSED_VAR (reset) - `UNUSED_VAR (unlock) + `UNUSED_VAR (grant_unlock) assign grant_index = '0; assign grant_onehot = requests; @@ -55,7 +55,7 @@ module VX_rr_arbiter #( always @(posedge clk) begin if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || unlock) begin + end else if (!LOCK_ENABLE || grant_unlock) begin state <= grant_index_r; end end @@ -85,7 +85,7 @@ module VX_rr_arbiter #( always @(posedge clk) begin if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || unlock) begin + end else if (!LOCK_ENABLE || grant_unlock) begin state <= grant_index_r; end end @@ -121,7 +121,7 @@ module VX_rr_arbiter #( always @(posedge clk) begin if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || unlock) begin + end else if (!LOCK_ENABLE || grant_unlock) begin state <= grant_index_r; end end @@ -165,7 +165,7 @@ module VX_rr_arbiter #( always @(posedge clk) begin if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || unlock) begin + end else if (!LOCK_ENABLE || grant_unlock) begin state <= grant_index_r; end end @@ -219,7 +219,7 @@ module VX_rr_arbiter #( always @(posedge clk) begin if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || unlock) begin + end else if (!LOCK_ENABLE || grant_unlock) begin state <= grant_index_r; end end @@ -285,7 +285,7 @@ module VX_rr_arbiter #( always @(posedge clk) begin if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || unlock) begin + end else if (!LOCK_ENABLE || grant_unlock) begin state <= grant_index_r; end end @@ -365,7 +365,7 @@ module VX_rr_arbiter #( always @(posedge clk) begin if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || unlock) begin + end else if (!LOCK_ENABLE || grant_unlock) begin state <= grant_index_r; end end @@ -399,7 +399,7 @@ module VX_rr_arbiter #( always @(posedge clk) begin if (reset) begin pointer_reg <= {NUM_REQS{1'b1}}; - end else if (!LOCK_ENABLE || unlock) begin + end else if (!LOCK_ENABLE || grant_unlock) begin if (|req_masked) begin pointer_reg <= mask_higher_pri_regs; end else if (|requests) begin @@ -443,7 +443,7 @@ module VX_rr_arbiter #( always @(posedge clk) begin if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || unlock) begin + end else if (!LOCK_ENABLE || grant_unlock) begin state <= grant_index_r; end end diff --git a/hw/rtl/libs/VX_stream_arb.sv b/hw/rtl/libs/VX_stream_arb.sv index a81be3ef..f3c4196a 100644 --- a/hw/rtl/libs/VX_stream_arb.sv +++ b/hw/rtl/libs/VX_stream_arb.sv @@ -19,7 +19,6 @@ module VX_stream_arb #( parameter NUM_OUTPUTS = 1, parameter DATAW = 1, parameter `STRING ARBITER = "P", - parameter LOCK_ENABLE = 1, parameter MAX_FANOUT = `MAX_FANOUT, parameter OUT_REG = 0 , parameter NUM_REQS = (NUM_INPUTS + NUM_OUTPUTS - 1) / NUM_OUTPUTS, @@ -57,7 +56,6 @@ module VX_stream_arb #( .NUM_OUTPUTS (1), .DATAW (DATAW), .ARBITER (ARBITER), - .LOCK_ENABLE (LOCK_ENABLE), .MAX_FANOUT (MAX_FANOUT), .OUT_REG (OUT_REG) ) arb_slice ( @@ -102,7 +100,6 @@ module VX_stream_arb #( .NUM_OUTPUTS (1), .DATAW (DATAW), .ARBITER (ARBITER), - .LOCK_ENABLE (LOCK_ENABLE), .MAX_FANOUT (MAX_FANOUT), .OUT_REG (OUT_REG) ) fanout_slice_arb ( @@ -129,7 +126,6 @@ module VX_stream_arb #( .NUM_OUTPUTS (1), .DATAW (DATAW + LOG_NUM_REQS2), .ARBITER (ARBITER), - .LOCK_ENABLE (LOCK_ENABLE), .MAX_FANOUT (MAX_FANOUT), .OUT_REG (OUT_REG) ) fanout_join_arb ( @@ -158,25 +154,25 @@ module VX_stream_arb #( wire arb_valid; wire [NUM_REQS_W-1:0] arb_index; wire [NUM_REQS-1:0] arb_onehot; - wire arb_unlock; + wire arb_ready; VX_generic_arbiter #( .NUM_REQS (NUM_REQS), - .LOCK_ENABLE (LOCK_ENABLE), + .LOCK_ENABLE (1), .TYPE (ARBITER) ) arbiter ( .clk (clk), .reset (reset), .requests (valid_in), - .unlock (arb_unlock), .grant_valid (arb_valid), .grant_index (arb_index), - .grant_onehot (arb_onehot) + .grant_onehot (arb_onehot), + .grant_unlock (arb_ready) ); assign valid_in_r = arb_valid; assign data_in_r = data_in[arb_index]; - assign arb_unlock = | (valid_in_r & ready_in_r); + assign arb_ready = ready_in_r; for (genvar i = 0; i < NUM_REQS; ++i) begin assign ready_in[i] = ready_in_r & arb_onehot[i]; @@ -217,7 +213,6 @@ module VX_stream_arb #( .NUM_OUTPUTS (BATCH_SIZE), .DATAW (DATAW), .ARBITER (ARBITER), - .LOCK_ENABLE (LOCK_ENABLE), .MAX_FANOUT (MAX_FANOUT), .OUT_REG (OUT_REG) ) arb_slice ( @@ -252,7 +247,6 @@ module VX_stream_arb #( .NUM_OUTPUTS (NUM_BATCHES), .DATAW (DATAW), .ARBITER (ARBITER), - .LOCK_ENABLE (LOCK_ENABLE), .MAX_FANOUT (MAX_FANOUT), .OUT_REG (OUT_REG) ) fanout_fork_arb ( @@ -280,7 +274,6 @@ module VX_stream_arb #( .NUM_OUTPUTS (BATCH_SIZE), .DATAW (DATAW), .ARBITER (ARBITER), - .LOCK_ENABLE (LOCK_ENABLE), .MAX_FANOUT (MAX_FANOUT), .OUT_REG (OUT_REG) ) fanout_slice_arb ( @@ -305,24 +298,24 @@ module VX_stream_arb #( wire [NUM_OUTPUTS-1:0] arb_requests; wire arb_valid; wire [NUM_OUTPUTS-1:0] arb_onehot; - wire arb_unlock; + wire arb_ready; VX_generic_arbiter #( .NUM_REQS (NUM_OUTPUTS), - .LOCK_ENABLE (LOCK_ENABLE), + .LOCK_ENABLE (1), .TYPE (ARBITER) ) arbiter ( .clk (clk), .reset (reset), .requests (arb_requests), - .unlock (arb_unlock), .grant_valid (arb_valid), `UNUSED_PIN (grant_index), - .grant_onehot (arb_onehot) + .grant_onehot (arb_onehot), + .grant_unlock (arb_ready) ); assign arb_requests = ready_in_r; - assign arb_unlock = | (valid_in & ready_in); + assign arb_ready = valid_in[0]; assign ready_in = arb_valid; for (genvar i = 0; i < NUM_OUTPUTS; ++i) begin diff --git a/hw/rtl/libs/VX_stream_xbar.sv b/hw/rtl/libs/VX_stream_xbar.sv index 2a8e4bb4..ac8a8dc1 100644 --- a/hw/rtl/libs/VX_stream_xbar.sv +++ b/hw/rtl/libs/VX_stream_xbar.sv @@ -21,8 +21,7 @@ module VX_stream_xbar #( parameter IN_WIDTH = `LOG2UP(NUM_INPUTS), parameter OUT_WIDTH = `LOG2UP(NUM_OUTPUTS), parameter ARBITER = "P", - parameter LOCK_ENABLE = 0, - parameter OUT_REG = 0, + parameter OUT_REG = 0, parameter MAX_FANOUT = `MAX_FANOUT, parameter PERF_CTR_BITS = `CLOG2(NUM_INPUTS+1) ) ( @@ -66,7 +65,6 @@ module VX_stream_xbar #( .NUM_OUTPUTS (1), .DATAW (DATAW), .ARBITER (ARBITER), - .LOCK_ENABLE (LOCK_ENABLE), .MAX_FANOUT (MAX_FANOUT), .OUT_REG (OUT_REG) ) xbar_arb ( @@ -95,7 +93,6 @@ module VX_stream_xbar #( .NUM_OUTPUTS (1), .DATAW (DATAW), .ARBITER (ARBITER), - .LOCK_ENABLE (LOCK_ENABLE), .MAX_FANOUT (MAX_FANOUT), .OUT_REG (OUT_REG) ) xbar_arb ( From 8d4b6c804fe3f0558af9e6242908a736cf481c32 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 4 Feb 2024 20:17:12 -0800 Subject: [PATCH 53/57] minor update --- hw/rtl/core/VX_scoreboard.sv | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/rtl/core/VX_scoreboard.sv b/hw/rtl/core/VX_scoreboard.sv index 6b806dd0..df07ca63 100644 --- a/hw/rtl/core/VX_scoreboard.sv +++ b/hw/rtl/core/VX_scoreboard.sv @@ -111,7 +111,7 @@ module VX_scoreboard import VX_gpu_pkg::*; #( reg [`SFU_WIDTH-1:0] sfu_type; always @(*) begin - case (scoreboard_if[i].data.op_type) + case (ibuffer_if[i].data.op_type) `INST_SFU_CSRRW, `INST_SFU_CSRRS, `INST_SFU_CSRRC: sfu_type = `SFU_CSRS; @@ -179,12 +179,12 @@ module VX_scoreboard import VX_gpu_pkg::*; #( if (writeback_fire) begin inuse_regs[writeback_if[i].data.wis][writeback_if[i].data.rd] <= 0; end - if (stg_valid_in && stg_ready_in && ibuffer_if[i].data.wb) begin + if (ibuffer_if[i].valid && ibuffer_if[i].ready && ibuffer_if[i].data.wb) begin inuse_regs[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd] <= 1; end end `ifdef PERF_ENABLE - if (stg_valid_in && stg_ready_in && ibuffer_if[i].data.wb) begin + if (ibuffer_if[i].valid && ibuffer_if[i].ready && ibuffer_if[i].data.wb) begin inuse_units[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd] <= ibuffer_if[i].data.ex_type; if (ibuffer_if[i].data.ex_type == `EX_SFU) begin inuse_sfu[ibuffer_if[i].data.wis][ibuffer_if[i].data.rd] <= sfu_type; From be0db6e1a511551ee3f03414126dea443354fac6 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Sun, 4 Feb 2024 20:32:05 -0800 Subject: [PATCH 54/57] minor update --- hw/rtl/libs/VX_fair_arbiter.sv | 2 +- hw/rtl/libs/VX_generic_arbiter.sv | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/rtl/libs/VX_fair_arbiter.sv b/hw/rtl/libs/VX_fair_arbiter.sv index acc01971..c063b2fb 100644 --- a/hw/rtl/libs/VX_fair_arbiter.sv +++ b/hw/rtl/libs/VX_fair_arbiter.sv @@ -54,7 +54,7 @@ module VX_fair_arbiter #( end VX_priority_arbiter #( - .NUM_REQS (NUM_REQS), + .NUM_REQS (NUM_REQS) ) priority_arbiter ( .requests (requests_qual), .grant_index (grant_index), diff --git a/hw/rtl/libs/VX_generic_arbiter.sv b/hw/rtl/libs/VX_generic_arbiter.sv index 2b7922d9..4573efb3 100644 --- a/hw/rtl/libs/VX_generic_arbiter.sv +++ b/hw/rtl/libs/VX_generic_arbiter.sv @@ -36,7 +36,7 @@ module VX_generic_arbiter #( `UNUSED_VAR (grant_unlock) VX_priority_arbiter #( - .NUM_REQS (NUM_REQS), + .NUM_REQS (NUM_REQS) ) priority_arbiter ( .requests (requests), .grant_valid (grant_valid), From ae7b01405c8e25c118f97dd2131d8a73f1f8fe5b Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Thu, 8 Feb 2024 14:10:00 -0800 Subject: [PATCH 55/57] CI minor update --- .travis.yml | 4 ++-- ci/regression.sh | 32 ++++++++++++++++++-------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 236ed3b7..8b6e2878 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,8 +37,8 @@ jobs: script: - rm -rf $HOME/build32 && cp -r $PWD $HOME/build32 - rm -rf $HOME/build64 && cp -r $PWD $HOME/build64 - - make -C $HOME/build32 - - XLEN=64 make -C $HOME/build64 + - make -C $HOME/build32 > /dev/null + - XLEN=64 make -C $HOME/build64 > /dev/null - stage: test name: unittest script: cp -r $HOME/build32 build && cd build && ./ci/travis_run.py ./ci/regression.sh --unittest diff --git a/ci/regression.sh b/ci/regression.sh index abe51129..41ce8332 100755 --- a/ci/regression.sh +++ b/ci/regression.sh @@ -22,7 +22,7 @@ rm -f blackbox.*.cache unittest() { make -C tests/unittest run -make -C hw/unittest +make -C hw/unittest > /dev/null } isa() @@ -31,33 +31,36 @@ echo "begin isa tests..." make -C tests/riscv/isa run-simx make -C tests/riscv/isa run-rtlsim -CONFIGS="-DDPI_DISABLE" make -C tests/riscv/isa run-rtlsim -make -C sim/rtlsim clean && CONFIGS="-DFPU_FPNEW" make -C sim/rtlsim +make -C sim/rtlsim clean && CONFIGS="-DDPI_DISABLE" make -C sim/rtlsim > /dev/null +make -C tests/riscv/isa run-rtlsim + +make -C sim/rtlsim clean && CONFIGS="-DFPU_FPNEW" make -C sim/rtlsim > /dev/null make -C tests/riscv/isa run-rtlsim-32f -make -C sim/rtlsim clean && CONFIGS="-DFPU_DPI" make -C sim/rtlsim +make -C sim/rtlsim clean && CONFIGS="-DFPU_DPI" make -C sim/rtlsim > /dev/null make -C tests/riscv/isa run-rtlsim-32f -make -C sim/rtlsim clean && CONFIGS="-DFPU_DSP" make -C sim/rtlsim +make -C sim/rtlsim clean && CONFIGS="-DFPU_DSP" make -C sim/rtlsim > /dev/null make -C tests/riscv/isa run-rtlsim-32f if [ "$XLEN" == "64" ] then - make -C sim/rtlsim clean && CONFIGS="-DFPU_FPNEW" make -C sim/rtlsim + make -C sim/rtlsim clean && CONFIGS="-DFPU_FPNEW" make -C sim/rtlsim > /dev/null make -C tests/riscv/isa run-rtlsim-64f - make -C sim/rtlsim clean && CONFIGS="-DEXT_D_ENABLE -DFPU_FPNEW" make -C sim/rtlsim + make -C sim/rtlsim clean && CONFIGS="-DEXT_D_ENABLE -DFPU_FPNEW" make -C sim/rtlsim > /dev/null make -C tests/riscv/isa run-rtlsim-64d || true - make -C sim/rtlsim clean && CONFIGS="-DFPU_DPI" make -C sim/rtlsim + make -C sim/rtlsim clean && CONFIGS="-DFPU_DPI" make -C sim/rtlsim > /dev/null make -C tests/riscv/isa run-rtlsim-64f - make -C sim/rtlsim clean && CONFIGS="-DFPU_DSP" make -C sim/rtlsim + make -C sim/rtlsim clean && CONFIGS="-DFPU_DSP" make -C sim/rtlsim > /dev/null make -C tests/riscv/isa run-rtlsim-64fx fi -make -C sim/rtlsim clean && make -C sim/rtlsim +# restore default prebuilt configuration +make -C sim/rtlsim clean && make -C sim/rtlsim > /dev/null echo "isa tests done!" } @@ -134,15 +137,16 @@ debug() echo "begin debugging tests..." # test CSV trace generation -make -C sim/simx clean && DEBUG=3 make -C sim/simx -make -C sim/rtlsim clean && DEBUG=3 CONFIGS="-DGPR_RESET" make -C sim/rtlsim +make -C sim/simx clean && DEBUG=3 make -C sim/simx > /dev/null +make -C sim/rtlsim clean && DEBUG=3 CONFIGS="-DGPR_RESET" make -C sim/rtlsim > /dev/null make -C tests/riscv/isa run-simx-32im > run_simx.log make -C tests/riscv/isa run-rtlsim-32im > run_rtlsim.log ./ci/trace_csv.py -trtlsim run_rtlsim.log -otrace_rtlsim.csv ./ci/trace_csv.py -tsimx run_simx.log -otrace_simx.csv diff trace_rtlsim.csv trace_simx.csv -make -C sim/simx clean && make -C sim/simx -make -C sim/rtlsim clean && make -C sim/rtlsim +# restore default prebuilt configuration +make -C sim/simx clean && make -C sim/simx > /dev/null +make -C sim/rtlsim clean && make -C sim/rtlsim > /dev/null ./ci/blackbox.sh --driver=opae --cores=2 --clusters=2 --l2cache --perf=1 --app=demo --args="-n1" ./ci/blackbox.sh --driver=simx --cores=2 --clusters=2 --l2cache --perf=1 --app=demo --args="-n1" From 3fee1a61935240e9145db0235addad9b632f7a5e Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Fri, 9 Feb 2024 20:34:44 -0800 Subject: [PATCH 56/57] minor update --- README.md | 2 +- RELEASE | 4 ---- TODO | 23 ----------------------- ci/travis_run.py | 6 +++--- 4 files changed, 4 insertions(+), 31 deletions(-) delete mode 100644 RELEASE delete mode 100644 TODO diff --git a/README.md b/README.md index bca70da0..05b1cb93 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Vortex is a full-stack open-source RISC-V GPGPU. ## Build Instructions More detailed build instructions can be found [here](docs/install_vortex.md). ### Supported OS Platforms -- Ubuntu 18.04 +- Ubuntu 18.04, 20.04 - Centos 7 ### Toolchain Dependencies - [POCL](http://portablecl.org/) diff --git a/RELEASE b/RELEASE deleted file mode 100644 index 48ae100a..00000000 --- a/RELEASE +++ /dev/null @@ -1,4 +0,0 @@ - -Release Notes! - -* 07/01/2020 - LKG FPGA build - Passed basic, demo, vecadd kernels. \ No newline at end of file diff --git a/TODO b/TODO deleted file mode 100644 index 0e4b84ed..00000000 --- a/TODO +++ /dev/null @@ -1,23 +0,0 @@ - - - -Functionality: -1) vx_cl_warpSpawn() - -> To be used by pocl->ops->run - -2) newlib Integration (LoadFile("")) - -> To be used by the Rhinio benchmarks - -3) POCL OPS Vortex Suite - -Performance: -1) Icache doesn't need SEND_MEM_REQUEST Stage - -> Blocks are never dirty, so why not evict right away - -2) Branch not taken speculation - -3) Runtime -02 not running on RTL, and -03 not running on RTL and Emulator - - -Vector: -1) Cycle accurate simulator (would require Cache Simulator) diff --git a/ci/travis_run.py b/ci/travis_run.py index f55a4b0a..8424cd59 100755 --- a/ci/travis_run.py +++ b/ci/travis_run.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -# Copyright © 2019-2023 -# +# Copyright 2019-2023 +# # Licensed 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 @@ -34,7 +34,7 @@ def monitor(stop): break def execute(command): - process = subprocess.Popen(command, stdout=subprocess.PIPE) + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) while True: output = process.stdout.readline() if output: From 5f2b10b8a6f4da14fbb1ad42433832c228ae5099 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Fri, 9 Feb 2024 21:20:23 -0800 Subject: [PATCH 57/57] minor update --- ci/travis_run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/travis_run.py b/ci/travis_run.py index 8424cd59..021e3ff2 100755 --- a/ci/travis_run.py +++ b/ci/travis_run.py @@ -38,7 +38,7 @@ def execute(command): while True: output = process.stdout.readline() if output: - line = output.decode('ascii').rstrip() + line = output.decode('utf-8').rstrip() print(">>> " + line) process.stdout.flush() ret = process.poll()

    U>d^?1`6ki*iWl?6o`eWy^tk3g5^H>&L5~-h} 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 Zf99>)u|jTJIGh-Oz|+;wWt~$(697W(-qZj9 diff --git a/docs/cache_subsystem.md b/docs/cache_subsystem.md index 4bfc0ded..9de309e1 100644 --- a/docs/cache_subsystem.md +++ b/docs/cache_subsystem.md @@ -2,69 +2,26 @@ The Vortex Cache Sub-system has the following main properties: -- High-bandwidth with bank parallelism -- Snoop protocol to flush data for CPU access -- Generic design: Dcache, Icache, Shared Memory, L2 cache, L3 cache +- High-bandwidth transfer with Multi-bank parallelism +- Non-blocking pipelined architecture with local MSHR +- Configurable design: Dcache, Icache, L2 cache, L3 cache -### Cache Hierarchy +### Cache Microarchitecture -![Image of Cache Hierarchy](./assets/img/cache_hierarchy.png) +![Image of Cache Hierarchy](./assets/img/cache_microarchitecture.png) -- Cache can be configured to be any level in the hierarchy -- Caches communicate via snooping -- Cache flush from AFU is passed down the hierarchy​ +The Vortex cache is comprised of multiple parallel banks. It is comprised of the following modules: +- **Bank request dispatch crossbar**: assign a bank to incoming requests and resolve collision using stalls. +- **Bank response merge crossbar**: merge result from banks and forward to the core response. +- **Memory request multiplexer**: arbitrate bank memory requests +- **Memory response demultiplexer**: forward memory response to the corresponding bank. +- **Flush Unit**: perform tag memory initialization. -### VX_cache.v (Top Module) +Incoming requests entering the cache are sent to a dispatch crossbar that select the corresponding bank for each request, resolving bank collisions with stalls. The result output of each bank is merge back into outgoing response port via merger crossbar. Each bank intergates a non-blocking pipeline with a local Miss Status Holding Register (MSHR) to reduce the miss rate. The bank pipeline consists of the following stages: -VX.cache.v is the top module of the cache verilog code located in the `/hw/rtl/cache` directory. +- **Schedule**: Selects the next request into the pipeline from the incoming core request, memory fill, or the MSHR entry, with priority given to the latter. +- **Tag Access**: A single-port read/write access to the tag store. +- **Data Access**: Single-port read/write access to the data store. +- **Response Handling**: Core response back to the core. -![Image of Vortex Cache](./assets/img/vortex_cache_top_module.png) - -- Configurable (Cache size, number of banks, bank line size, etc.) -- I/O signals - - Core Request - - Core Rsp - - DRAM Req - - DRAM Rsp - - Snoop Rsp - - Snoop Rsp - - Snoop Forwarding Out - - Snoop Forwarding In -- Bank Select - - Assigns valid and ready signals for each bank -- Snoop Forwarder -- DRAM Request Arbiter - - Prepares cache response for communication with DRAM -- Snoop Response Arbiter - - Sends snoop response -- Core Response Merge - - Cache accesses one line at a time. As a result, each request may not come back in the same response. This module tries to recombine the responses by thread ID. - -### VX_cache_bank.v - -VX_cache_bank.v is the verilog code that handles cache bank functionality and is located in the `/hw/rtl/cache` directory. - -![Image of Vortex Cache Bank](./assets/img/vortex_bank.png) - -- Allows for high throughput​ -- Each bank contains queues to hold requests to the cache​ -- I/O signals - - Core request​ - - Core Response​ - - DRAM Fill Requests​ - - DRAM Fill Response​ - - DRAM WB Requests​ - - Snp Request​ - - Snp Response -- Request Priority: DRAM fill, miss reserve, core request, snoop request​ -- Snoop Request Queue​ -- DRAM Fill Queue​ -- Core Req Arbiter​ - - Requests to be processed by the bank -- Tag Data Store​ - - Registers for valid, dirty, dirtyb, tag, and data​ - - Length of registers determined by lines in the bank​ -- Tag Data Access:​ - - I/O: stall, snoop info, force request miss - - Writes to cache or sends read response; hit or miss determined here - - A missed request goes to the miss reserve if it is not a snoop request or DRAM fill \ No newline at end of file +Deadlocks inside the cache can occur when the MSHR is full and a new request is already in the pipeline. It can also occur when the memory request queue is full, and there is an incoming memory response. The cache mitigates MSHR deadlocks by using an early full signal before a new request is issued and similarly mitigates memory deadlocks by ensuring that its request queue never fills up. diff --git a/docs/microarchitecture.md b/docs/microarchitecture.md index 972da7b0..3459abcc 100644 --- a/docs/microarchitecture.md +++ b/docs/microarchitecture.md @@ -24,71 +24,57 @@ Vortex uses the SIMT (Single Instruction, Multiple Threads) execution model with - Control the number of warps to activate during execution - `WSPAWN` *count, addr*: activate count warps and jump to addr location - **Control-Flow Divergence** - - Control threads to activate when a branch diverges - - `SPLIT` *predicate*: apply 'taken' predicate thread mask adn save 'not-taken' into IPDOM stack - - `JOIN`: restore 'not-taken' thread mask + - Control threads activation when a branch diverges + - `SPLIT` *taken, predicate*: apply predicate thread mask and save current state into IPDOM stack + - `JOIN`: pop IPDOM stack to restore thread mask + - `PRED` *predicate, restore_mask*: thread predicate instruction - **Warp Synchronization** - `BAR` *id, count*: stall warps entering barrier *id* until count is reached ### Vortex Pipeline/Datapath -![Image of Vortex Microarchitecture](./assets/img/vortex_microarchitecture_v2.png) +![Image of Vortex Microarchitecture](./assets/img/vortex_microarchitecture.png) -Vortex has a 5-stage pipeline: FI | ID | Issue | EX | WB. +Vortex has a 6-stage pipeline: + +- **Schedule** + - Warp Scheduler + - Schedule the next PC into the pipeline + - Track stalled, active warps + - IPDOM Stack + - Save split/join states for divergent threads + - Inflight Tracker + - Track in-flight instructions - **Fetch** - - Warp Scheduler - - Track stalled & active warps, resolve branches and barriers, maintain split/join IPDOM stack - - Instruction Cache - - Retrieve instruction from cache, issue I-cache requests/responses + - Retrieve instructions from memory + - Handle I-cache requests/responses - **Decode** - - Decode fetched instructions, notify warp scheduler when the following instructions are decoded: - - Branch, tmc, split/join, wspawn - - Precompute used_regs mask (needed for Issue stage) + - Decode fetched instructions + - Notify warp scheduler on control instructions - **Issue** - - Scheduling - - In-order issue (operands/execute unit ready), out-of-order commit - IBuffer - - Store fetched instructions, separate queues per-warp, selects next warp through round-robin scheduling + - Store decoded instructions in separate per-warp queues - Scoreboard - Track in-use registers - - GPRs (General-Purpose Registers) stage - - Fetch issued instruction operands and send operands to execute unit + - Check register use for decoded instructions + - Operands Collector + - Fetch the operands for issued instructions from the register file - **Execute** - ALU Unit - - Single-cycle operations (+,-,>>,<<,&,|,^), Branch instructions (Share ALU resources) - - MULDIV Unit - - Multiplier - done in 2 cycles - - Divider - division and remainder, done in 32 cycles - - Implements serial alogrithm (Stalls the pipeline) + - Handle arithmetic and branch operations - FPU Unit - - Multi-cycle operations, uses `FPnew` Library on ASIC, uses hard DSPs on FPGA - - CSR Unit - - Store constant status registers - device caps, FPU status flags, performance counters - - Handle external CSR requests (requests from host CPU) + - Handle floating-point operations - LSU Unit - - Handle load/store operations, issue D-cache requests, handle D-cache responses - - Commit load responses - saves storage, Scoreboard tracks completion - - GPGPU Unit - - Handle GPGPU instructions - - TMC, WSPAWN, SPLIT, BAR - - JOIN is handled by Warp Scheduler (upon SPLIT response) + - Handle load/store operations + - SFU Unit + - Handle warp control operations + - Handle Control Status Registers (CSRs) operations - **Commit** - - Commit - - Update CSR flags, update performance counters - - Writeback - - Write result back to GPRs, notify Scoreboard (release in-use register), select candidate instruction (ALU unit has highest priority) -- **Clustering** - - Group mulitple cores into clusters (optionally share L2 cache) - - Group multiple clusters (optionally share L3 cache) - - Configurable at build time - - Default configuration: - - #Clusters = 1 - - #Cores = 4 - - #Warps = 4 - - #Threads = 4 -- **FPGA AFU Interface** - - Manage CPU-GPU comunication - - Query devices caps, load kernel instructions and resource buffers, start kernel execution, read destination buffers - - Local Memory - GPU access to local DRAM - - Reserved I/O addresses - redirect to host CPU, console output \ No newline at end of file + - Write result back to the register file and update the Scoreboard. + +### Vortex clustering architecture +- Sockets + - Grouping multiple cores sharing L1 cache +- Clusters + - Grouping of sockets sharing L2 cache \ No newline at end of file From 648bf75b0b6c96c64d12ffca638c13ba5b1a6129 Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 3 Jan 2024 19:09:18 -0800 Subject: [PATCH 42/57] minor update --- docs/assets/img/vortex_microarchitecture.png | Bin 0 -> 474407 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/assets/img/vortex_microarchitecture.png diff --git a/docs/assets/img/vortex_microarchitecture.png b/docs/assets/img/vortex_microarchitecture.png new file mode 100644 index 0000000000000000000000000000000000000000..7fde5296a077f9d4c46a8d70e99cb36fd7a43177 GIT binary patch literal 474407 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

  • C2QsBUWp!lQ$M>pL3Wb?!PKCU?*qB$d7|#V%jI)F- zR*QAOk&*zDh$}QyF(TJSj0Hur=OLlh#rcmlvcoljJ16|&*XeIBhGz`b9qyPv_d$Y4I6Lo^ErrhPI|4&PiC1Iz$iz_30dnJEw0gFtGo(J z$=p2XEnj{sA50d;>wSI05M`^8t4zM-ok~utqR`pn!U?9$>DdE^=%u1C4WW^mdd(#_ z-gO((Zb=-kDE)WS59mBgU`;muj?HGEKF`oO5@PF+yh*x7JC--{WX zDmj5f^-o<13u^oD#pu=mgWKteiMdMz3EV zk8%E(+7l{?uQcxsj0`Z6x=SsNG_o?cC+;(H$V^GvtMR%0JU5?&OKs5tXUKq)ruo$6W5KA3M(2kx= zo;|?8Ij^ge0Wh%UnAzjWKRe8!_c;ip@EA&LygDeJe8r`QK>L{Ej8-aM9^p9$E$;YW}J&&&T+vY<;$%Ehfn<83_FB3zE!oGcJjb23=x%ox7h6Z(acm3jAn;44tdMgUr?~yo12@ z!MG948rhE@*{qh6O)aY%Mnxg6K2!ktq=?O>;?X)$Ia^_%!rUq1lx@o4;_n00JiGz^ zUyef^ELNJQwb6;`czDR?s^6lGGva(LZNx#ft+QY25I((p#E`*rSj$!*7!i2|`?RD> z;Q~+{RA`Pu(3OTYpNS$}4MZ~6a&q=HU4~c7W)DsGuu1vkDzsB2#`;Vr@@0_zI8UH{ zjKOPUL1InNH3Ly7Gq4EE^c z$x>NNof?-Yz0N|+M37pRsj*GW{w=!8_HhdM=~Uf)H_=#mI|~7`nGO^zOfE!N(CXBK zpq;}*9X^ZXs%VBQuoRyr8p$e%p+ax-D%Il;TCcDH<~4Fik6g@CvhS47^N5K#tA4hh zSdiDQU(+TiE6Yqx;|IS_k`Ozm?f+pN35llO$5G!7lexy!7t`K3f`XEtFq_y5C{! zL~~i0s`J(eawe*q#EPT`f1{$Y8DI46p$}C+WGP<7oQM;=ci~#fJip_F2iujCH*dU$ z2=G?^YEx{-A3la2?W&ufy8|oYNU_?r7RzMr?Kuk?A~s#l=e@4sSEsh`1+HqG_NZ_n z*;@1a!RX3s#I z(b?Ac{nPEqXzWm}68+idwU1uOmMr%W4&g(}1*;?rNUPI_l!q!JDTQ1Wx1(ZAC6WGk zM*JWoqvq!BrB{j@AfXrctTgi4oxK)FwVFW!^3gi4^OF6l%0qbNTfV^U?$%qX5!CKi zeywygxSAio)6orH+J(&CsJ1h6MY(K`W(r~N&cFZWBpdKvvi2HC9W$Lc`)=PhnB+5S za~iEqk0R0fj$Q&HuX^2)tc|8rM?#Qsg9@oAS~Kc7^f2mMU3*A)zg3FRDI^$VbKF3Y z8S{a|+BzSV2f}<`PVG5mfeA6)EEbfFzBgKB;y#?DbndH3zO>-+nS)T+}=TV!Yv_xjXi$r~@l#G4xDaSo%S9n6qWS>pJp%E$Ig zOtIlw7T&Q&vio6<-Ey;HMmqxwYYEp26F9kYjnbI5=!EQaTfIB--Cb*0L(iT)d*XaS z*B8q?R4s}It6N2X@KYQh_oC;+Qh|dcXn5ER>|DW(^h}B^nZRv(h!{r`=Cw0DeM$oA zS#pZ<(l1}W>}$oxk4#RcyJ2tDYLv$vG$3v^KXr|d5fVT{L$jaln!F@gy$XMu_uuPS z8XJWG>?4L3ZI+^bcXKePM`0289@^}@h3B{`=RKp#5u*hv5AJ(!^S)zny)@Nn^$`(t zwv2dY>X|;gQ~LQgA88WMb2LS#D>t!B7d4q!ARxI9wL{L872j!#a2;h2RS+F<;9xX- zK_*)YaW=1dK6k-l1k%3)#miQ2kO69pm#m&;So{Ggosb?k_!#*`<|>nYThfl_M}N9y zSGQkTo{Q^sMF)W-)+eOI34J!y75Suwr~zvBbX+g(t!(dqFz^)rCZ2B8>XY!)DTlSP zw!%(DZ7YVu(|mrW+J<=I!|w@;SRHlgLSm=LM#nYu3bSV^Z2au+aLFnSa0uU`Ky5L7 ze;)=D#H3ICTsypt@z;un7C1tUvqTFs>|^#w2NSuq=hmM1T-5C>+je)1XE$v*jHbUQ z&@>(m#xM|~bJWEZ*ac!^ZNYh-MAFy`bqiio(0CcUD&}&We4H8koUFRPrh&qRgT8RD zXKlhb=Jm1BfV&r_pzBVUq|Cqpli-Sc_Z2AJ@4>ERJ$Bp_Zb$FFY`zCXQ|(>v?9B=< zTra!1iDx09p;dOutK_t(GN1(Lzqk+_^q!iHPf>7~=0=DO6ZjE~Eg#uz45vmeEKZbt zndXKU#xxsU?FOwU{Qz6C(qdQ{MYo6p6vwvS<;L!+lqlGnf~{l>!OMjT4K;Z8C70WF zY3V~EmYtJd2a))qox2fQjp6Cyw+oiDMWW^dhR_n{n&Qm~!b?1uj>=3uca4+t&pDK> zg~()_uI<-A0O)-tv-r`oTW$+IXPOaJ13$R+y_=XPvG1tvB6f%gFjLKwKl{J)7$W|ETKF?3+(ER;k@=UiSQhyYuC7DXClo6Zn4+z-I z-lDRrw#iLMnOE;unXY=!<3SF6)KO-DOIpUugPm9QHBt;Du+L3%hF5reNqe8k4f#Qa z{x)r|jty{?CTFRqe9b$2k|9sZ`*%M^j?SFwZ>`?L=wo~b{b_7x<)1Q-lh8$y+5cu* zHEW^2&gJ@JVSl~TtL_j1p-hYT^_g-fF%%=N&x)K&=lqaf1B>rX)@wXyA5-0%qSkN$ zNvCjTfF#o~wojoQ=|q2j6}vz}!P^z;J=CRbyjnH1ZH!?rAQPJMG;{HZ))b}l<4UFg zKo#^p=*Q`QTkd2=z(3g&zAzxnVpr7$hhyYjTcQCthF@9P>&~kEz*M9lFJ!vL_RYov zA1;0Z3I~!%c-2r*DZW4CZ*rK?E@!sued_NlgmT1ifv8fqFXDA(2`w8JG|h6(9!Gja zui7g?8q=^DJC2TMl7q!-0jtUw!=eBreYfq&0SZJ+ z2p2)7ESAjHSoT7kpw~rP20ptXAI?*kAyZ}yU6jlSqK5nZs&4B))(R6&M=ju9@A(m{ zz#x9K-pPV3RlpEE!gh@Z30h=Wyy@KM#JOEI@9C}9xSroGxAnREo*yv`@wo*pmpW4B zsD9YgY@T=J!F>#PC5{;BKDKoGI}{C?&;kxupO_nFgNCXda(F@R!&9U{ z9}L(%Vn~x&tg?#Mj8{8y0{m=5L6<7+Z0*3`s--Wgt<~putw+B2?@(tik!03(T_9?6HU3Sp&UV* zF(#chCfN&qfdga}ydEJrp4WMqF%>Zc6$0<@X5d;N&kuY`t@4N+2z-|e&TF{Od&V>+^C>EDt?D?-8l($M0F~^$R2pJg`riNBH`b` zizm_@-0TCX2K$Hl@b?xHLoX141~0& zCpQ8oG9d6`8SZ~CmXSM)xM|b$= zB|Ycz# zm&bG5JR<4nQfh*FTVaMIzV|XKfMH~CE&B}JYkLdcwfe*fO!W;?|&2`z0%l&?_i7RQWDpJ)^BPb2~IS0cm7g8pH| zLss$~_wrv|mu!yuLXOrr1I6#rK7I(Aijy>;nX=(P0m6D~BKy>u0@u;wvzEA|R2hxsjmI zXNJXrQBwt#;Ha)Hjv6CR0+%i7TD(t4gF;fWnKLxeXH zaIXkU9AB24WQlNpp4;;^gMtTCuLprF2wuYh1$JBUrN9J&Er4P+^R5ReLE>jL*g&4y zVpkeS_d?$%Q3}{&g4qw?v@81Ri7GEp(mR+o{_(5muXOsoiPm&@MFtV^ASe(uoGfE! zMZJ9h&2T0{_+rk#F*<9TV!jJ*rN+CF>iG+_r{9pTua{DGo|HR~eBu!JDjyLW6a$MP zAn4O1APhBo3@=snf>PCt2krkTRq2^&YSju>6pWd6Jb?8*_Z`X(SEr3bcGtO^etmR- zJ9sO0E@^r~CXD@xH48Z!Es&h{&n7$YHbA(F`cFg71)MtMS^?U4ryqnny~b22bJO7# z+MKjUEW;a_j-^Xt|;srpN>w z0)x1*=mnk-MJ26~hr$$bTz(-}78-fS$$fmA>zrxoa=1`Nw#LXaFHq^~x;-#QfbfOJ z`Eg+cXaL{K?C=ts-rHWB*M8$X{WdUbIJgWQ2kCwu1_Z@O)u;A+d$OPX@JXRcO}<9% z#}m=vkCBYU;rizwLF7Y%_PF$Yq6>&ulb+NnjTqS-I$ti5Egj;{Uoz!z#WJ)H@{#Jw z(A+x8U&27v9)OoD|E?H`1eU;;@%tqj%vRr>bfqEOI+vW5_I;BV5axq} zo~h+14Qh7iT6^F7yK)p5sI^k>p_dzE;N%W=_4LxVXLRM?IY14XAJ`mWPuMgIDm+|2 zFs75V5JJ$588Tm=DN-u)i&SesdsSyoG^oV-E@g^@*2Pe)m~PYhi@ME0FNzB5V&K#Q zvx((mgUg7JY3I=KI`eZ4r>i7kBXVDg8P?`*zs=ZnyV2%l)fgB@t`#R9XnzMcxa`rb zIVJy9(@mUsj1wd@hqp^XGqj37>#q&?h{m`&clA_SSDBibkz6dIcypCBu{xN&^Hr9_J4;1QD7+K6Dup7RmFoQaKMSuztb} zk)U66K3GPu$^c#0vDE(3u~3b}oeW}TpdMP3n*`8s*HOvBbEPNnW78v};udZ~ENBZ! z?0GRB5} zsOBTgC@qT2bxu)#o;8+?bFxhJ_p4`Bia=EA862E#^Qk@L2K!fz!^1yob2YvPiFfXg zPyYe1PP8GM*Ms$353AtKa8=K~5eM;+7dM;}N_&SoOMpO93R*=`|@*EjtpgrQ>Z z2B+1$ji5j7T8TWO$KsF08t}ude8tttLF6n!LgyzylY)5<)IB4&)s2?cx$#I!gw}%8 zl80Oo^W;*LI63fx+8;m}g2+c0phB9U+wIDaE#Pn)_U?VCW4InNxNGG6_7H&;foZ=c zz8rGeVMO5ZT;I0KM6qdXc9IpKzqPAF&#(>r^9X=ZB+n6o#pOr$ugiKUnJmujmfGEUD$s*|f1(LAg=$1Dpu|9l z8hRl(i}Iz&UQLi}kaPGN87gdj8O+WJ(cP;Ck}dG8ZbZriAG5B(OFun#Xz?Tj0S!O}YEpNsCm==eHSK9NQf_C>%hz zC4~eZ76!god$o^iVqyYBJO1{~#2orfxh+0X=*cPTZP9t`5@t7OiSf5(qmmrqqp|sHfdmP-b zs93|5q6H5p05HlF#<$i+r~Ot0cBYi0YvGlgc=l@o;Gy%iyAqnNF%LCQdR=)8#+UZE za3G1r<3`R}XWE>>YGK&y`st&CABRIz9;6JO1OR!Qy#K3Am#&_^2hzKc-kXtkiSn@& zD~^S6J9wvHmkn{4{KQHQ52XPJuo-MzA*XiN4-75*Cvn+%PJFZt<;Ym+CX|z0BpLH}exb7-2)9+Dp z*HLTlt7 z$$7k!fI>Se*zfeU>cV)NEzjvm`T1;pCg}P~?73RHj(KMv#}*zYJe}^uK8I`dOqx0d zyZT+T!d<_5?7=8j69!GqTt$0^nh?v+$hZEZ1)yo~dCMuR7y1^wpG0`ljp83^P&gOn ziAVyQ@TuAD5HW63g;DTp3I>*-(o+Cvnfn9}4m7zMHTEedkPbi2`?m5_WkZ2WUQsbd ze}lu|2|bD~Tm&|Kyo(0LpJwd~e3tHEwhWb;0-od6Kd+KiFkBgDt|0T~e7BAs+=;3_O=E=uM zvDN8Aa3R~a1W%Qp_V#_jG-p_z7ED^?cHDa{n=Ko@eI>M@UD{>3+}<%ZvNPqOsf}3a zYVKBN)!j2-jc-Z|w65l@NjD z?o-pwA!W_#of` z8~A8|0sC!W!QTT3p9E*(ZBr`XiL=_M3)-Z%d`*#ZgG^LE;F2hkHOjevZ{ZmiIw)}e z*G3O)u^0oD->DrKij;dzV>9x(X}cie9T* zq@I2+g+Ib167T@eEv1(f@~`E=w4B-bRdur{W4l~S{f?M%2!Vy~dFnFt21!L!%)ox` zCcMGF8KMr3u_3EgYj{Z$NEa+*{$+u3m#nGB?VNiqeHE&TMwo4l)`p_ zKzWnNXgE=bWlH!QP9X4>cq^bl(;kvdXEon~adsfKN&00HxisTX6Kjg%-%$aabg(+X z4fcVa)SDqZFqdcyx}VBdeWV+Q%)~&c!--aFPb;OFmCoQw0_?kcH$KkP#oVI;N)~5( zPIk&j!Flo$J?x#qt377@T3w;FjcyG|YcLkrVs)_tG@YJkt-22jl~cTo!3>tv8J zdKZ~ocQQg5te=_4bG@gTUI_Y+N=Jz$48>cDXogChSUeMIU`~W&QNbg+L+wO*jD&U= z9iXuc{Ta61KtJNlbkeJDwAhAGF-Z_j%}}_Ufs3cyJ%$1PtH3to2xsMY1aY=?FmVWY z6}i1J{*R!Zr%{vnyOZK{t-!}jUQ2-1Xy<Q#`bys+mTkqWD;~r z1(9~>6+9zMAmoaguGhbu;qK6&=dqv9L77$tdfgR14?g3|526Wz{jbK|*$am%dCsLx$!cYoKZyqgZy!={;s_3#l%` z1kMyHLeQKz?pn1kK*!uE^35v8kBRFgq9}9{{RCPxR8ZG1Z1AYy!nCb}IJnVxKukVMo621m1-JeT! zuCzgC6mjzCf~ID7eGiZUUU4_=+&Ev24&sp+sqsf5_@6#-3+NT5Izq?=HA7biJs2F? znYQL||H{etoRVr)#BK|cl||$`oh4LOo6l@7z_0 zR6PeoI4?QS>Ue1812p6q@)&Frn;0(*GX1Vg&E~`;->D=ZsfboYGWv)w;YCUpAO|8uW zQ&>>la=F~T>Tn95YCSmHR*$W|sqpDA321i?Ly$VwBJ{I=0NUplwRPrHkl3Hh=Pfi> zrha)DQEYZg&VUzFy>KP zIn+d;5dRO3k?TtT*ekK+dLLQUBhi^%MT3qQ1`!11_csWM7(`ss`X>YIE!lH%V+c5= zBGz*}38^<(bO9kpL9cG-ezgTSk32ivh2&dL-Wq#bO_!uTk~o^BQ4ib`EI+4t0hAo8 zeIy{S)A(`q?$42(tS(tRnx>S*al@x&^jBf4=3*PmE2bF|6C29a6_*Q#qR3Fz=N6~7 zVcg7vj?8I|tm3B{kF&UQ!&ffp2dKQSq@DJKMXx$U`!*}kVY`os8g{tH#eC9%N}&2@ zU_2#@V+NYyu$!qAqd-{zn1;=GzlXz~m36f1!Eh0Q`etr$VW zs>6}x_Ej9>Gtcf`d0j0LrK7hwXL~<$Ti-^07+ZBE%p8tUQ@##i3Y3d^9uZ~mi2$QS zw;^0|h+md=nvFE%C6dG2ysrDt*`G*Ue3gV)HyiH?(?_d@lFg>RlP{7l5wf@!jN!xd zJG*zc{JuodQ7@hYRE1A+(TR+Ex7q5~>2lLcdKF&K{*(x^@jldw@FRDP1n#}ubvuLN ztGqE9D)|YML4y`U4{hfnuP0=zD*y-8=8hXT%xDkNE9dPWV+&(Zt_G`z18j&|B09Ug zE`4oegE#tapg`!-5p$inVUdC4bQDoks3(RX>3idh5%I&!@BNN&xH;~%r&s?jmVTA# zUP29dYvitT?zKv6I;fv628r;o8K z9%HPcMut8TlsC8x*<)~mN-mxydc%K?S(Iq@%_VtZF6iw6k{%(@uHX4Q)!#^5pi#R2 z`Ii>pSwy^l8#cUQaZ6sXa8NbhAJ^i$dy7LWE4}|~clr013#StIe@ryg(PTofppz#3 zDM)1XXA%i%0X*=1Y(VgXBRP3&@GT84g)0>}l^;pIB#2LqyF!5N?zZIBiw8u-gGvYN zhu$VeAh5!YW3mfK1*OZ}NP}%~sl{4Y!ZWO-=mi9chIh($DBpmsJpzvnABvvOv4~74 z9p;W9NM9NBYCirPKjDSwHo6hLl9cZpGon8{+Z@i*Xo${>h*&xO24=iRV$zJGc(d`S z(st~s8k-FXSit-RaFE^cJFGdmrlYBIs2rROEL~fCSGs?apY^4`#pLp6&G9y^mm|}w zb$#8TSSz4WK(eA~SF&VHIm1SEKj9|%+au^yD(5Q?gSF_0d0{dlF4LDiHn%jQD)lqK z%I)aY+WAuQXZrNKjLSIv?(T#o+J_-%*75x|N5?T9FT(?PfX=Jzmb?&mk1JZKDqJK< zdHlBD14*-|X)XTPKW{;v*IxYb1?i1AwU^qoYb6KYo<;4f^znn&zaf1vs7Gn;v`uJz5?bJUPOlY0SRj zJBMjthNT(3FeCnb+?=d6&bJX3J*eRJJ@aeO!9dey;8FdQ#$9xJ_!3;ozuEZ#p}n7pmmJ$Q2~L_-8PN@>aRo6eS*O zY)|^y>b|yCoxuh{_d0@K=5f-!m1O&+z__c7o7+V|OUF}k0y^)dk3p3!6pe)acj_(V zfk0etIbrFE8B-#!936&l7WdVu*{8g`lRvzW@`G_05j8D}th}rr`I+rw$uzdJ=3GZ{ zEq$8wFlPyf8V}{G@ds$U#+oi65iFLG$@sh;grfR!QBXc8?%c9?E?DbWjCGYyitD+V z%S)a^$MOPaM6FCo*~zPkBB^#CW8D;Z`{lI$w8kLk!Z{Xs7h7Oy)PvCzyli{qG;Oc_ zaEa|9B(n_wX^!$ZXV$rUk8w~FhGcoJBK4X4c5a~Q_C1hpPHlcZ59PCK# z3R|_Wcs5m{%Y5lW$fzQYw*M7l_3Irx0OI97Vt+SkaE8Mn^nvlQ0@i)$jVqeId7GN- z?2j6Q3|R&_OmnOqJLDJ6dTc$q9kn7inRPtlIiaEeNol`z<$dG6$z!VEi>_8EXlP0_ zYk0h4+p-dtv6552NVJ6SY@uG3^Uk+`M#*NzQQSo0phx>E#!1H;6)#nU=!jO~#yQ;5 zN*$J7poU2@-58|jO3?`@hE&wl2oFru;_cojXmEIV&4NOy*rg}8yhm9AjhKO^_~R`q zifh;TwNUal>47)}EO4$%aA7nZ4-1rJF9TE>PT2|hVm{UDVr~eTk!87rt;)riiAF!bnc5@NTYzbfg0QnrPetJg@ZC%PU`hPNJU%@X#Lm=0)|%W zlwW7FjTKOt0>&KKdAhkVi394?d-sunysWf>Z1g)hd0DTEgHGgo1%>u3ljDXbu@>G` za#6G7Iv&8JTG)0`urFE&+eiduHz=fzrEGzazE%3p&%j$raxCV$>z&3`%D_f$;=#pN zF-CWX*!Ph$_vi$@(5;>-d3$APg)weUiRtXs9|uH2mrfSCZW9VqMQ@cF-vGlM-bqf5 zE3>v-&H7#L{GZaM%=g`wXl*fJl_QxcnOgyKp=yEwC1P&ridZLkyA1U3<{B{GJ9- zuCWR3Ed58XWkT2J^DxOeHta_Of4^A)m-J>`t$E$}Y_(CgLU_qpwm#yIpPVWRc~fpP z*Zs}RBM{vt2O>oc=J21jwsi%4QOwUhPDlcurFu~6)}Pqyd}?K=rU9m`Er_>2pG)qZ z*Dn2FBZk2o2pKkEA- zeAAlqk^Qkz{=8U{?E5o8mFskzhj4-!FXAx#42 zH0$0R661hL$g;WU3z>7>3dm#db`^No&uO-R%|~ASX!i4Cs2(l$u{s;*tf75|gYGn8 z>m8l#H83dWa}KArq!g4(^(S;*U@we;b_7QP0sSzft4p`-v)WGicIByxUYd6S+T!jc z2497UAOqVw>S9+0D3WzBnEj%kS+4yd-va?GpJ5Pgv6=4%je@6^-HIi@j#RGrg8Z#<$=nJsr1oe>; zd{e0hz%!-xn0{wHS+GnW3hWW1dE7T4;p8tdI=6t4;pMqc!YW`_=jM^83fzDgk7>X^A7?6|KvXxpUHT^J?{ew^hS zPTB#a!^^g=DRREa5{yLDaGw4-I?f*vc|rX#f+VV~w`YOFN?5bC*Y2zEv$BHYg@$uG zKz1K`G?W$y^sH7;YwO&bexa);J)Hf&-#&k+z@t_;BfvDL5m|wd5%!Y5T;X33?;DTK z`C%9UcOE{sk!EwWN(f%)HR*?hJR921e0^N6kIFFdyQ_7x^%L}E5Zk@J`!Gh#IFgX| z*_CP+IsTktRNT*EP)DCWY@1i>O=Cp|$ka7ufnxj1P~cNZt&w`{3=+(Vl+1DWsrXju z`8jUgN>u=Jz>|KMC3$wLK8|94>9#Do)3VN!HVzq=Hwq~iYk^-I!4lD%{ zp=%9FuZ*A=RWw}|f?jU&(?>pu14D7L#9T+zpe?$pM5mIxWp9qTiP-m+c&_tD*Jc}8 z-8PkxN^3gMavV>?Tof-;?{L1J&_bDNemGzbi>yIKQduq%cpBG~ft(l}lp{1t>q1+) z+t-#dTt^hlPAza(5a1M2KX>&5%KJcRbIk5r!?xr1M)rs8d}YZQuRN!yd3b)j(KQxF zyGTZOSTA=qbbI?)fL@M0k_0B}@8d!3icBsPJiN>H*+KjF{DIMvI6}@mU)KmEo2BLe zwRG#&g2^5Gl_g)$&I)89YCl|9Pq({Y?8uIh+fWp3h-W8yu0W9efr9C;$w1J+_!QfN zXm)p13=jDex2jzPkdgYEAEVk+(_X4gb6zPTxR-zNuGg!xri7((ot$yVtDK4(x8H`Q7*Aqcu+du}$Rw>l! zpxN>8d0-7Z#O43~yuthzM*D=CmzRpYDV)%xp6n0GI`e8?_Z|0wJA^zL;tN#Jp?ZL*Q|H z;Qc;C&A)JHO)VfSpq6qu_LxPxp{rQ5%c1L!S5raWy_1^pNc`-nPcHdNncJmg1ZL62 zs>lQN;Zng&bAR3u#h08vtn>Q3sUQdqITt~hXgtfbx_dCJ8wZQ2LtfG-xD<2Kl#!sq=1iYv$LwUoZi zIt=RBa6Wg=EpNVg&EkxgC`$)dmriEj68!GjV{{&qKyy?1YI#jKTAV6Wl6+5Uu+u;! zo517`)_l|-f3T%+Xo^BC9!5)^1sBXyl=#no=BXRN$(6>Mp19PQT_)XU$^~g~SSiuZ zw*c*Us&y=p+raz-*0yg$B1WgbYY#0ZHogmRtp)IE*4iUiydV0U@Xm_>Fd$Y+0?;0{ zASA4m_|rm6r?oo-eqGk9HIbjNw~)2sj<|Hk@G==(yQaJ8QmB0`1`^r_>W}|!y6ws{ zvzT0@3f?z=%}MN{5;;I`n+hklZ`Lt^W|N4&EUW5OC!5eT)Fq&9{rKQ;I2&H40SK=w z^r(gfN(-o@52lB2M$^9Vlvy{I@f&Hmcs%ibIL77qdxibw)6wU5uFS;MkYJEh|2|$j zcz8W9BCxf5cv#bGP%1H{HtM>_G6AASx32dPjebW0-&_fw`97%*?Ub zWHT}ve($GhbSaPGu1piXOvjPK%{wjbLGKYqp68_`avk`i;ZX;4fWHWyfBL_7<-_w+ zLYjix*WSI%@OQVnDlH8|hiHOk`rd^*{kG6CPIov_I8e9vLAnPZgkk_5$6=;VQDt*l zFd)fR$dX+m#ddw?sd~7I%R9e)KeFm-cecy-w@aWLrGHN$Vo+f!0tS0VtCch|?L#RJhxX@VA8Kx=hX6$kyL&dRHY zt|^YO+(WaeXB>#fypnKqUS+!@1^LXY-3(hLN?#ktPfkVt@USZ^h`*q_LzeE(`25x& z%*(0bpAbP~nswhslu&|U=cX3JHDdXHB!ff&7?j4@So_SD$O-htabk^US4womdK4CD zzmFrnD5V?EXg6&Oh9CPp^2}hoN>QoG&d00L=9?*&+#4&{3J@?a99ispKs84=RPdTujs_cO|%;pIR=X?I9W?t?}ZDxj+X zPt|WE()nV&ps2$=aMez!fNHdEI`3NqYh~c%1e)+xogZsOx`BE~PB;ixRNxLcX8qJb zync7K;@9}$0X6}_wg@6-1&~9&w0ZfkyWG?%{#Rgf$ulbncQs|}0zwvYioc)RrUZbq z^b2#I0X~a9kLeGN!CNzU)5hx>OXOh8gt{6vuWW?%q5DoG$)o)+4B52KN?aIhyFxJJ z3BeCUC;_YeaxTfAbXS7<55dlbcig{KC^xm!N!@$ZS*}LOWO1G zLr-t`|Kn%*+R}ZM2r{@>Zy@W95<;(UAqa>cN|RdqoHL~MwG54b+hRU7=y9oRj7N9|Dw!%~r(4wNarPLW2i*lLoBoU^pZ-@Y83%xhbNp@zYX~WfO z=`M62HN5G3B|>|w>DqGqlKk{Zl=|0?tRh~iOuhaXlGo=HKjM^8H7t~((UE=|PaB4?a({ zvsR4%Y@o>h_XfJ-e?lSj3E%RW!4Ton%CB^(OJ=x8VJ;kYUMsvm`c8ao!_I-ZK=WB; z^wTqIt*`Q5%wBV-yc%#_x}|J7xj7!u2i>9GFHq#7UC5S1&M_X}$av@F*T`L2LeDFR z;Yg>}KD>Yi&&r|G#6~R0v(3vQFXmCTHQa0?H5LOSLvjhnnUbdyuuk zxK{|21gEST!zqauQ+SQ%i+JWYS^|<g@^+FI`2 zd9P#WIqvo%>_Cw=DRq2~vpFY4I{c1qBCd17uzmoWmry`UsZaC<$bHiylT;1JmW*^;k6J$dP>?SSymY0yKUd(g`N z-+^u%A#28wkkjahB>1!JfrUT(#F^gN?1MJ`lqu&-tMss9=MixjDW@hsd-h|fqS(_P z8I6E`_l$cxmBF%d?OMe{dFuo&LPV6$f3_fGGO&XOB6oru&k)CBdULo6>y` zO_YF<=!Ytg1=qwEr$#r2)12nY+Y;X@YYg*a@xg8?$}?3Y`kNxhfe(C0${zj@h>w4+ z@3b>ThCzDAw(eaqJQ;@y^#m@7CFA$APjG*lZv(-oq$-~dlghoHNaJsjT=Lr(_WPZy z_PChVgy2g&UCh?8oF9=u@^zOJyFE&rtX%T}R4V_Q7#U?-38j;o5`%2Kg1s@b0O#b|V8X^DE`H8+RSb zPM0_>7vk`?+n;hS7%+?J1ONR}UdOuieBGm1;9qE>^rpzn=edTkKsT|xGdMeuCUhRP zYYzHH;Y12w8*-?-A;O#jj)Wn^b9}{rSd^MlI}*GSQ%o zI&JJ^Vy>;ens^-1ZIxudLUP$=u9r{5)dInN!!zd6rhK9-p8MMxrP{?#!(4bs56H~cOB<`;Y1z~ zwS6bzr;4l&r5S*tF!NGt2I4zSdbBpwtDF67z32khh;GQau)eKQ@jH@aBqCRD zce;-tc29VZtU)~y2IusPcN~V!Z0GIA3uJpRYJ!vFL=muut(;H_e_?aBVR#|iqzc|L? zjNwiGONJeel5vZ?By}n1`$WsHyQW7U#f@K?9SQ>xTL;cK=T3uI%|2X39qC=ak;$6z3e)K>Gs3{9{y(divk_p;oMaYY)cuTZwG(P6mk4 zD>YP?XG9Ywz#j7-Wqm!rNO=?N=v?@hm6N~NsX&;Ctxysg|c zpGt)?68}#F8F$N$66HvVkT+IXFPgZqg!DHqQ8xllrW`G+e{EK(|9DcSg$(>Z%gB!h zB!Ca=1sS~Yp;Y$}PQZYu$pOLHzxyNmA<}@QAPi2=htk=@e#5D%%G3JSI#i*24gBOD zJ{KO;q5doOea(@WjQ-~VkqG8me@i53Sm0IvwVEEWvKBnZvi{u@(i6Z{3;aSaxc`aT zG-l??)&CMn&K6Bl|2rZZh@$^ZRJij}UIQ~KRcln!3`bC~xVn=5^dwI+Y|8jF`pfBXXv-0;_ z+mo%;{~3;)x7J4s%+mb46n%%+ItT9u)iJQ6-eRY*K|ciPq4%?+xKs3%Olz*BZ5tm9 zSTmlNx#@9R^z^%}^1ppM^*l@1eD(_~vtsl+5{GM9);+hO2}tpot`K44?VEVlBkot$ zQ3&dI()GS1=Ld_OLp!;VZtP+O)HJ$JKH^zKj9T#)y^%3t0X|8q0vxgm3N>NeFJHbS zwSQk;+(9tKgzx_KVG%?bQ3L}1*LdHobiE_0!Lo9%+IPB&wL;ivnNzs4AMsx?XUby6 zKL?XW!2*@IsMCsaudrBWh%?+ta(IcnxZZ(t@WU7)gKUNQc+4yC2J30CC)1(|6a~dTu-}ea6spP$%wOKBE zb2By8Bo>neYumpnOa?{)-K}=|%e2Sn9>g5m@O*!P)2JImT%t~-`Wso+5A@6NPmYk8 zEX<>gkt$YI-doQp-{ucF1Hv!eGMH3kSU-15Ro$hbu9m@^geAs zRUFeS*t=CBm=lelBf0ig*pdi5n_zGpV`ls8I z`LHWR4T+MJw-X;9^GJiZWGCs@fSO?MG(r!;;75(59r-NtGW>sLnFKw}`0rQbt;k7( zpZ{o%vtomgWoxEEy1s_wQ$Mf7ddk?@8{&`Eu*51z@_ns_qcPCx6uqsV9Bou)#bZxm zN0Cx|^{^TA80^e?Jf&spL(60-pfrL3?DbDitZ^Wh6p(Uq`)+a+a*pV}NT6Wz5Mcr8 zR74{rsGIU~9UHIk2Z8ciwCySWjg=9*<#GHDbwc)Ql?uj4k>}$%6Ij3hoQu%YH1tpu ze*m?O&8Y_S6R%14V%NAulKV6JL6Zec)R~{!eKPD}CPQ`d0D6=J@{4 z!0>_!1-A)I{AZ$v8JQ}fa#ZYfpIvz*JXis4Z+>l-Tz>bwW@;a3K^I@AuYU9p7}E7S z`6j`@5Uj*OHA-}9)-`{pz)1}OfNsq^K%|av$=_H)qHR-O9u}lN{lXbxlM|O__6gXs zmFFt^Rqy^RZ+GGF@E%2;Iq%_=hX_DU(|jQOZ^*m#g2I1QR_pou;WWs`F?;~sl;3L` z6u2+Of8||eEm$HNQkKT%hc9O+kx9)^Ezq7oEw-;7dg`%YZ5t`-|djfMkx zd86q8dHVZpW=%UXt=n4ET?XsJs8+`rmBhZ~05^Od^Em`iDh)WRBwic)H zl!78cB9y>=*Q~|omZpJKyT+|*XQ@Tx>|hD20q`1grUq=OnV4{ve5%KdC~9n$LevVU zjh6gGXd6JR7E3l&%+gv@S*L?yYL%0mq2G63-uCMG^3eTi3wAoYHd&t%Lx3JSN08bTVd@%yTrB^l^)eYW>1NA@b@3A08C%Oel61xLF6P?Z{Hjc+fG*2nHildEHPtf%tQdLD$K5B1PNCk9!v{}=j$ z+~^vsEKpPZ8oc&GrA^t+FG~K?k?7iBja9)(bmQNe^_nbUYQjslhTD^Q>AJUN4uCpF zCS*@;U9Tt>f+JCWv2y-e&f(I5RJ~;OgPP@(oQcDFFH7BYbx3~DsFL>cmDlHe6qs@P zvAnO?T6TV)`?6s1bI79eBZuw)|J94qM}K!MAA>f41JPV4BO4gq>(x7%|5@iWoX8kd zbK3sF_<)<`U*}|4WMpg*WM`^4 z#wB~NhTGv5`1jpk0+Ta#j_BudGv2<%TGjKd44b%(1xWgc>XLaA*Z_B%-^|<_H(bw5 z1`dv!KMbv#pn_G#vU_>_#WRV*Nh*g9@)@Qdn|w$Z>tKdQIJZoz`X(9#YNg4sTu&hw>S@ryWZMplLP56_tC0&Hqb zTEUD5V=Dvj%~rFh77N>s(C~Xlc zXY|>(61+tLjVHH}Yc<2g>1vV>iqR6@@5=9d4FNi}pB z&}i7BW@a2!>;gxgdqIgdMv@V&4YxD9n4Mwh$X}2i1f?_nB`Ezzi;Ck&gu_s1Ty~?w z#n^ej%O4#U8<2pkn=OrvLHgn;h%8P4)O3(kPT8hNR9GV-)O|0LM;@nKy&`^n7ttz zP_pC1lTA;RHbT(WnNjWJ9#nY|Wd7Y{kszWhLQwp2(79jKt4jb;_l7>S_|@pkTUEj4N4-$?5q$Ad9I7>T_6ENk#9(7?|7 zTuxx05q#j#!@GwwgN2DHp|4Mg`!?!2Hh{!AYA`dAIfa*ldISCP=jZA+gh_uS^u$k9 z;9{cF;*)xrTt1BU0UPxd$%PtLWrStZ2c`=fefl58K&dL$KWYYl=;oHp_ohp{w83YE z;MmkIRPPl=`{z?cj7!XZh z))7FPJ;_=yn~`8uVnvmYqPxRLdOnPOQ=5oPObixp65ev9zAWxJnPs*=Ji-)nmnMH| zC}uHh@LhY2Q^g@7s@nPV%$jt{dd5G8d5XL1CX}#Mk^8!JVxpsj-Mctl-gbtJ`_-HG zXp-S?&BJX!`A1bGNu~1#H6u!9e)Q#oK`0EWkBr{i{+^lD{_wvp`_aJz&AG-Cv-8EG=N=tEJnQa+F;mF(D%-tvDr*rB-Ul6*ZCw+ zx4)pQ1!MAyf7ETEbTY3JhlWdHfm|64mPPvRHSbroS*x%CnEX1I7--mwtm*Kn~tQhLgw4F z-tgbO7ndcOXBjWDq`c?8+|AaEBYq-}~pF@xRF zBd!t}#fl!~I{ejO#cns9VSTcgxg!edX^Lbq`40aiaDmhDrL&732hLUaQ^zrN$H_z8 z>PzeLG*sDBF%(#hmCmP;`)P>zM2OUNc8SwB?qv)Pl@I7TB(RTZ7L}QeZioKv(X3}} zQD&TIaH2k)Pio{b;Es&8eoa*?`Z>%qb!!%|^B5kOLCoIpHwzbaF?a{c_r}taI3gc)McDn`$2=KYax1cNYF3s%ym7|EEfnO->9`2rvRNr2+xHF*x|J;kIesI*;RlA5exf1ZMLRJ)v2 z-}fKa50gD1;p`&9QQ^|Gap37Z$RuYW!J<`=c>R688O=}mrI+Bg277petBt>);NDDA zsf1{zel{6LMF9FdA((JubZ==I|EM>i*deDWEefgpC@37f98paKos*x10EituXW*95 zJHlg+AxI*!~1Dw1F1cwnrM z#ZN;KrYxC*@OIwpjSdomE$UJ!>RJ#RmI{gac&7y?xq zIAi5>npbl3%;iEm+qmR)yF5d!*RXoBRFzJhWuc+Goc1@W9%bL_^X8zsBPjZO#%DGq zeX+C_p5B-Ohb}{Nw>`-mqc3>l#bqcn($y-BvU#EWt`4hrHprcZpVK^^I6$Q(aR_xS_uev200N|s;!3;m^c{P<&EMf~d= zV<&^Pw=j>BYx0IW{{CI6?fDYa#zsL_g`~m{V^O}tU%NL_Uw12KSlMH2Pd{O8$+v|) z-T-4q)@ZlI{sE{Cf`^3 zUe8rZ-%4a8=$2z2>lPEgT+=&jja4AUAN)8jN_+ogxtd``??-0u^UQ>0-Cd|#d?H4w zqOeij;5+ugMx3G{yro+$1`!GX3jKuRqfb8m__CSu)E-*m@RI-$+T0a<@7;MnY;@g) z#AQQ~Mr({m%3n@AS*(JGwZFvaF7m2-aC6QRZq6Ci1TMrss-{hvnox-&+Ke;WLxP^? zO%Pa;bydm=<{Z>nICDG}TU(HGR6^f~r_U2nLQcAcF8BgFb)>qEAgJD7WXuD8`r@#q z2-5OgeROQyw4N8ZXjz=6&GBYb zHobc*VtrA2bB&AJ3-@^0zgB|Qn|D&jX^I*F!Me{ z(r(2?v)Vf6@ZKH!nA3S5&v-D_sZyd%`VJ=WYNLy}hT7S}w#q_1eb$ocG}5Cf8eMQI z(*e{s@WBP69rz9bWGEchds#&US)zu)+v}l;LTUNn0I6>UA2g!l0vbiu8{mP`5csyE#+%N(IpCySKpKUUhZ*ZqSi3Ih-Og+oHe7k%*}V&$H!FiP?H?V8&g zW+bQpAt42fG~+lXmtASJg>z+Fz(VtR-v^pgj~p5Z_6Y88Kf@6*oy;8nDB8$nz4Oa! z#bWsIY7+JGJg1u=zuf@A46k@`s2qI6j4+Itx1XHxODl%N=eX7zK2=5t{8u38!{_bs z(O|klj(_%#edUuSJ+&f>46M+0{Z36-?_Fk-=TJI%<*kt}5Z#l~-Re~T@aGy2W;OA8 zlf@MQy7mVCn5On^%!vKbyzZNlT^$bU6^ofXOlj&FBY|T21y!=K-L?P10;nKX?>Nvv zqRPvFJhMQx=^63baB{MJp(i0>&y8M&gZs8@ZfiDJ5z4q5MmMn%@&}=W%#^5+De#h> zXS-rO;bivLXV$RW66B-RGhX)>9s8DaE$Q>Zu#5B3jDbT;Cq^!kfz$nYl?vw6oZLf| zwqTlj0)7?=tQrE3I#E9aQ*33Kg`4049Yst|4v!PAcS<5E2eYd5cKQbjZFjlSQ8>jv zU3-GC4(wLuOe{FB@}jxh%r+F3>wYVKg(Li4(a0&mbUA^VM|7 z!ffJ7yMf+H^Fo}I--(nY!7IqCu5wm4oq)*>Ft?^)uRO8ZN@FQZZ+H;-95*^+l~sQw zLmN=>u)Xt`Q>_a-iTGQ*P9I;&K5H-3u!W_vy={CdiMjVVerP-SyLLGe7_)5aDFl-p za%lN4^m$7UP!J>vwwNv)Xe{+y5JaajXy&~7?n*Q-mnqUo<^a}@v8CtM{J|l zpz!Ja3qP4b>z#~g61(FmA)4(|f3>Hg#6m?R&A020-Tn{ZL4t!CF*fO!n#CJ_VF;>3 z4(`A!8roY4d3g+@4B1rvYND#cbMd#IWqShcn~%3u$%S0TL#l(tvpwDJ*>K%UbT^*T zjUu3aZxvyH)UiV1knHBBEJJdRb%@>ldYk5v>WKyNfanAw{$_jFhGc3%P z#bfbc(o9U(PtYV0uIe};&bxe%2d1s0wp1iIoW1mJ4vvZa(WOyC$MzRIS=ffJPIqJj zzoq)_cYHi}pRtv|%h8yATjGA^Z5Ye`+Cf==lM#K#!={f_69sB4_mQ<-04B)JGO6@;#!x>pzk)A&fxTBIx@ zI3~D6>Bh{s`m*o*kfLK>&DXoy*{@@?s))e(FkA&$XgWvX-EnQ(TwWN>u!a^cd+)(RmCKC@^mR#@Vp;v& zRbLsWvAz>@8g()rPJFT=Nk^;f)VXZNG5*qrjCFf(0hfm7fEUp+Nqh%ao1|vbYeyYJ z>ta%B>PNe~dFLF>!NH;@MpFkJI>Bv)*lQTpK^Gjhr*zXh^GQP*30w_!sA&ccLYCgM zBGCZ$7O|wNE%6}5wqEPD;6!92xJU`R-%v_xY~82SNML@YsRQKhB|K=pOuR!(G(n22 zvf@1YBNMZ%tg}17vM6jmnxg?ZK7o2ao?r*F+#i4~f?KOuW9unmWw>#ies(y3E<}Y_ zsCwf41af>wI@w$WE>uj#q?b&SIvj0lr$v{2W_w^NZ>yt zfB4hxTg#{lSA;;hYrE5}FCI8W-s&(6VTF&5Z$rV~u303le!uX1_eC#mWcb4M7dRXw z=vr$q(o>&RQYt+gK0-au0WG-`rdYU<#k0g?_Yx<33uLOR6O$_Qv8T(g8ZtlXiB+0D z?0a0;s#z9r8x?~D%jwpZka1dXi;E8?1^6Q!4}4b7t?A0M3e#uN{Ei1M2NJ)7G&F@p zNQuVjY2)7P*wI1ws9VA#ZL}u79GpqwEJb@M(7@_yU6~?p6zC%)i0%os(T97D#ILGM zu7$lOTq4Uo)tE1he&;Rb5h`^VCgi*;Wq^bX)q5PMa;PY3XCzfW^%7$#j)2)M2vZbG zre|8yU|v0jGt_!_MIqQVpgcoG03~@8NnG+1y*2LsSFrDSHv-O~h!?8pg#Hi9?UM3B zdRNHl_N;eIoe_M#;|ND%sHa>2d+*y>1d~2cKS-AB%kN~L>k0B&Bz4t9gmR|aBzyKD zW-Ympi)Yzhb5BNv4X`FnbzDR>$+JkS*zy3guBcz=w^vwg+i{`xTuj74PsmIjE~MIY zhPp~W+!3gCtbEbYdP%RldLa;i#pTXf#)St+FEICjmo1@n8OuJz+}eEhR`QDDG2RwCQXcCT6 zp}#%~K@$Gn59tzH=uYkrf0ACWBz*7dSxt0IVz*LYOp1$cf{GV)D|LGRGf{0IWV!y_ z_ak?k4FRKeu7aVVS8JGK5Ym!j0vqC-%WlXfZjkvK{xLPPx(}Kcst)Tw+Aq;ALxvT4+D+}IXs3G>(-8;ND2!tQr?%os}yti zgCymT{pBazR{FdBV7IPV$@tVK14K;iXSKDb3 zi6ChNmk1xB)MfST{k~@nO6wvl#Q9zKH3eL@6E&o7v%pRnC%wh$Q$HSn)kk~PX@2g9 zzF|ejx0)Gad0UaV8lLyI@*C$g0$=)%*ZpO_j>lYOe@*dX9(m2XtZBh6_MLB@U0~5l zYg-vp8i`Z-cRf>Nuluxc9Dr8K>{leK%*NV(!)TB>es6I84v3mp zS`2>-<#K=MxQ~2}W$-apznA*(E26(5!DYs=Jab}+@ z@z@+z%Mj7>7ryZ!v(dZI&qhiOX&|*vPv&<;Goq!AuNJ&K=J4ou&Z(4e^>h~Yyd%Dm zBOs9fZBZ-&F6>`e_tIXq_1@Jj`;Tqq`RkkBK1A0><5^qrvG;bbr#7G zI08gU0j@#;pccp~dDZ#x!_G!;N-{-STAJCFwZMGyB|8!n-WxEwGp6bNFH$$JvD4$&Db1YAtLS8ce?&$;jmdV*W|?+4KHJl-gst3=Vp`oA`uuP>gUFb#03jLE z+l`H)-sB#_kdUhg5pe+_N2<`UFzx}|muwF6K@{AkgB*eC_~RUWAEFYwf>)o{yB-Ly zXi2e18wPQ=2A^yVrwVM2Hj^E#_kS=s?mZ832;${1WF>0mtKjy7yFfkD9Dt_;{V-$Fab<^2Q;R3oM^><}*(^qxB*N zwR%Cprp8}uTX81>5}y@)Jw2$_+vIdwu1VR+7vB1woOcz9_@kiHuwW;GkSCa-N_(dW%mcaN4;jB%qY# zp(ev6fDW4(KHVH6+Zd5Fm~D(=P+=&|77oRa{w+JrT$KAYnY5gEC^T_Ilg~z{$>1hg zQ?Q6^KKU+wPn$~&DSk-TqAJpEL~SK-0SCe-_r9F3;?(>74ol9`{$t6POSpzMb1F_1 z)fh{<$$D5K3DL!SWgDn|WAniw4B8n?7E_lxWggqI@0mg?&mrYHqXlZrDZ;ENpab;> zsUnr`^YcR*<8x`a4ePhIHB0!YRi>CQV>C*9*c`lO+gAT|1WA!}o^VN@JkZmMkWJt+ zVXE31MO=7=3{AFGFm>w_Vp^#9RB69;LsY3IWwRTylphpCA8azzalB%SrMT|AVo9F% z-Ss@41x%uit4eF0I_vW5Hm}y@C(^x!og=2h@r1G$J58Z6EQ!q#Yjh+2ua~=ad!8W7BsWGlMOtz<4?Hf!4H!?%BoI1L6 zX!tR7d<@WfjOKnYYBuY~c4dE$Mt&svxhr_#y1g{Pmh*SL|J!Xuzx=}vdi`!iZo9i5 zd|7c@x;iOe1s+nkG5+Ioyu<1hggl5-#fF90d&Zs7)K+N*hk_i2LX|4zOjvcRsESVS z+8L;V4~tVsg|Zi9dF5Daa+~p3ASLeqKU}?KSXEKiH7u>9q=b}!bPGuLp+Q1A4&4pX zEdp}r5G19Mk`C$aQo2*Rr1M*N-_P^C@B5eQ;_S88UNPqwV~+VH2b#moR>7VWPZK^i z^5m=E%N4sP9dN1fKTGR2-lI^FAc1puUI23VWDtQZjP0X8g*GykFmC3Pr(t!Jgv9P=DTA+1L(K+$T0Z{bARe#`tr6Xt1x# zh?=|1X>kgkFy`KFrUHqSugYAEGUUU9`tb9?euna%0*T~U`J*RtEN(X0w-gAsO`Nwr z-0K470Wnmr0Gp%KD^_SwcS)>ZTR?&p>;0WUF&+N#GHhWjtUg*US=^3DuGB?u);kQr z%Z*)?bO% zbeB}Am4@uBEb2q> zVaK)LU$VR_7bUKXv)vZ>M)6!_HoBrGG^1xr;uJ}(RD3*$Ml#!a>RJv)wn!R`y3YOK z{Z0e~>{%oFoh3iIb}3B!Ds*0k%l1uMucP&Cw6VjF$EshJYf1T&9TtpwuKxZ>&P1>N zp4eI3x6a>FBaRM}E)g5suDj8{yb5JH`$(Sn6$>Jkh|LRKx8lQH@J;2D8t*&~GSK9g zu}!0K)ik06!8fy1?m*l<0`6N{w}W|^F$oWp`jJ<{U7zten>*a<*J#;jTgB#+^qV|` z0e|Z6>amuufi36F0`|E`Pt>VwR&Fc`Y#mCz^}gU;K-j4)W~ojB4cliSN4yf^WKS!# z@7icSC{f)8{Ix5q^{PpN&hY(T{(h-*ny*c&)Z4as)_k<2PYJ4f>m^y>F2(z1R7hbq zcp?mhF&G+?{-G1HAgJ|Sw|Y2DcE%{t<|F@}IIPsRl?^ZVrK}@%V|TRpJqjHXB*&`o znf``E?ph$Wm*XEuZY3U50RPNnAnVh!Wby>X0*w1~hI6z&6}5)$66EEnr3c7>*%`Z; zyBkQo*R2?lA(5z4daW(b7&Hna2a`E<_Sv5iaG3Vvt@oP}h`v7(z!^@^jMQ&&?_KBb z|JrrENcK%O$3I5Jz{)5Q9Uc{nT!2HygaHMn``(;AJVy6!Vp7Y_uQ7!j+G_a@#cuB?S!kq zC;a-Yr$brtn`T}oO4Us!%^G)1r0j>R1YQ!@^bH$Q5G$QWpZ|ZCr*!0Vuxmd;_DC@h zy5F&Jq^VT5hE~0*GW-rzm~-y-j6{J8Q`o zLS83oZad9^R^{q`>fZd*ju@zfr>W&3T9_3NATchlqSyVgC$4@q78O>WPSEJ9?3~Fm zhmVDdrj=WC5yY{r&1dple|$@b?zyF6^28;5(BFmJerVds>tYXiCZCju$P)d;*m6Bl zMDnS~W$CJzoxKs(+4>$kP7oc(>w5&@6XIH|UsS$tFw=^F6WQ6WMxAHhiSG^Y2!i(K zI6i$!;UN}xxMIV$szVcOCI&8+E?N~=whHAZsF23Oyi%9`x^epZXHMm)CHw53eMmyy z6#7U=QJ+CN(%M4tWd@C?8D5w9mw3T`HyhF}=r()v^11GO+(7H*U`bTLVrRpVJF$|Z zv;4+)Cws*XMCwXWmCK zX6)I3q4Qg>G}soaT)vrT>z!QO*$bnxS){8boZ-V(6i`wKkHHPu_??%FXz+YD^EXMv z`V)wecAt;I092w|OxLQnIXlyy1iI(8K#ie<4y!w`?fmZiXOr}G{#b;cG24$Dk&jBm z^o0F7Dr-2XmKd;tVVu_r5NvQjRJU4;oL|vtHAb_eyyPi*c6BpZkKulC{!AboJ!F`l z2mPTw>IaHWjasuytll=02fH*9RmGC@)(^Z7I!_Cxh4AR!Jpt9-%MeM^DIOjt#wi_e zP|2!Y&r@fR6=7dBdE7bKXjV)Acvut?A{4TD{t5GdmS5%vY-1BglAcg2<25Ser4R7X z3o1A65!;sd@u1b+b3cVHY*5C{0gD?-!8^H7VWh`!zM{B@Np6{OyV2q@`nR zfDu>8s`B!gxBDd6&Fo9L2SHMn%h++$>-V9q|(1VBtQ?XS~(po7yRc&qv!@U}6+r-Rzj z@2vmLQ-yMz``%GvQs zUEzUyzgYhq&_uvJa2m0!Q}&IUHZ??^7%o;R03uB7|NR_^{Z@ zVUAhPu?(>zw$;xS>`@tcYNw7W^4hXgumaB=*ZDl;&D zGTX0jec_Z_DeAwD1mQf7ytgl-!Dw#1IbyJ7kG+=MvD?65!9-fM%Z6S>9x28x9IVJR zjX7wrRp^K?;#-iydc{jI_k*Il=lt=}x+&g&kI!=Il{xBzJg3eK%jlZSKJCnuX-ZziSb`|Uw?Qgzc@gFa3DpaLg1eCMoo(zeE%EQ zBn}5R8D8lHi)W$*9D_Ct@lTXCtTVB?>VlrI5DQZ5MLLyRsxuXt#O?aZ+q*GWA^wxz zwt9(n7$zy7k)z35K4c$H97a>95mW*guS;O!xCD?WE80o$akoU;NAAh%-F7SrK&*nW zC$#!M$7*yhv`Q~->6KL_1QS*nlWtbv758!$L?ZX>lv?a8V<2%RMDsZN)C>2y>7fdcKCdU?nCoezVK@1KR&1sr{7M#S~{)L#Z&*H%p4xE zFh4YWhE7CGM=#Ll^l^4om?6cpSo6OflSmeUEww9|^UDDFh5+mt?E4#ba`N^R#W#4>}F`9>#!&KJ3{ASFYh4V0hPW?&O=gnG8@*7BH8A8b> zQcO`C4nekVy;EQ-_5;O%3qVTWFBnm~4yxEq*V-=)uhXNFj}zT_)h1|HcR39|p{hP1 zl))EA~@E7HT<-S2S;0q3<1jZDq{5Aprl!`F_trOts7-@lC=hdi|bsP3G z{oGOvYo0yICa;zCunzfXBw@ILwBOv98!s){RrsS~)G(?tD>Xj~9cb1m!{x%1(fH)5 z2_I)?L-rCMZ(gZKyFEA2*cGqRL6t4GVs(#E{PCPHp?Xn=MHsV9;ds&anz5oVvXkzM z)8oGRT~84Vo`*fZJEJq-?>Q;`oEgHvp^wx0pPzt?DSi z|Iva$kN-M}{2wg5NV2jShQL|W*)4t?TSf!yZixZ; zzuBV?Agsdk{^oL4)0@D^s^ZzrnV2=G-d-@*uz2~07Xem$c6W47MW>aA$YIvsi>FG} z5=r3l0g;eb$2@nkfO8kjVDmLNlo24*i>(F9*$zj`qM*6%uN-4)Oi>31HgIVLXJ%5| zw>w|~-wu#9;K4+gA^qNlVDwn9_~dU&)djZf-zPE|Q8!0|6VQ6-7hJ>7Ea7097kuL~ zzL)k~t-x+oM|Q``GHd;lKLQW{MMxkQ_E`%e6mSjq4Q033gnePQ4S2a97lS ze_Z7`Y_T~)eCKyy%FN3TY2KtH;Vzcry;e~T<9)FMMuy;_aM_@0g0evGMJliJ@bq#; z?%%Pzv)WkNSZx@!oT*Cm$CZ1>otJCYKA%2j{qaxlUVbv^bOj_G8#|_XDFWlMNiw-=?vQR-4yv-B3HPJ1HoW@dx94olh&}IKc<68#5A|4%ayZm z7N@2NW1fJ%lcg>M|8>?HI%HhsFvbxFS%=5=;y|L3k(x9;E32%8o;S>GnL*1G`U$&YIBT2oP@|~u&HCY@xOs^_!Fiv zKt4hMeUFw-P0O$_kM#GrXSfCXcMTiyn_kSNy~T09ET_UtcVKqq1H&L8r=X<77xN0q z)Qk}$&;b$9AW(&>kinWW-jEviC~&9?c>Z?q=J9?$P3J0VtJ7bB2hI=s5@(*fxUU6W zbVWXa+HdFZUGtzh{VEQHvh%g9#S{HHI@!>ZPf>~0Tu|F7znj2$ ztKD>NAWtTY9E|qjd2uw581uyu|2tbJV;fZ1IHqP}ykOG1b3C>^qtS-1Nxy+8vOdwl z+7UkuByhqPrRr3V;egX*ahBV#4H=acdn_lCzY4T!`wR2*#f2hMl7^^0N~)UY!nMv@ zcRDi8d_^$4)tBJC2w>8-^UJ8~ez{B#6fDx7qoc5=#qW{hI`|9g7+z{rXSaotCcpE4 zLY$y@?UH2=>9|p> zhGdL>JNvV>u+3;n;2&r0NI>WqGBmWk7AgQ4j!xZSDsCtWR8}@nGH0UtV)b{YLqg^* z7rL$nKDNv%r%WL0+ja48K)~d!TlFy-URD!^Np_90>!-iNG5Jb8Wa-0v*9ui3n`fs3 z2%dZdz>$mwvDp_3AY6wZzYS(A_uPN|5z8hBg7Lke>eWk~5(2yFdaB4P9%Ld;bBS(w zqU0}t$#k6zQg;FKH+*aLO&t|dGXzhvp8r3}_SpX_+bM3A{{Ursb&2E@UwB{)@}}G~ zHtl9B!Bt$vY`2j>V#1hH76H#wOiG_&qqCC?JQS+yP6ZP({fu}aWjo!I^=<1dL28_h z{;Rc~WL!KV`kzx4U@KLe5Jo)s5`4I;#|k$)6W_*Z_d3Me&O~4wBPKi!QEcmF4{y`r zQ)P1+yyeTrhlki3FHyLDtx`|PC!kXGpd-{WD8YlJ9$Ri!7a|feYu3Ho=G2!6`49|h z7`FA?&-Vl;izB2iSPVfJGLR=Pg9?E~TKQwU1(xdHy#P?QSmI!^*4iyV zJ1Q6qS*n8c`eW09mDE@87$n424*qu+TltS|3`C86pCC>Z@-g@^Ris`m_U@fWu|8=8 z0*cXd?6IdpLiBrNE5GvXvGJ-fS60s6RpvP;zP6+4G|C|$+&0jyyhOB~`2PMWDr$vS zqpUh~dz->C8(imR29Y0X_w%4{9A|NU7ruuBa*sIbm{|fUnY1TAOlGv1^vcN$1yi!l zcwBSR^RAo@d^<`Lo;kRsEp;|aF0L9-x|P}_JzpeIAVHFjT_kM_MNjoMcq$r4t*l08 zf&p7yU42eK@M*r@IcU9BZ3o(Bv6R6-Dp<#^$}FRL(gGP8^PASpMhbhpH+iii17luR zt1%P-2Wkj+H7Z>n9PCo*$F#!}6`pWk3EZW#ox*`@M%tNDojU-p_emww?ouBn+$@&PnQnjyLz>JO^Gm>CHYjS#F1mk9BWj z_>lqv#cGAI$16tQIw;XDCx590TuB2(uN2o5X z|NUI&eh^1O4wv)EfJ=P($Warh;#ku8ga50J z=UptT!=}%%=n*gJ0sz(cg_TG7}>l$I-IgjY%ZnKD8qubu}N6>G%$_fsaST-9f zDW{$d*}w@+8eJe7P^#vR>%jPFwc1zkmUruR?}~Aq!Gbc9@GdW32?{5(R}OB zYYX*(0`q77?wbH_DbS1p&AV>duk47ts(dM!*J+(?Gs4jDBM^HvLS`xK9JMM;*yFTI zyF!_T-H)Jo55@1p)CLhr^b6(#J;jt@w6{l0zLklr4C+?iJ zT)!BLW`SBg2-~W#fH7rgT^Tmkv-4%&srd%i@N(30|JYN~3`DK@L*DWbXQvAwG+%Pu z?fuHd_>1-6f`>f)WRtPgB6li|TyU|wo5Rl;%W0p75PeV%4lcv6yDIGH;>9NmE%LW7 zSmfJ!uh)Un8kwM$5!7pDMMpDhwlp)}-c|%)DKZfXx*yGIenKh?Lh(wjKa+vW&Q~H^ z>-uYcbaZOMz2LbeAatj2e{p%)5Hg%Im=|F^#8N!J{rX5m7pwR1ccCgL)CGWJxWK!h zE4?Kq9tn>?zK){HFXCpS!@$#t336L;>l-VCjDnI*k(d{QrhjMm-bJh1a#?89{zz2=po}UCZo^uR` zE|Qi01S^2DNoI+e8P18*exD!kw$dJQ1f&G99}edG-t=kfX|k=tKi$>mc~l!Xpa4Vy zK#+%@dTKwE6Fc;%Ws1O=-QFHMa8WMJsbHNnO*U$&!cfUS8+Cn_793&*Wf=f@xeDF~ zJ+98FOLU1MCW>^Z!tAPph0?8tY zk!X5(Ps~2PiQ{<5X8djFsYBj=l1R!hLR5xO&w*eMV#rn+1I_iRO@tu=-)eV>)aO6! zv01yjJoZPXYtTH4rjh;?P??aEy6I%9yYlI7V~%!9zns_m*Vms<>pw4-X8t|L_cOXU z@l*TqMz#BNy4n?UO&=78;1Dy_pA(m9@F7S?3o5aaySwLIUPAkEqsRq+phCn-T@pnC z&$OY27T2fS-K`k1LD(;TXb#{CPh*phUlPZh0Mb&|N$;X=sV~2*VLt2alZk2x$yj5V#J2k#i9TJ|)Ks*gTyDEN4 zv}o`buePo5?xifl>`k_ZZ~u5<(utP5U4+nv=XZ3`ns~;Am>O zI^ntC+y?5`E`3Y zr4Aj605{l>#AyT~E777@jOadoK^&Y|Cb~g;pI3h#KITjbH^e8$%gJ{J4@|LtP*Hh; zd>_-n!}tknFO+3Jg+gH`=V)>mIlJTMmrVKXEZBRP0JRZ0Ub#;Tb`$!c5qVo>r^%N0 z2~mgyPJDR1MqK8z;`bppnNdj348R#$yWvdIX^WoEOEhnPF(k?GC1x+Jn64TTcFiIV{`zd$)g|su$lW zI4s07=|?-}TQBC2DQ2{+u!WC-4n-pH%(vHbc6kN}UOeIhud7YVY&G}-0%MHL80)um zD}Bvh3VrC7Py?~;`f@4y^IYi_)06Z{kX8Pt0BQBr4}93=62BM)Fz7SGUqV6U*Qrv7TXNw~G}% z5ICa3c@_{e^Cbozn3Gm$oc#tmtW1ADDgp1)!5q?u*kE=$2_^5pu9?TKQv2+$LNP{ReY7onIta+-M_E9o$n8cuQBPb2E_oiF7uV z+ArBA3I1fSFjH8=0qg)f&~wQB=ybz)hYJgxOuVhS`r8`(Z778&#T3F5{%*Y+`o?t< z6`ho8j!wCrql=K@`Z|0Bh*YeC#_kcMe)z6&rwY2oSn~f+CqhTHj4V$66|PS*|4qcH z&Ty(-fCeRPV9F|7)x5N|%)%E&IFBUC{Lr)4SN;J=(93Uv>WuN6zSXRIc3&_-o#A41 zrFN&v%)f6)`Kc1aq)GNJUc0qmFHwop#qdrAr!^{_ylL`0>rd+0noU4U;oOsLm>7_onIfN?V+Zw}i1g$G7>hG=!`)=7e2x$m0#-u|?qD>8>;;^UwGPS@MpMa*K{1m; zjM`gR7dMHTFhF&-)4CED>196xPQ$agUjNc1E%1JDl=t`F-WO@F0I{qa^`w!+GTqy^ z+cLPk#N13~FqQl+L5SFj_?5B~QvmkO^<%YqdF+qu&iDShsbM6f&q|k{vKh67oCc8S zr|!S-NF&J%a22IcB0xcxMn$nbe>1GmX0d)*KS=iRh*A&xGTB{`BDZa;t4Kq$#gGv} z^7#0f^cQZfS#B(mxlLD*tQDHtAb^ra&FN*0*B1?s<+EmcYYESEWJ9TSI21BkQK;zC z9xJ=0`}qt901%a(C~FF8&k`EGyH{Ij!=%+R);*7WDv?|PD9z`5@O@%v*qb>XF`Ier zzV$kzc6B)IMxIllx!@D1AnDEE@p97pJWcLAPH9YQU?yYvGMDuBq^pv^VcTIrc2~fD zY{dQalF0LeC4hV~+LL~M1z1Lo51DQ*9)OR`KLf?l)Fbj@J$L}17t)T&j3LfsR=s9S zxx})dl2R8uSZwT+le0(?lR6I)RXw>hP3zWHd7S3MU+&bm9$zh+t&oJPY_a{V@WTi8 zF`1R{M?b=wey{DG`8!2H@LmBot$O?!Scw^wb2o0Fnm;G5u&Y-M@bh>uY9EJGt$$Eu z?v#O34PoEJ$?b;D);te9jT~M_U~gfCVpLdtgeytya_!QC(J-hdLs=>=EVuqEuXQ%s zt_D{^FVZIM4hiKy1ANv0DsrpJH#%F#RqE_YN>DTou>J!Ou~z>Fhk8u33#+P%HRPBf zFd;W`0m({C+-M%)v!cbWF|O9x)nt7B9J{uj$9|DRQTO6tu`S5UEjl{d|L=p1NZ+aq z@0%@Ad_pJe_j}YH_>qefH>VKdD=zpLBt;eUUX=}?@1HNy7XHDx!&%>;)Kbg|{VI=<;rKWJ7?r0Bow*Hvm7yGOJnR@18iGmQ zGrVwHNfLGRRf+4fm> z$5|t4YU(V|ZSUyptXlIFFpq}knDly)2kba0lxItiJc9Hv1K2kI??@JIve=!*QS)5# z&r4wD`_uI=fLw#)eyK+5Nn8$>bt3wp^@deV*LI}_Q;pNXG;%zH=moJ%Dzdh`I4WTN zr|&JLIoe7=-N-%qW9Un5j<52cZAgj)adbR>iZ&NHU;m3FuG%TY1*Cx=KiafipV_Yb z`JymxAyYB+U$BE(bPvEGKw@J0F?b@@rTHshUtB4O@Uj3>{Mut6vLorV15(-U;bbOx z=YLW_{thk}ZJn*zen`8Mz-poqZj$*~w__!N+<`z$@`qkFp|MIIBth~P~4%YT-L z>3^4q1~OGCwb3#SH8~Ph0s(%$HY#MCtJ(1{-2L?p9*b^$L{_kKwtI{~fpR?}D8M&V ze>SBpVb?$==nAVV`5-myJVWCHb?Ci){{okMP)A0Nh37bSB%U9fhgz%>|CzmTeAJ1&U zQ+a*L4bR{!InW4Lq^@Bv#=hwphBx6MywG9#x4!XE0R$#3$}X(lr5$cHMHht~#Gh^0 zw6iQ^IFiIpnm4Q+5Io@9#$$joYr-|_cgge#rq^CIy)`fbydu;$P{gcVJdlJsdx9in zy{}J+h`9;^j{)q)`h=WGXEA42Yre$xy*uI>MRk^rQN_Px4YJ z_9R)_8{^&ZVx>}8uR8pQjQx&C^^B_Y=ut8W$%82UTG_*W-Wga6M6oY<@L_ftgZAwHEkl0~03xR4-iZM*CM;V@Iev37h#YI1?+ zctIF5RkCl0Lre%*ix-dNAJ=PUx+Yqxf~hyUKYg(V2!_R0+L2yzKArtMz%W{_<9B;w zkFGvK0(%wgG{Y5XK4JiRr8V>>a^aHcE!k@5oto@|b4|rB_}_F-9>Tgi^6jCcG?Ss| zH@BhJl^eGNfFAP092GXQ4?sk)%aL1)P*jLbA3w%2uN%kS(yHf}?L6sltIdYy1Rzn5 zgHIEgoXr5Y?}oV>%ymcr<9>j)PAYEbWlA-dlH715-d zt-7D2Bl2R=5cd__s}~;p`k8p5=xg8IUCwqL2yXKf(w>r&+ebh2M5a)`WnO6b@Fua+ zZ86ogS(mNBVVjRk&^OY57JsP0`)Wr4uWULstU&sla7FJ$T@% z5jdmSs4-1FXwdjfSdlz%^nls6c;lDl!4n85uM$1qn|c27cR!+cFWuVeqTx|Awq~6L zQ6h7iy|>?fLqrl0J4%rT3#8mg#*1a9V%?s=#RiUwg|1vy*ykLblg^bBbba? z0Q9qx8O<>EI0ER!qH&$u2A0WS^l-6TxQ317)adb}M*zXlGdGdLID1^cre=7dLh^{? z=DoAK6~#+hKW)vpB~3g_syv`L^+a&d_h|In(>ZPW|36|9*=ch1VX~-w@9z>1uFIzq ztxkA^5#$eF#>6_Yx)j=^slp}Acz`+qZ?Jo{X!20xr(O0D@PIMyIO*e_T=j*XdNheN z`rgeBz7j7Mv!1jO8647iYBd)NM@8UoHCb$itm6G#1r-*$n!}2?TE}K~fyh?}&(6k& z?E|-#&(vN+>c=TaLOcl<*K>}&XL{zD=5Ttcbz5)CvV)}NcqARG;r#ek_K$C6f9XNu zoB9*6B=G0z?xrXKEyaP40D&DJYFfy_Rn#5Apz(B(u&bga$lX*;csUUhfJ)&oY?$UQ2Ab^TsVWYvbEm?bjMTLh zII{Y4Zr)`4_*k>bC^aI#jj^`{2n1rf49&qunxW5x{W2fY3;JQmnamle?b{|%O7*R=sc}6?hTQGR z6Z~r#2~o8_iHWX?jvl(2Fkgm zdlMq7wj&9$0pPZFLnL=R)$BK@ezfen&kl-x%Ab;GvViy2oWhh$qPbD zleXS1@coF4=-;{AkfV%Nbg*@H(bOB8_a~7h^nZEMXDe~;3_NxSEXOZHYpOhMDBW{q zAKgJ4Ow{;TY*JyLyT6G`MI5-SH~HLPW=cg358jhC2TRkvYX{{u@_|f0pe~!}>@{fQ zx^=5TI9{KA?z5xrp3|5O=|vdResrabUKGw@9?!Y2LN;iL>{<%R!uHw3iA$=pOY5Jm zrim^09T(SoJadXz3)2F}Xd}plyg%ACp{!l~{i6B9iex;8eaW~tanW_1gJr=TF-Vbz zjf06|JIsLNE%@XnvEuoM%$QiZ@(CPBo>c{TfTjC9^J5N;;3a1bRlJ*YX;*I#EfRua zwbc;kfSZYo8PEmXAxXDM`$SwZ3-}$Qrqu3tbsOAwrnf{<2?@33DPDdl@y957(I7x5 z=yCnKE`$~|7L*?iuCdi=A1N!KAUytN3TVASx&INK(m0z<8?gi3;@~#`KV}CN5O?1?%yLO}9PTp++REQ#ue!)z0<+z~KMnFaBIQ@Ll29aNBUuPRmehwF}-TpuZMY5gZ6^8n%vweh2^uU+em_FVvZuISB_(u8!XYBC5X`H+R^1wX zyw}z2b|cP`>&t53KDBV>{T00_W27Nr)2`$uTlo1gIjqvA_swuXYzaZZ8ErL(1*tUH-fqxjS6eFIMNdgmSvV>YaI^T^OG$fVJpGNj!8kr zU^WbNfH4#8pGH~(X;LDZs3^T<=nR~mqv4jnIop|qSC~V8lgL|V%??cb2X04Dvhzpu zUlk1W=3J;bEU3yrLNs>4Te<~P1!_CxQcdPYrpb#-{zagsGi6^r54zp|eiPA&(^!F) z^kjVN@CEcwhLpqZs=a)Ugy&l&IFLkGXS{5qd%elM#$D_7U^pLIAH3IGKU%cpfX7Uk z9=X*SJona{0U0^SP6l`xvFwaQ*Jx)#b4sp6EION6p=^87$?a&QDQbZiJ-s4Ezz^Wq zHbpUseTZE0bKUUfOzDDRmPaKNC^Ud=QEoLIKJ4i-9z#+}UyC>i$?S5>@q$`0kfHpi{Esn^Emg zYunnpk_(L#3NKJKPhRp23W({Sn?vD3*vU3aL#9)2j5oQ$lw4|+!Eu4R$8u!sQ zD2t*(h*JlfInSp?cTdp|+-y{cwtu;cqY}oPsG1G74t%L)x0RLIa+ytAJR>x>8u{P`(p7rE!$KRE4|c^MmP`ID}OaYwz?kF6H7Sd1$v%$$|4 z3vW`ZJV-e{JUb^B3Xe`F9cwUEwWJ+W=~D>+dF-n?<8j|_!aNER4ONA4xtOJIEx_U$ z`N|(KRy0-SxVlaxk--;UuvJ;-dQ%$aPmSo-H@-nccQO>ClUP?~v}8Clxi-j4h8*>^ z5@nK?sR*8jzIcJ(oCkY)((p8F`e#2>B-$?~wLm8~)C9QH4e7CAwLBd21P0xWF8^f$ z_(n}N$>;P7O8qD*sdVVt2o?a9aD2qXl&gMNYC72kfp?8DU?4m$5xu>WMErz&X4|vJ zYqYQnP7b(IWY?mVl{IsV#k$flE~RAb26JY_&re^*WRHExpz^9IKHz=F$M6&H@;Q0b zlG{Poul$kG0#SUR=rPvtIW_5F05F+PlOAX$c<)83tlY`qf;l#3{`}&gNxABDn={KK z`GjuUARR92W&O!C(^k4)>B@Zd4aEqnA37R(P5rAE!a()}p=C4KOjqIC8jd-rzRQ9~ zC)cMeHrH7n+ztm9edzi1qxh}bi#AI!t*6OL2~>n9Yoxh8mlN$qFI3KQ7yVs|-#Wh) z2Hcf8@nX+?S2vW|I`zfxIYgz?gm`e7MCo*E@pyQ@apVZGhhwMoY>g)nnkmIbzn7i0 zh}9@GwRSUJtRU^P9(AeWrhiu{Dt#eK)aZp-7R&kMFm-tQ zV@mCg6*OmRH`zx_hQftFriP37pxQ|rSj4~@0`@^EkP2@9K z+$_W5lsk~^QZL&Z&0Z!(3h ztLcvvQxK2_s?9~reoOpiUHNqOJp~B@Md0{xr(bO$P`Xq%@NxS!n}qJ#Iylh7Q!6d! z$l@$M43B=Qk-^VIeTS5q+gkav=lG~wf2-p6C-Zy#;hj%&wMF=Bo_CuVpto26F0CSG z04_iSjIw-IjA#hM-)&dm6Hz#I9&dRtaUTc-OEi&<8m_1QXbp?B&=>%6=JAs~?>(KZ zK|#4EdinhMHLHsgaa)tTPxpfs<^r8A4t%QYrqFpr<F23km<#V%oZ}8&&`q_1-yZ5hCH1w^xj$jDI;)LK0rr~LwrF>iBe#1A% z%9>T$F`QUDw#J`Pos7l-A2p=o$|;;)*dr>jUR3kR;sg_9f%RJekEyoYSJL6`y-V>c z%X~3%)YN*pbu!LebyxlN<9U)}^ldxT(17oWBJ;w8g_@3a+DlY2Tph>(8R+yfcVy8U$PXw(}W7 z)H(C7znqGPEGL56vaI>p?_w4xya07sX8j}dW#^MZcYxooM6GOneWztAvp;XB{ zE6RAMjRtF*e(gtuu%_H2HQ5ORWxNh-6KaOMQhQMYr=KG^*rL zMnyA4_KouoE0FJbsxB)EZk9c3AeguOu&ueLERu1A`Hb8M`{slIXKjh&{WeetvncVq zn-p6qO`Pf`qoVK5J#(|`$<(+wx0q{4&Z#UjXbJ1+iG^+r&Y->iFldU-*#Zc9MVTchr^xPH_|7W}Ev!vOV)8L}an7!7(hoBz+&)Qctr;6q9B=8Z zADzoY=z5%d%kksQImx@xOXaW)vxmC-Jd<{RCVnf2Q}c^{Au~b+NmmAL$Vc|g6s5*j z1=s8Ee`PV;P5p;yS^tV-{bBe)=R|ydm%Lt@!S9BtR;UIS78XWPdJCWj6W_m4Ag#{S z&9$P_DC9d?XI`F%n;yN+{$u}R_Xz(rb!~n~&zb~+_Afz6kbP>(mO7*2maybbHFP5S zaK$3lh++ui4Skt#MHcar{dYX9hU6DooH2K= zP9JZe|Ni*n{YrsKP2IV6n@rc}ef+Y_ph=`ZzA&0oLw|iR1q+BF-8^E_1){pb&}tnw zUhkqx$JO>Ht39%lhv^UC-*cv4~%sNZOe2Y!lLfc>hcIUqw{z8R;Fm=}pk%c)** zB|6zl)?>@10|S}Ou}n4Z$f#Hf$;lKl3H#kO>}nQ!9uMCBe<#Dg5MD{Y^VQ}eXSeJr zrBHy6a{}C_z8Hj^^nA~m$Bbpp#W}h1dU)D^N;#iA4*{0E&H-SCHUX`76y~qjhhoM| zyT$nbuTMu&&){&=hSoXn7fIrlzS_0>HX9vzSwktPXMF}?_oZU#EFG5}DnypP@YoZC zBR+OHq}SqbgbE7=(z^5GK1BT=!{$-{{{|XM zPI_$jKyo9Gpv119jhxyB$2Suqb=+Mmyv0 zSFgS1iLZQB;`^n_xv*}%jZF#A2CkKR_s+P_GA*b&IO5W=Hy7iOlF0)db;5dne!+;JVKT!r5e{ z4mHGB@yF^l-mdKI;Vst0MyE=5&!@I literal 0 HcmV?d00001 diff --git a/docs/assets/img/vortex_bank.png b/docs/assets/img/vortex_bank.png deleted file mode 100644 index 8c10995e8eabdfba68f48dcf38bb2f3bd2360c01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 79299 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